1 /*****************************************************************************
2  * Author:   Valient Gough <vgough@pobox.com>
3  *
4  *****************************************************************************
5  * Copyright (c) 2002-2004, Valient Gough
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation, either version 3 of the License, or (at your
10  * option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <cstddef>
22 #include <iostream>
23 #include <list>
24 #include <map>
25 #include <string>
26 #include <utility>
27 
28 #include "Cipher.h"
29 #include "CipherKey.h"
30 #include "Interface.h"
31 // for static build.  Need to reference the modules which are registered at
32 // run-time, to ensure that the linker doesn't optimize them away.
33 #include "NullCipher.h"
34 #include "Range.h"
35 #include "SSL_Cipher.h"
36 #include "base64.h"
37 
38 using namespace std;
39 
40 namespace encfs {
41 
42 #define REF_MODULE(TYPE) \
43   if (!TYPE::Enabled()) cerr << "referenceModule: should never happen\n";
44 
AddSymbolReferences()45 static void AddSymbolReferences() {
46   REF_MODULE(SSL_Cipher)
47   REF_MODULE(NullCipher)
48 }
49 
50 struct CipherAlg {
51   bool hidden;
52   Cipher::CipherConstructor constructor;
53   string description;
54   Interface iface;
55   Range keyLength;
56   Range blockSize;
57 };
58 
59 using CipherMap_t = multimap<string, CipherAlg>;
60 static CipherMap_t *gCipherMap = nullptr;
61 
GetAlgorithmList(bool includeHidden)62 std::list<Cipher::CipherAlgorithm> Cipher::GetAlgorithmList(
63     bool includeHidden) {
64   AddSymbolReferences();
65 
66   list<CipherAlgorithm> result;
67 
68   if (gCipherMap == nullptr) {
69     return result;
70   }
71 
72   CipherMap_t::const_iterator it;
73   CipherMap_t::const_iterator mapEnd = gCipherMap->end();
74   for (it = gCipherMap->begin(); it != mapEnd; ++it) {
75     if (includeHidden || !it->second.hidden) {
76       CipherAlgorithm tmp;
77       tmp.name = it->first;
78       tmp.description = it->second.description;
79       tmp.iface = it->second.iface;
80       tmp.keyLength = it->second.keyLength;
81       tmp.blockSize = it->second.blockSize;
82 
83       result.push_back(tmp);
84     }
85   }
86 
87   return result;
88 }
89 
Register(const char * name,const char * description,const Interface & iface,CipherConstructor fn,bool hidden)90 bool Cipher::Register(const char *name, const char *description,
91                       const Interface &iface, CipherConstructor fn,
92                       bool hidden) {
93   Range keyLength(-1, -1, 1);
94   Range blockSize(-1, -1, 1);
95   return Cipher::Register(name, description, iface, keyLength, blockSize, fn,
96                           hidden);
97 }
98 
Register(const char * name,const char * description,const Interface & iface,const Range & keyLength,const Range & blockSize,CipherConstructor fn,bool hidden)99 bool Cipher::Register(const char *name, const char *description,
100                       const Interface &iface, const Range &keyLength,
101                       const Range &blockSize, CipherConstructor fn,
102                       bool hidden) {
103   if (gCipherMap == nullptr) {
104     gCipherMap = new CipherMap_t;
105   }
106 
107   CipherAlg ca;
108   ca.hidden = hidden;
109   ca.constructor = fn;
110   ca.description = description;
111   ca.iface = iface;
112   ca.keyLength = keyLength;
113   ca.blockSize = blockSize;
114 
115   gCipherMap->insert(make_pair(string(name), ca));
116   return true;
117 }
New(const string & name,int keyLen)118 std::shared_ptr<Cipher> Cipher::New(const string &name, int keyLen) {
119   std::shared_ptr<Cipher> result;
120 
121   if (gCipherMap != nullptr) {
122     CipherMap_t::const_iterator it = gCipherMap->find(name);
123     if (it != gCipherMap->end()) {
124       CipherConstructor fn = it->second.constructor;
125       // use current interface..
126       result = (*fn)(it->second.iface, keyLen);
127     }
128   }
129 
130   return result;
131 }
New(const Interface & iface,int keyLen)132 std::shared_ptr<Cipher> Cipher::New(const Interface &iface, int keyLen) {
133   std::shared_ptr<Cipher> result;
134   if (gCipherMap != nullptr) {
135     CipherMap_t::const_iterator it;
136     CipherMap_t::const_iterator mapEnd = gCipherMap->end();
137 
138     for (it = gCipherMap->begin(); it != mapEnd; ++it) {
139       // TODO: we should look for the newest implementation..
140       if (it->second.iface.implements(iface)) {
141         CipherConstructor fn = it->second.constructor;
142         // pass in requested interface..
143         result = (*fn)(iface, keyLen);
144 
145         // if we're not going to compare the options, then just stop
146         // now..
147         break;
148       }
149     }
150   }
151 
152   return result;
153 }
154 
155 Cipher::Cipher() = default;
156 
157 Cipher::~Cipher() = default;
158 
MAC_32(const unsigned char * src,int len,const CipherKey & key,uint64_t * chainedIV) const159 unsigned int Cipher::MAC_32(const unsigned char *src, int len,
160                             const CipherKey &key, uint64_t *chainedIV) const {
161   uint64_t mac64 = MAC_64(src, len, key, chainedIV);
162 
163   unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff);
164 
165   return mac32;
166 }
167 
MAC_16(const unsigned char * src,int len,const CipherKey & key,uint64_t * chainedIV) const168 unsigned int Cipher::MAC_16(const unsigned char *src, int len,
169                             const CipherKey &key, uint64_t *chainedIV) const {
170   uint64_t mac64 = MAC_64(src, len, key, chainedIV);
171 
172   unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff);
173   unsigned int mac16 = ((mac32 >> 16) & 0xffff) ^ (mac32 & 0xffff);
174 
175   return mac16;
176 }
177 
nameEncode(unsigned char * data,int len,uint64_t iv64,const CipherKey & key) const178 bool Cipher::nameEncode(unsigned char *data, int len, uint64_t iv64,
179                         const CipherKey &key) const {
180   return streamEncode(data, len, iv64, key);
181 }
182 
nameDecode(unsigned char * data,int len,uint64_t iv64,const CipherKey & key) const183 bool Cipher::nameDecode(unsigned char *data, int len, uint64_t iv64,
184                         const CipherKey &key) const {
185   return streamDecode(data, len, iv64, key);
186 }
187 
encodeAsString(const CipherKey & key,const CipherKey & encodingKey)188 string Cipher::encodeAsString(const CipherKey &key,
189                               const CipherKey &encodingKey) {
190   int encodedKeySize = this->encodedKeySize();
191   auto *keyBuf = new unsigned char[encodedKeySize];
192 
193   // write the key, encoding it with itself.
194   this->writeKey(key, keyBuf, encodingKey);
195 
196   int b64Len = B256ToB64Bytes(encodedKeySize);
197   auto *b64Key = new unsigned char[b64Len + 1];
198 
199   changeBase2(keyBuf, encodedKeySize, 8, b64Key, b64Len, 6);
200   B64ToAscii(b64Key, b64Len);
201   b64Key[b64Len - 1] = '\0';
202 
203   string str((const char *)b64Key);
204   delete[] b64Key;
205   delete[] keyBuf;
206 
207   return str;
208 }
209 
210 }  // namespace encfs
211