summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--pwmanager/pwmanager/libgcryptif.cpp430
-rw-r--r--pwmanager/pwmanager/libgcryptif.h13
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
25PwMerror 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;
128out_delete:
129 delete [] *outBuf;
130out_close:
131 gcry_cipher_close(handle);
132out:
133 return ret;
134}
135
136PwMerror 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;
219out_delete:
220 delete [] *outBuf;
221out_close:
222 gcry_cipher_close(handle);
223out:
224 return ret;
225}
226
227PwMerror 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
247unsigned 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
255int 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
276int 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
299bool 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);
326out:
327 return ret;
328}
329
330
331bool 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);
398out:
399 return ret;
400}
401
402void 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
422void 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
444PwMerror LibGCryptIf::encrypt(unsigned char **outBuf, 38PwMerror 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>