blob: 348d9e344754721e28fb0234e8b8270d3096ad1f [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 2010 David Sugar, Tycho Softworks.
2//
3// This file is part of GNU uCommon C++.
4//
5// GNU uCommon C++ is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published
7// by the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// GNU uCommon C++ is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
17
18#include "local.h"
19
20static const unsigned char *_salt = NULL;
21static unsigned _rounds = 1;
22
23int context::map_cipher(const char *cipher)
24{
25 char algoname[64];
26
27 enum {
28 NONE, CBC, ECB, CFB, OFB
29 } modeid;
30
31 String::set(algoname, sizeof(algoname), cipher);
32 char *fpart = strchr(algoname, '-');
33 char *lpart = strrchr(algoname, '-');
34
35 modeid = NONE;
36
37 if(lpart) {
38 if(fpart != lpart)
39 *(fpart++) = 0;
40 else
41 ++fpart;
42
43 *(lpart++) = 0;
44 if(eq_case(lpart, "cbc"))
45 modeid = CBC;
46 else if(eq_case(lpart, "ecb"))
47 modeid = ECB;
48 else if(eq_case(lpart, "cfb") || eq_case(lpart, "pgp"))
49 modeid = CFB;
50 else if(eq_case(lpart, "ofb"))
51 modeid = OFB;
52 else
53 modeid = NONE;
54 }
55 else if(eq_case(cipher, "aes128") || eq_case(cipher, "aes"))
56 return GNUTLS_CIPHER_AES_128_CBC;
57 else if(eq_case(cipher, "aes256"))
58 return GNUTLS_CIPHER_AES_256_CBC;
59 else if(eq_case(cipher, "aes192"))
60 return GNUTLS_CIPHER_AES_192_CBC;
61 else if(eq_case(cipher, "arcfour") || eq_case(cipher, "arc4"))
62 return GNUTLS_CIPHER_ARCFOUR_128;
63 else if(eq_case(cipher, "des"))
64 return GNUTLS_CIPHER_DES_CBC;
65 else if(eq_case(cipher, "3des"))
66 return GNUTLS_CIPHER_3DES_CBC;
67 else if(eq_case(cipher, "rc2"))
68 return GNUTLS_CIPHER_RC2_40_CBC;
69 else if(eq_case(cipher, "idea"))
70 return GNUTLS_CIPHER_IDEA_PGP_CFB;
71 else if(eq_case(cipher, "twofish") || eq_case(cipher, "2fish"))
72 return GNUTLS_CIPHER_TWOFISH_PGP_CFB;
73 else if(eq_case(cipher, "blowfish"))
74 return GNUTLS_CIPHER_BLOWFISH_PGP_CFB;
75
76 else if(eq_case(algoname, "cast") || eq_case(algoname, "cast5"))
77 return GNUTLS_CIPHER_CAST5_PGP_CFB;
78
79 switch(modeid) {
80 case CFB:
81 if(eq_case(algoname, "aes")) {
82 if(atoi(fpart) == 128)
83 return GNUTLS_CIPHER_AES128_PGP_CFB;
84 if(atoi(fpart) == 192)
85 return GNUTLS_CIPHER_AES192_PGP_CFB;
86 if(atoi(fpart) == 256)
87 return GNUTLS_CIPHER_AES256_PGP_CFB;
88 return 0;
89 }
90
91 if(eq_case(algoname, "idea"))
92 return GNUTLS_CIPHER_IDEA_PGP_CFB;
93 if(eq_case(algoname, "3des"))
94 return GNUTLS_CIPHER_3DES_PGP_CFB;
95 if(eq_case(algoname, "cast") || eq_case(algoname, "cast5"))
96 return GNUTLS_CIPHER_CAST5_PGP_CFB;
97 if(eq_case(algoname, "twofish") || eq_case(algoname, "2fish"))
98 return GNUTLS_CIPHER_TWOFISH_PGP_CFB;
99 if(eq_case(algoname, "blowfish"))
100 return GNUTLS_CIPHER_BLOWFISH_PGP_CFB;
101 if(eq_case(algoname, "sk"))
102 return GNUTLS_CIPHER_SAFER_SK128_PGP_CFB;
103 return 0;
104 case CBC:
105 if(eq_case(algoname, "aes")) {
106 if(atoi(fpart) == 128)
107 return GNUTLS_CIPHER_AES_128_CBC;
108 if(atoi(fpart) == 192)
109 return GNUTLS_CIPHER_AES_192_CBC;
110 if(atoi(fpart) == 256)
111 return GNUTLS_CIPHER_AES_256_CBC;
112 return 0;
113 }
114 if(eq_case(algoname, "camellia")) {
115 if(atoi(fpart) == 128)
116 return GNUTLS_CIPHER_CAMELLIA_128_CBC;
117 if(atoi(fpart) == 256)
118 return GNUTLS_CIPHER_CAMELLIA_256_CBC;
119 return 0;
120 }
121 if(eq_case(algoname, "3des"))
122 return GNUTLS_CIPHER_3DES_CBC;
123 if(eq_case(algoname, "des"))
124 return GNUTLS_CIPHER_DES_CBC;
125 if(eq_case(algoname, "rc2"))
126 return GNUTLS_CIPHER_RC2_40_CBC;
127 return 0;
128 default:
129 if(eq_case(algoname, "arc4") || eq_case(algoname, "arcfour")) {
130 if(atoi(fpart) == 40)
131 return GNUTLS_CIPHER_ARCFOUR_40;
132 if(atoi(fpart) == 128)
133 return GNUTLS_CIPHER_ARCFOUR_128;
134 }
135 return 0;
136 }
137}
138
139void Cipher::Key::assign(const char *text, size_t size, const unsigned char *salt, unsigned count)
140{
141 if(!hashid || !algoid) {
142 keysize = 0;
143 return;
144 }
145
146 size_t kpos = 0, ivpos = 0;
147 size_t mdlen = gnutls_hash_get_len((MD_ID)hashid);
148 size_t tlen = strlen(text);
149
150 if(!hashid || !mdlen) {
151 clear();
152 return;
153 }
154
155 char previous[MAX_DIGEST_HASHSIZE / 8];
156 unsigned char temp[MAX_DIGEST_HASHSIZE / 8];
157 MD_CTX mdc;
158
159 unsigned prior = 0;
160 unsigned loop;
161
162 if(!salt)
163 salt = _salt;
164
165 if(!count)
166 count = _rounds;
167
168 do {
169 gnutls_hash_init(&mdc, (MD_ID)hashid);
170
171 if(prior++)
172 gnutls_hash(mdc, previous, mdlen);
173
174 gnutls_hash(mdc, text, tlen);
175
176 if(salt)
177 gnutls_hash(mdc, salt, 8);
178
179 gnutls_hash_deinit(mdc, previous);
180
181 for(loop = 1; loop < count; ++loop) {
182 memcpy(temp, previous, mdlen);
183 gnutls_hash_fast((MD_ID)hashid, temp, mdlen, previous);
184 }
185
186 size_t pos = 0;
187 while(kpos < keysize && pos < mdlen)
188 keybuf[kpos++] = previous[pos++];
189 while(ivpos < blksize && pos < mdlen)
190 ivbuf[ivpos++] = previous[pos++];
191 } while(kpos < keysize || ivpos < blksize);
192}
193
194void Cipher::Key::assign(const char *text, size_t size)
195{
196 assign(text, size, _salt, _rounds);
197}
198
199void Cipher::Key::options(const unsigned char *salt, unsigned rounds)
200{
201 _salt = salt;
202 _rounds = rounds;
203}
204
205void Cipher::Key::set(const char *cipher, const char *digest)
206{
207 set(cipher);
208
209 hashid = context::map_digest(digest);
210}
211
212void Cipher::Key::set(const char *cipher)
213{
214 clear();
215
216 algoid = context::map_cipher(cipher);
217
218 if(algoid) {
219 blksize = gnutls_cipher_get_block_size((CIPHER_ID)algoid);
220 keysize = gnutls_cipher_get_key_size((CIPHER_ID)algoid);
221 }
222}
223
224void Cipher::push(unsigned char *address, size_t size)
225{
226}
227
228void Cipher::release(void)
229{
230 keys.clear();
231 if(context) {
232 gnutls_cipher_deinit((CIPHER_CTX)context);
233 context = NULL;
234 }
235}
236
237bool Cipher::has(const char *cipher)
238{
239 return context::map_cipher(cipher) != 0;
240}
241
242void Cipher::set(const key_t key, mode_t mode, unsigned char *address, size_t size)
243{
244 release();
245
246 bufsize = size;
247 bufmode = mode;
248 bufaddr = address;
249
250 memcpy(&keys, key, sizeof(keys));
251 if(!keys.keysize)
252 return;
253
254 gnutls_datum_t keyinfo, ivinfo;
255 keyinfo.data = keys.keybuf;
256 keyinfo.size = keys.keysize;
257 ivinfo.data = keys.ivbuf;
258 ivinfo.size = keys.blksize;
259
260 gnutls_cipher_init((CIPHER_CTX *)&context, (CIPHER_ID)keys.algoid, &keyinfo, &ivinfo);
261}
262
263size_t Cipher::put(const unsigned char *data, size_t size)
264{
265 if(size % keys.iosize() || !bufaddr)
266 return 0;
267
268 size_t count = 0;
269
270 while(bufsize && size + bufpos > bufsize) {
271 size_t diff = bufsize - bufpos;
272 count += put(data, diff);
273 data += diff;
274 size -= diff;
275 }
276
277 switch(bufmode) {
278 case Cipher::ENCRYPT:
279 gnutls_cipher_encrypt2((CIPHER_CTX)context, (void *)data, size, bufaddr + bufpos, size);
280 break;
281 case Cipher::DECRYPT:
282 gnutls_cipher_decrypt2((CIPHER_CTX)context, data, size, bufaddr + bufpos, size);
283 }
284
285 count += size;
286 if(!count) {
287 release();
288 return 0;
289 }
290 bufpos += size;
291 if(bufsize && bufpos >= bufsize) {
292 push(bufaddr, bufsize);
293 bufpos = 0;
294 }
295 return count;
296}
297
298size_t Cipher::pad(const unsigned char *data, size_t size)
299{
300 size_t padsz = 0;
301 unsigned char padbuf[64];
302 const unsigned char *ep;
303
304 if(!bufaddr)
305 return 0;
306
307 switch(bufmode) {
308 case DECRYPT:
309 if(size % keys.iosize())
310 return 0;
311 put(data, size);
312 ep = data + size - 1;
313 bufpos -= *ep;
314 size -= *ep;
315 break;
316 case ENCRYPT:
317 padsz = size % keys.iosize();
318 put(data, size - padsz);
319 if(padsz) {
320 memcpy(padbuf, data + size - padsz, padsz);
321 memset(padbuf + padsz, keys.iosize() - padsz, keys.iosize() - padsz);
322 size = (size - padsz) + keys.iosize();
323 }
324 else {
325 size += keys.iosize();
326 memset(padbuf, keys.iosize(), keys.iosize());
327 }
328
329 put((const unsigned char *)padbuf, keys.iosize());
330 zerofill(padbuf, sizeof(padbuf));
331 }
332
333 flush();
334 return size;
335}
336
337