summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--pwmanager/pwmanager/libgcryptif.cpp435
-rw-r--r--pwmanager/pwmanager/libgcryptif.h158
2 files changed, 593 insertions, 0 deletions
diff --git a/pwmanager/pwmanager/libgcryptif.cpp b/pwmanager/pwmanager/libgcryptif.cpp
new file mode 100644
index 0000000..8e55144
--- a/dev/null
+++ b/pwmanager/pwmanager/libgcryptif.cpp
@@ -0,0 +1,435 @@
1/***************************************************************************
2 * *
3 * copyright (C) 2004 by Michael Buesch *
4 * email: mbuesch@freenet.de *
5 * *
6 * hashPassphrase() is derived from GnuPG and is *
7 * Copyright (C) 1998, 1999, 2000, 2001, 2003 *
8 * Free Software Foundation, Inc. *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License version 2 *
12 * as published by the Free Software Foundation. *
13 * *
14 ***************************************************************************/
15
16#include "libgcryptif.h"
17
18#ifdef CONFIG_PWMANAGER_GCRY
19
20#include "pwmdoc.h"
21#include "randomizer.h"
22
23#include <gcrypt.h>
24
25PwMerror LibGCryptIf::encrypt(unsigned char **outBuf,
26 size_t *outBufLen,
27 unsigned char *inBuf,
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
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
diff --git a/pwmanager/pwmanager/libgcryptif.h b/pwmanager/pwmanager/libgcryptif.h
new file mode 100644
index 0000000..e86d638
--- a/dev/null
+++ b/pwmanager/pwmanager/libgcryptif.h
@@ -0,0 +1,158 @@
1/***************************************************************************
2 * *
3 * copyright (C) 2004 by Michael Buesch *
4 * email: mbuesch@freenet.de *
5 * *
6 * hashPassphrase() is derived from GnuPG and is *
7 * Copyright (C) 1998, 1999, 2000, 2001, 2003 *
8 * Free Software Foundation, Inc. *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License version 2 *
12 * as published by the Free Software Foundation. *
13 * *
14 ***************************************************************************/
15
16#ifndef __LIBGCRYPTIF_H
17#define __LIBGCRYPTIF_H
18
19#include "pwmexception.h"
20
21//#undef CONFIG_PWMANAGER_GCRY // for debugging only.
22#ifdef CONFIG_PWMANAGER_GCRY
23
24#include <stddef.h>
25#include <sys/types.h>
26#include <stdint.h>
27
28 #define STRING2KEY_SALTLEN8
29
30/** interface class for the libgcrypt cipher and hash algorithms
31 * NOTE: Always allocate 1024 extra bytes for the inBuf (for padding)
32 */
33class LibGCryptIf
34{
35protected:
36 struct STRING2KEY
37 {
38 int mode;
39 int hash_algo;
40 uint8_t salt[STRING2KEY_SALTLEN];
41 uint32_t count;
42 };
43 struct DEK
44 {
45 size_t keylen;
46 uint8_t key[32]; // this is the largest used keylen (256 bit)
47 };
48
49public:
50 LibGCryptIf() { }
51 /** is libgcrypt available? */
52 static bool available()
53 { return true; }
54 /** encrypt data. _algo is the PWM_CRYPT_* ID
55 * of the algorithm.
56 */
57 PwMerror encrypt(unsigned char **outBuf,
58 size_t *outBufLen,
59 unsigned char *inBuf,
60 size_t inBufLen,
61 const unsigned char *key,
62 size_t keylen,
63 char _algo);
64 /** decrypt data. _algo is the PWM_CRYPT_* ID
65 * of the algorithm.
66 */
67 PwMerror decrypt(unsigned char **outBuf,
68 size_t *outBufLen,
69 const unsigned char *inBuf,
70 size_t inBufLen,
71 const unsigned char *key,
72 size_t keylen,
73 char _algo);
74 /** hash data. _algo is the PWM_HASH_* ID of the hash */
75 PwMerror hash(unsigned char **outBuf,
76 size_t *outBufLen,
77 const unsigned char *inBuf,
78 size_t inBufLen,
79 char _algo);
80 /** returns the length of the hash. _algo is the PWM_HASH_*
81 * id of the hash. returns 0 on error.
82 */
83 unsigned int hashLength(char _algo);
84
85protected:
86 /** returns the total buffer length */
87 size_t getBufLen(size_t inBufLen, size_t boundary)
88 {
89 return ((boundary - (inBufLen % boundary)) + inBufLen);
90 }
91 /** pad the data up to the given boundary.
92 * "buf" has to be big enough!
93 */
94 void padData(unsigned char *buf,
95 size_t bufLen,
96 size_t boundary);
97 /** unpad the data */
98 void unpadData(const unsigned char *buf,
99 size_t *bufLen);
100 /** maps the PWM_CRYPT_* ID of an algorithm
101 * to the libgcrypt GCRY_CIPHER_* ID
102 */
103 int mapCipherId(char algo);
104 /** maps the PWM_HASH_* ID of an algorithm
105 * to the libgcrypt GCRY_MD_* ID
106 */
107 int mapHashId(char algo);
108 /** hash a passphrase to a cipher key */
109 bool hashPassphrase(const unsigned char *pw,
110 size_t pwlen,
111 unsigned char *salt,
112 unsigned char *key,
113 size_t keylen,
114 bool create);
115 /** hash a passphrase to a cipher key */
116 bool doHashPassphrase(DEK *dek,
117 const unsigned char *pw,
118 size_t pwlen,
119 STRING2KEY *s2k,
120 bool create);
121};
122
123
124#else // CONFIG_PWMANAGER_GCRY
125/** libgcrypt is not installed. This is a NOP wrapper. */
126class LibGCryptIf
127{
128public:
129 LibGCryptIf() { }
130 static bool available()
131 { return false; }
132 PwMerror encrypt(unsigned char **,
133 size_t *,
134 unsigned char *,
135 size_t,
136 const unsigned char *,
137 size_t,
138 char)
139 { return e_cryptNotImpl; }
140 PwMerror decrypt(unsigned char **,
141 size_t *,
142 const unsigned char *,
143 size_t,
144 const unsigned char *,
145 size_t,
146 char)
147 { return e_cryptNotImpl; }
148 PwMerror hash(unsigned char **,
149 size_t *,
150 const unsigned char *,
151 size_t,
152 char)
153 { return e_hashNotImpl; }
154 unsigned int hashLength(char)
155 { return 0; }
156};
157#endif // CONFIG_PWMANAGER_GCRY
158#endif // __LIBGCRYPTIF_H