-rw-r--r-- | pwmanager/pwmanager/libgcryptif.cpp | 430 | ||||
-rw-r--r-- | pwmanager/pwmanager/libgcryptif.h | 13 |
2 files changed, 21 insertions, 422 deletions
diff --git a/pwmanager/pwmanager/libgcryptif.cpp b/pwmanager/pwmanager/libgcryptif.cpp index 6f3a994..8175510 100644 --- a/pwmanager/pwmanager/libgcryptif.cpp +++ b/pwmanager/pwmanager/libgcryptif.cpp | |||
@@ -13,6 +13,14 @@ | |||
13 | * * | 13 | * * |
14 | ***************************************************************************/ | 14 | ***************************************************************************/ |
15 | 15 | ||
16 | /*************************************************************************** | ||
17 | * copyright (C) 2004 by Ulf Schenk | ||
18 | * This file is originaly based on version 2.0 of pwmanager | ||
19 | * and was modified to run on embedded devices that run microkde | ||
20 | * | ||
21 | * $Id$ | ||
22 | **************************************************************************/ | ||
23 | |||
16 | #include "libgcryptif.h" | 24 | #include "libgcryptif.h" |
17 | 25 | ||
18 | #ifdef CONFIG_PWMANAGER_GCRY | 26 | #ifdef CONFIG_PWMANAGER_GCRY |
@@ -22,424 +30,10 @@ | |||
22 | 30 | ||
23 | #include <gcrypt.h> | 31 | #include <gcrypt.h> |
24 | 32 | ||
25 | PwMerror LibGCryptIf::encrypt(unsigned char **outBuf, | 33 | #ifdef PWM_EMBEDDED |
26 | size_t *outBufLen, | 34 | #include <pwmprefs.h> |
27 | unsigned char *inBuf, | 35 | #endif |
28 | size_t inBufLen, | ||
29 | const unsigned char *key, | ||
30 | size_t keylen, | ||
31 | char _algo) | ||
32 | { | ||
33 | PwMerror ret = e_success; | ||
34 | gcry_error_t err; | ||
35 | gcry_cipher_hd_t handle; | ||
36 | size_t blklen; | ||
37 | size_t unpaddedLen = inBufLen; | ||
38 | size_t cipherKeylen; | ||
39 | unsigned char *hashedKey; | ||
40 | unsigned char salt[STRING2KEY_SALTLEN]; | ||
41 | int algo = mapCipherId(_algo); | ||
42 | |||
43 | if (!inBufLen || !keylen) | ||
44 | return e_invalidArg; | ||
45 | |||
46 | // test if algo is ready for encryption | ||
47 | err = gcry_cipher_algo_info(algo, | ||
48 | GCRYCTL_TEST_ALGO, | ||
49 | 0, 0); | ||
50 | if (err != GPG_ERR_NO_ERROR) { | ||
51 | printDebug(string("LibGCryptIf::doEncrypt(): GCRYCTL_TEST_ALGO failed: ") | ||
52 | + gcry_strerror(err)); | ||
53 | ret = e_cryptNotImpl; | ||
54 | goto out; | ||
55 | } | ||
56 | // get the algo block length | ||
57 | err = gcry_cipher_algo_info(algo, | ||
58 | GCRYCTL_GET_BLKLEN, | ||
59 | 0, | ||
60 | &blklen); | ||
61 | if (err != GPG_ERR_NO_ERROR) { | ||
62 | printDebug(string("LibGCryptIf::doEncrypt(): GCRYCTL_GET_BLKLEN failed: ") | ||
63 | + gcry_strerror(err)); | ||
64 | ret = e_cryptNotImpl; | ||
65 | goto out; | ||
66 | } | ||
67 | /* double check if we have enough space. | ||
68 | * We have only 1024 extra bytes for padding and salt. | ||
69 | */ | ||
70 | BUG_ON(blklen > 1024 - STRING2KEY_SALTLEN); | ||
71 | // get the algo key length | ||
72 | err = gcry_cipher_algo_info(algo, | ||
73 | GCRYCTL_GET_KEYLEN, | ||
74 | 0, | ||
75 | &cipherKeylen); | ||
76 | if (err != GPG_ERR_NO_ERROR) { | ||
77 | printDebug(string("LibGCryptIf::doEncrypt(): GCRYCTL_GET_KEYLEN failed: ") | ||
78 | + gcry_strerror(err)); | ||
79 | ret = e_cryptNotImpl; | ||
80 | goto out; | ||
81 | } | ||
82 | // now open the algo and get a handle | ||
83 | err = gcry_cipher_open(&handle, | ||
84 | algo, | ||
85 | GCRY_CIPHER_MODE_CBC, | ||
86 | 0); | ||
87 | if (err != GPG_ERR_NO_ERROR) { | ||
88 | printDebug(string("LibGCryptIf::doEncrypt(): gcry_cipher_open() failed: ") | ||
89 | + gcry_strerror(err)); | ||
90 | ret = e_cryptNotImpl; | ||
91 | goto out; | ||
92 | } | ||
93 | // hash the "key" to a fixed size hash matching "cipherKeylen" | ||
94 | hashedKey = new unsigned char[cipherKeylen]; | ||
95 | hashPassphrase(key, keylen, salt, hashedKey, cipherKeylen, true); | ||
96 | // so now set the hashed key | ||
97 | err = gcry_cipher_setkey(handle, hashedKey, cipherKeylen); | ||
98 | if (err != GPG_ERR_NO_ERROR) { | ||
99 | printDebug(string("LibGCryptIf::doEncrypt(): gcry_cipher_setkey() failed: ") | ||
100 | + gcry_strerror(err)); | ||
101 | ret = e_cryptNotImpl; | ||
102 | delete [] hashedKey; | ||
103 | goto out_close; | ||
104 | } | ||
105 | delete [] hashedKey; | ||
106 | /* allocate a buffer for the encrypted data. | ||
107 | * The size of the buffer is the inBuf length, but blklen | ||
108 | * aligned and plus the length of the salt, that is appended. | ||
109 | */ | ||
110 | *outBufLen = getBufLen(unpaddedLen, blklen) + STRING2KEY_SALTLEN; | ||
111 | *outBuf = new unsigned char[*outBufLen]; | ||
112 | padData(inBuf, unpaddedLen, blklen); | ||
113 | // encrypt the padded data | ||
114 | err = gcry_cipher_encrypt(handle, | ||
115 | *outBuf, | ||
116 | *outBufLen - STRING2KEY_SALTLEN, | ||
117 | inBuf, | ||
118 | *outBufLen - STRING2KEY_SALTLEN); | ||
119 | if (err != GPG_ERR_NO_ERROR) { | ||
120 | printDebug(string("LibGCryptIf::doEncrypt(): gcry_cipher_encrypt() failed: ") | ||
121 | + gcry_strerror(err)); | ||
122 | ret = e_cryptNotImpl; | ||
123 | goto out_delete; | ||
124 | } | ||
125 | // append the salt to the encrypted data | ||
126 | memcpy(*outBuf + *outBufLen - STRING2KEY_SALTLEN, salt, STRING2KEY_SALTLEN); | ||
127 | goto out_close; | ||
128 | out_delete: | ||
129 | delete [] *outBuf; | ||
130 | out_close: | ||
131 | gcry_cipher_close(handle); | ||
132 | out: | ||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | PwMerror LibGCryptIf::decrypt(unsigned char **outBuf, | ||
137 | size_t *outBufLen, | ||
138 | const unsigned char *inBuf, | ||
139 | size_t inBufLen, | ||
140 | const unsigned char *key, | ||
141 | size_t keylen, | ||
142 | char _algo) | ||
143 | { | ||
144 | PwMerror ret = e_success; | ||
145 | gcry_error_t err; | ||
146 | gcry_cipher_hd_t handle; | ||
147 | size_t cipherKeylen; | ||
148 | unsigned char *hashedKey; | ||
149 | unsigned char salt[STRING2KEY_SALTLEN]; | ||
150 | int algo = mapCipherId(_algo); | ||
151 | |||
152 | if (!inBufLen || !keylen) | ||
153 | return e_invalidArg; | ||
154 | |||
155 | // test if algo is ready for encryption | ||
156 | err = gcry_cipher_algo_info(algo, | ||
157 | GCRYCTL_TEST_ALGO, | ||
158 | 0, 0); | ||
159 | if (err != GPG_ERR_NO_ERROR) { | ||
160 | printDebug(string("LibGCryptIf::doDecrypt(): GCRYCTL_TEST_ALGO failed: ") | ||
161 | + gcry_strerror(err)); | ||
162 | ret = e_cryptNotImpl; | ||
163 | goto out; | ||
164 | } | ||
165 | // get algo key length | ||
166 | err = gcry_cipher_algo_info(algo, | ||
167 | GCRYCTL_GET_KEYLEN, | ||
168 | 0, | ||
169 | &cipherKeylen); | ||
170 | if (err != GPG_ERR_NO_ERROR) { | ||
171 | printDebug(string("LibGCryptIf::doDecrypt(): GCRYCTL_GET_KEYLEN failed: ") | ||
172 | + gcry_strerror(err)); | ||
173 | ret = e_cryptNotImpl; | ||
174 | goto out; | ||
175 | } | ||
176 | // extract the salt of the encrypted data buffer | ||
177 | memcpy(salt, inBuf + inBufLen - STRING2KEY_SALTLEN, STRING2KEY_SALTLEN); | ||
178 | // open the algo and get a handle | ||
179 | err = gcry_cipher_open(&handle, | ||
180 | algo, | ||
181 | GCRY_CIPHER_MODE_CBC, | ||
182 | 0); | ||
183 | if (err != GPG_ERR_NO_ERROR) { | ||
184 | printDebug(string("LibGCryptIf::doDecrypt(): gcry_cipher_open() failed: ") | ||
185 | + gcry_strerror(err)); | ||
186 | ret = e_cryptNotImpl; | ||
187 | goto out; | ||
188 | } | ||
189 | // hash the "key" to a fixed size hash matching "cipherKeylen" | ||
190 | hashedKey = new unsigned char[cipherKeylen]; | ||
191 | hashPassphrase(key, keylen, salt, hashedKey, cipherKeylen, false); | ||
192 | // so now set the hashed key | ||
193 | err = gcry_cipher_setkey(handle, hashedKey, cipherKeylen); | ||
194 | if (err != GPG_ERR_NO_ERROR) { | ||
195 | printDebug(string("LibGCryptIf::doDecrypt(): gcry_cipher_setkey() failed: ") | ||
196 | + gcry_strerror(err)); | ||
197 | ret = e_cryptNotImpl; | ||
198 | delete [] hashedKey; | ||
199 | goto out_close; | ||
200 | } | ||
201 | delete [] hashedKey; | ||
202 | *outBufLen = inBufLen - STRING2KEY_SALTLEN; | ||
203 | *outBuf = new unsigned char[*outBufLen]; | ||
204 | // decrypt the data | ||
205 | err = gcry_cipher_decrypt(handle, | ||
206 | *outBuf, | ||
207 | *outBufLen, | ||
208 | inBuf, | ||
209 | *outBufLen); | ||
210 | if (err != GPG_ERR_NO_ERROR) { | ||
211 | printDebug(string("LibGCryptIf::doEncrypt(): gcry_cipher_encrypt() failed: ") | ||
212 | + gcry_strerror(err)); | ||
213 | ret = e_cryptNotImpl; | ||
214 | goto out_delete; | ||
215 | } | ||
216 | // remove all random padding | ||
217 | unpadData(*outBuf, outBufLen); | ||
218 | goto out_close; | ||
219 | out_delete: | ||
220 | delete [] *outBuf; | ||
221 | out_close: | ||
222 | gcry_cipher_close(handle); | ||
223 | out: | ||
224 | return ret; | ||
225 | } | ||
226 | |||
227 | PwMerror LibGCryptIf::hash(unsigned char **outBuf, | ||
228 | size_t *outBufLen, | ||
229 | const unsigned char *inBuf, | ||
230 | size_t inBufLen, | ||
231 | char _algo) | ||
232 | { | ||
233 | PwMerror ret = e_success; | ||
234 | unsigned int hashLen; | ||
235 | int algo = mapHashId(_algo); | ||
236 | |||
237 | hashLen = gcry_md_get_algo_dlen(algo); | ||
238 | *outBufLen = hashLen; | ||
239 | *outBuf = new unsigned char[*outBufLen]; | ||
240 | gcry_md_hash_buffer(algo, | ||
241 | *outBuf, | ||
242 | inBuf, | ||
243 | inBufLen); | ||
244 | return ret; | ||
245 | } | ||
246 | 36 | ||
247 | unsigned int LibGCryptIf::hashLength(char _algo) | ||
248 | { | ||
249 | unsigned int ret; | ||
250 | int algo = mapHashId(_algo); | ||
251 | ret = gcry_md_get_algo_dlen(algo); | ||
252 | return ret; | ||
253 | } | ||
254 | |||
255 | int LibGCryptIf::mapCipherId(char algo) | ||
256 | { | ||
257 | switch (algo) { | ||
258 | case PWM_CRYPT_AES128: | ||
259 | return GCRY_CIPHER_AES; | ||
260 | case PWM_CRYPT_AES192: | ||
261 | return GCRY_CIPHER_AES192; | ||
262 | case PWM_CRYPT_AES256: | ||
263 | return GCRY_CIPHER_AES256; | ||
264 | case PWM_CRYPT_3DES: | ||
265 | return GCRY_CIPHER_3DES; | ||
266 | case PWM_CRYPT_TWOFISH: | ||
267 | return GCRY_CIPHER_TWOFISH; | ||
268 | case PWM_CRYPT_TWOFISH128: | ||
269 | return GCRY_CIPHER_TWOFISH128; | ||
270 | default: | ||
271 | BUG(); | ||
272 | } | ||
273 | return GCRY_CIPHER_NONE; | ||
274 | } | ||
275 | |||
276 | int LibGCryptIf::mapHashId(char algo) | ||
277 | { | ||
278 | switch (algo) { | ||
279 | case PWM_HASH_SHA1: | ||
280 | return GCRY_MD_SHA1; | ||
281 | case PWM_HASH_SHA256: | ||
282 | return GCRY_MD_SHA256; | ||
283 | case PWM_HASH_SHA384: | ||
284 | return GCRY_MD_SHA384; | ||
285 | case PWM_HASH_SHA512: | ||
286 | return GCRY_MD_SHA512; | ||
287 | case PWM_HASH_MD5: | ||
288 | return GCRY_MD_MD5; | ||
289 | case PWM_HASH_RMD160: | ||
290 | return GCRY_MD_RMD160; | ||
291 | case PWM_HASH_TIGER: | ||
292 | return GCRY_MD_TIGER; | ||
293 | default: | ||
294 | BUG(); | ||
295 | } | ||
296 | return GCRY_MD_NONE; | ||
297 | } | ||
298 | |||
299 | bool LibGCryptIf::hashPassphrase(const unsigned char *pw, | ||
300 | size_t pwlen, | ||
301 | unsigned char *salt, | ||
302 | unsigned char *key, | ||
303 | size_t keylen, | ||
304 | bool create) | ||
305 | { | ||
306 | DEK dek; | ||
307 | STRING2KEY s2k; | ||
308 | bool ret; | ||
309 | |||
310 | dek.keylen = keylen; | ||
311 | s2k.mode = 1; | ||
312 | s2k.hash_algo = mapHashId(conf()->confGlobHashAlgo()); | ||
313 | s2k.count = 0; | ||
314 | if (!create) | ||
315 | memcpy(s2k.salt, salt, STRING2KEY_SALTLEN); | ||
316 | ret = doHashPassphrase(&dek, | ||
317 | pw, | ||
318 | pwlen, | ||
319 | &s2k, | ||
320 | create); | ||
321 | if (!ret) | ||
322 | goto out; | ||
323 | memcpy(key, dek.key, dek.keylen); | ||
324 | if (create) | ||
325 | memcpy(salt, s2k.salt, STRING2KEY_SALTLEN); | ||
326 | out: | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | |||
331 | bool LibGCryptIf::doHashPassphrase(DEK *dek, | ||
332 | const unsigned char *pw, | ||
333 | size_t pwlen, | ||
334 | STRING2KEY *s2k, | ||
335 | bool create) | ||
336 | { | ||
337 | // This function is derived from GnuPG-1.2.5-rc2 | ||
338 | gcry_md_hd_t md; | ||
339 | gcry_error_t err; | ||
340 | bool ret = true; | ||
341 | size_t pass, i; | ||
342 | size_t used = 0; | ||
343 | |||
344 | PWM_ASSERT(s2k->hash_algo); | ||
345 | BUG_ON(!(dek->keylen > 0 && dek->keylen <= array_size(dek->key))); | ||
346 | |||
347 | err = gcry_md_open(&md, s2k->hash_algo, 0); | ||
348 | if (err != GPG_ERR_NO_ERROR) { | ||
349 | ret = false; | ||
350 | goto out; | ||
351 | } | ||
352 | for (pass = 0; used < dek->keylen; pass++) { | ||
353 | if (pass) { | ||
354 | gcry_md_reset(md); | ||
355 | for (i = 0; i < pass; i++) // preset the hash context | ||
356 | gcry_md_putc(md, 0); | ||
357 | } | ||
358 | if (s2k->mode == 1 || s2k->mode == 3) { | ||
359 | size_t len2 = pwlen + 8; | ||
360 | size_t count = len2; | ||
361 | |||
362 | if (create && !pass) { | ||
363 | Randomizer *rnd = Randomizer::obj(); | ||
364 | const unsigned int salt_len = 8; | ||
365 | string rndBuf(rnd->genRndBuf(salt_len)); | ||
366 | memcpy(s2k->salt, rndBuf.c_str(), salt_len); | ||
367 | if (s2k->mode == 3) | ||
368 | s2k->count = 96; // 65536 iterations | ||
369 | } | ||
370 | if (s2k->mode == 3) { | ||
371 | count = (16ul + (s2k->count & 15)) << ((s2k->count >> 4) + 6); | ||
372 | if (count < len2) | ||
373 | count = len2; | ||
374 | } | ||
375 | // a little bit complicated because we need a ulong for count | ||
376 | while (count > len2) { // maybe iterated+salted | ||
377 | gcry_md_write(md, s2k->salt, 8); | ||
378 | gcry_md_write(md, pw, pwlen); | ||
379 | count -= len2; | ||
380 | } | ||
381 | if (count < 8) { | ||
382 | gcry_md_write(md, s2k->salt, count); | ||
383 | } else { | ||
384 | gcry_md_write(md, s2k->salt, 8); | ||
385 | count -= 8; | ||
386 | gcry_md_write(md, pw, count); | ||
387 | } | ||
388 | } else | ||
389 | gcry_md_write(md, pw, pwlen); | ||
390 | gcry_md_final(md); | ||
391 | i = gcry_md_get_algo_dlen(s2k->hash_algo); | ||
392 | if (i > dek->keylen - used) | ||
393 | i = dek->keylen - used; | ||
394 | memcpy(dek->key+used, gcry_md_read(md, s2k->hash_algo), i); | ||
395 | used += i; | ||
396 | } | ||
397 | gcry_md_close(md); | ||
398 | out: | ||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | void LibGCryptIf::padData(unsigned char *buf, | ||
403 | size_t bufLen, | ||
404 | size_t boundary) | ||
405 | { | ||
406 | size_t numPadBytes = boundary - ((bufLen + 1) % boundary); | ||
407 | buf[bufLen] = static_cast<char>(0x01); | ||
408 | size_t i = 0; | ||
409 | Randomizer *rnd = Randomizer::obj(); | ||
410 | char c; | ||
411 | unsigned char *b; | ||
412 | while (i < numPadBytes) { | ||
413 | c = rnd->genRndChar(); | ||
414 | if (c == static_cast<char>(0x01)) | ||
415 | continue; | ||
416 | b = buf + bufLen + 1 + i; | ||
417 | *b = c; | ||
418 | ++i; | ||
419 | } | ||
420 | } | ||
421 | |||
422 | void LibGCryptIf::unpadData(const unsigned char *buf, | ||
423 | size_t *bufLen) | ||
424 | { | ||
425 | size_t pos; | ||
426 | BUG_ON(*bufLen % 8); | ||
427 | pos = *bufLen - 1; | ||
428 | while (buf[pos] != static_cast<char>(0x01)) { | ||
429 | BUG_ON(!pos); | ||
430 | --pos; | ||
431 | } | ||
432 | *bufLen = pos; | ||
433 | } | ||
434 | |||
435 | #endif // CONFIG_PWMANAGER_GCRY | ||
436 | |||
437 | #ifdef CONFIG_PWMANAGER_CRYPTO | ||
438 | |||
439 | #include "pwmdoc.h" | ||
440 | #include "randomizer.h" | ||
441 | |||
442 | #include <openssl/crypto.h> | ||
443 | 37 | ||
444 | PwMerror LibGCryptIf::encrypt(unsigned char **outBuf, | 38 | PwMerror LibGCryptIf::encrypt(unsigned char **outBuf, |
445 | size_t *outBufLen, | 39 | size_t *outBufLen, |
@@ -851,5 +445,5 @@ void LibGCryptIf::unpadData(const unsigned char *buf, | |||
851 | *bufLen = pos; | 445 | *bufLen = pos; |
852 | } | 446 | } |
853 | 447 | ||
854 | #endif // CONFIG_PWMANAGER_CRYPTO | 448 | #endif // CONFIG_PWMANAGER_GCRY |
855 | 449 | ||
diff --git a/pwmanager/pwmanager/libgcryptif.h b/pwmanager/pwmanager/libgcryptif.h index 7390827..ce76675 100644 --- a/pwmanager/pwmanager/libgcryptif.h +++ b/pwmanager/pwmanager/libgcryptif.h | |||
@@ -13,16 +13,21 @@ | |||
13 | * * | 13 | * * |
14 | ***************************************************************************/ | 14 | ***************************************************************************/ |
15 | 15 | ||
16 | /*************************************************************************** | ||
17 | * copyright (C) 2004 by Ulf Schenk | ||
18 | * This file is originaly based on version 2.0 of pwmanager | ||
19 | * and was modified to run on embedded devices that run microkde | ||
20 | * | ||
21 | * $Id$ | ||
22 | **************************************************************************/ | ||
23 | |||
16 | #ifndef __LIBGCRYPTIF_H | 24 | #ifndef __LIBGCRYPTIF_H |
17 | #define __LIBGCRYPTIF_H | 25 | #define __LIBGCRYPTIF_H |
18 | 26 | ||
19 | #include "pwmexception.h" | 27 | #include "pwmexception.h" |
20 | 28 | ||
21 | //US ENH: should we put this better into globalstuff.h? | ||
22 | #define CONFIG_PWMANAGER_CRYPTO | ||
23 | |||
24 | //#undef CONFIG_PWMANAGER_GCRY // for debugging only. | 29 | //#undef CONFIG_PWMANAGER_GCRY // for debugging only. |
25 | #if defined CONFIG_PWMANAGER_GCRY || defined CONFIG_PWMANAGER_CRYPTO | 30 | #ifdef CONFIG_PWMANAGER_GCRY |
26 | 31 | ||
27 | #include <stddef.h> | 32 | #include <stddef.h> |
28 | #include <sys/types.h> | 33 | #include <sys/types.h> |