1 /*
2 * Copyright (c) 2000, 2001, 2002, 2005 X-Way Rights BV
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19
20 /*!\file dhies.c
21 * \brief DHIES encryption scheme.
22 * \author Bob Deblier <bob.deblier@telenet.be>
23 * \ingroup DL_m DL_dh_m
24 */
25
26 #define BEECRYPT_DLL_EXPORT
27
28 #if HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include "beecrypt/dhies.h"
33 #include "beecrypt/dlsvdp-dh.h"
34 #include "beecrypt/blockmode.h"
35 #include "beecrypt/blockpad.h"
36
37 /*
38 * Good combinations will be:
39 *
40 * For 128-bit encryption:
41 * DHIES(SHA-256,AES,HMAC-SHA-256)
42 * DHIES(SHA-256,Blowfish,HMAC-SHA-256)
43 *
44 * For 192-bit encryption:
45 * DHIES(SHA-384,AES,HMAC-SHA-384)
46 * DHIES(SHA-384,Blowfish,HMAC-SHA-384)
47 *
48 * For 256-bit encryption:
49 * DHIES(SHA-512,AES,HMAC-SHA-512)
50 * DHIES(SHA-512,Blowfish,HMAC-SHA-512)
51 *
52 */
53
dhies_pUsable(const dhies_pParameters * params)54 int dhies_pUsable(const dhies_pParameters* params)
55 {
56 size_t keybits = (params->hash->digestsize << 3); /* digestsize in bytes times 8 bits */
57 size_t cipherkeybits = params->cipherkeybits;
58 size_t mackeybits = params->mackeybits;
59
60 /* test if keybits is a multiple of 32 */
61 if ((keybits & 31) != 0)
62 return 0;
63
64 /* test if cipherkeybits + mackeybits < keybits */
65 if ((cipherkeybits + mackeybits) > keybits)
66 return 0;
67
68 if (mackeybits == 0)
69 {
70 if (cipherkeybits == 0)
71 cipherkeybits = mackeybits = (keybits >> 1);
72 else
73 mackeybits = keybits - cipherkeybits;
74 }
75
76 /* test if keybits length is appropriate for cipher */
77 if ((cipherkeybits < params->cipher->keybitsmin) ||
78 (cipherkeybits > params->cipher->keybitsmax))
79 return 0;
80
81 if (((cipherkeybits - params->cipher->keybitsmin) % params->cipher->keybitsinc) != 0)
82 return 0;
83
84 /* test if keybits length is appropriate for mac */
85 if ((mackeybits < params->mac->keybitsmin) ||
86 (params->mackeybits > params->mac->keybitsmax))
87 return 0;
88
89 if (((mackeybits - params->mac->keybitsmin) % params->mac->keybitsinc) != 0)
90 return 0;
91
92 return 1;
93 }
94
dhies_pContextInit(dhies_pContext * ctxt,const dhies_pParameters * params)95 int dhies_pContextInit(dhies_pContext* ctxt, const dhies_pParameters* params)
96 {
97 if (ctxt == (dhies_pContext*) 0)
98 return -1;
99
100 if (params == (dhies_pParameters*) 0)
101 return -1;
102
103 if (params->param == (dldp_p*) 0)
104 return -1;
105
106 if (params->hash == (hashFunction*) 0)
107 return -1;
108
109 if (params->cipher == (blockCipher*) 0)
110 return -1;
111
112 if (params->mac == (keyedHashFunction*) 0)
113 return -1;
114
115 if (!dhies_pUsable(params))
116 return -1;
117
118 dldp_pInit(&ctxt->param);
119 dldp_pCopy(&ctxt->param, params->param);
120
121 mpnzero(&ctxt->pub);
122 mpnzero(&ctxt->pri);
123
124 if (hashFunctionContextInit(&ctxt->hash, params->hash))
125 return -1;
126
127 if (blockCipherContextInit(&ctxt->cipher, params->cipher))
128 return -1;
129
130 if (keyedHashFunctionContextInit(&ctxt->mac, params->mac))
131 return -1;
132
133 ctxt->cipherkeybits = params->cipherkeybits;
134 ctxt->mackeybits = params->mackeybits;
135
136 return 0;
137 }
138
dhies_pContextInitDecrypt(dhies_pContext * ctxt,const dhies_pParameters * params,const mpnumber * pri)139 int dhies_pContextInitDecrypt(dhies_pContext* ctxt, const dhies_pParameters* params, const mpnumber* pri)
140 {
141 if (dhies_pContextInit(ctxt, params))
142 return -1;
143
144 mpncopy(&ctxt->pri, pri);
145
146 return 0;
147 }
148
dhies_pContextInitEncrypt(dhies_pContext * ctxt,const dhies_pParameters * params,const mpnumber * pub)149 int dhies_pContextInitEncrypt(dhies_pContext* ctxt, const dhies_pParameters* params, const mpnumber* pub)
150 {
151 if (dhies_pContextInit(ctxt, params))
152 return -1;
153
154 mpncopy(&ctxt->pub, pub);
155
156 return 0;
157 }
158
dhies_pContextFree(dhies_pContext * ctxt)159 int dhies_pContextFree(dhies_pContext* ctxt)
160 {
161 dldp_pFree(&ctxt->param);
162
163 mpnfree(&ctxt->pub);
164 mpnfree(&ctxt->pri);
165
166 if (hashFunctionContextFree(&ctxt->hash))
167 return -1;
168
169 if (blockCipherContextFree(&ctxt->cipher))
170 return -1;
171
172 if (keyedHashFunctionContextFree(&ctxt->mac))
173 return -1;
174
175 return 0;
176 }
177
dhies_pContextSetup(dhies_pContext * ctxt,const mpnumber * private,const mpnumber * public,const mpnumber * message,cipherOperation op)178 static int dhies_pContextSetup(dhies_pContext* ctxt, const mpnumber* private, const mpnumber* public, const mpnumber* message, cipherOperation op)
179 {
180 register int rc;
181
182 mpnumber secret;
183
184 byte* digest = (byte*) malloc(ctxt->hash.algo->digestsize);
185
186 if (digest == (byte*) 0)
187 return -1;
188
189 /* compute the shared secret, Diffie-Hellman style */
190 mpnzero(&secret);
191 if (dlsvdp_pDHSecret(&ctxt->param, private, public, &secret))
192 {
193 mpnfree(&secret);
194 free(digest);
195 return -1;
196 }
197
198 /* compute the hash of the message (ephemeral public) key and the shared secret */
199
200 hashFunctionContextReset (&ctxt->hash);
201 hashFunctionContextUpdateMP(&ctxt->hash, message);
202 hashFunctionContextUpdateMP(&ctxt->hash, &secret);
203 hashFunctionContextDigest (&ctxt->hash, digest);
204
205 /* we don't need the secret anymore */
206 mpnwipe(&secret);
207 mpnfree(&secret);
208
209 /*
210 * NOTE: blockciphers and keyed hash functions take keys with sizes
211 * specified in bits and key data passed in bytes.
212 *
213 * Both blockcipher and keyed hash function have a min and max key size.
214 *
215 * This function will split the digest of the shared secret in two halves,
216 * and pad with zero bits or truncate if necessary to meet algorithm key
217 * size requirements.
218 */
219
220 if (ctxt->hash.algo->digestsize > 0)
221 {
222 byte* mackey = digest;
223 byte* cipherkey = digest + ((ctxt->mackeybits + 7) >> 3);
224
225 if ((rc = keyedHashFunctionContextSetup(&ctxt->mac, mackey, ctxt->mackeybits)))
226 goto setup_end;
227
228 if ((rc = blockCipherContextSetup(&ctxt->cipher, cipherkey, ctxt->cipherkeybits, op)))
229 goto setup_end;
230
231 rc = 0;
232 }
233 else
234 rc = -1;
235
236 setup_end:
237 /* wipe digest for good measure */
238 memset(digest, 0, ctxt->hash.algo->digestsize);
239 free(digest);
240
241 return rc;
242 }
243
dhies_pContextEncrypt(dhies_pContext * ctxt,mpnumber * ephemeralPublicKey,mpnumber * mac,const memchunk * cleartext,randomGeneratorContext * rng)244 memchunk* dhies_pContextEncrypt(dhies_pContext* ctxt, mpnumber* ephemeralPublicKey, mpnumber* mac, const memchunk* cleartext, randomGeneratorContext* rng)
245 {
246 memchunk* ciphertext = (memchunk*) 0;
247 memchunk* paddedtext;
248
249 mpnumber ephemeralPrivateKey;
250
251 /* make the ephemeral keypair */
252 mpnzero(&ephemeralPrivateKey);
253 dldp_pPair(&ctxt->param, rng, &ephemeralPrivateKey, ephemeralPublicKey);
254
255 /* Setup the key and initialize the mac and the blockcipher */
256 if (dhies_pContextSetup(ctxt, &ephemeralPrivateKey, &ctxt->pub, ephemeralPublicKey, ENCRYPT))
257 goto encrypt_end;
258
259 /* add pkcs-5 padding */
260 paddedtext = pkcs5PadCopy(ctxt->cipher.algo->blocksize, cleartext);
261
262 /* encrypt the memchunk in CBC mode */
263 if (blockEncryptCBC(ctxt->cipher.algo, ctxt->cipher.param, (uint32_t*) paddedtext->data, (const uint32_t*) paddedtext->data, paddedtext->size / ctxt->cipher.algo->blocksize))
264 {
265 free(paddedtext->data);
266 free(paddedtext);
267 goto encrypt_end;
268 }
269
270 /* Compute the mac */
271 if (keyedHashFunctionContextUpdateMC(&ctxt->mac, paddedtext))
272 {
273 free(paddedtext->data);
274 free(paddedtext);
275 goto encrypt_end;
276 }
277
278 if (keyedHashFunctionContextDigestMP(&ctxt->mac, mac))
279 {
280 free(paddedtext->data);
281 free(paddedtext);
282 goto encrypt_end;
283 }
284
285 ciphertext = paddedtext;
286
287 encrypt_end:
288 mpnwipe(&ephemeralPrivateKey);
289 mpnfree(&ephemeralPrivateKey);
290
291 return ciphertext;
292 }
293
dhies_pContextDecrypt(dhies_pContext * ctxt,const mpnumber * ephemeralPublicKey,const mpnumber * mac,const memchunk * ciphertext)294 memchunk* dhies_pContextDecrypt(dhies_pContext* ctxt, const mpnumber* ephemeralPublicKey, const mpnumber* mac, const memchunk* ciphertext)
295 {
296 memchunk* cleartext = (memchunk*) 0;
297 memchunk* paddedtext;
298
299 /* Setup the key and initialize the mac and the blockcipher */
300 if (dhies_pContextSetup(ctxt, &ctxt->pri, ephemeralPublicKey, ephemeralPublicKey, DECRYPT))
301 goto decrypt_end;
302
303 /* Verify the mac */
304 if (keyedHashFunctionContextUpdateMC(&ctxt->mac, ciphertext))
305 goto decrypt_end;
306
307 if (keyedHashFunctionContextDigestMatch(&ctxt->mac, mac) == 0)
308 goto decrypt_end;
309
310 /* decrypt the memchunk with CBC mode */
311 paddedtext = (memchunk*) calloc(1, sizeof(memchunk));
312
313 if (paddedtext == (memchunk*) 0)
314 goto decrypt_end;
315
316 paddedtext->size = ciphertext->size;
317 paddedtext->data = (byte*) malloc(ciphertext->size);
318
319 if (paddedtext->data == (byte*) 0)
320 {
321 free(paddedtext);
322 goto decrypt_end;
323 }
324
325 if (blockDecryptCBC(ctxt->cipher.algo, ctxt->cipher.param, (uint32_t*) paddedtext->data, (const uint32_t*) ciphertext->data, paddedtext->size / ctxt->cipher.algo->blocksize))
326 {
327 free(paddedtext->data);
328 free(paddedtext);
329 goto decrypt_end;
330 }
331
332 /* remove pkcs-5 padding */
333 cleartext = pkcs5Unpad(ctxt->cipher.algo->blocksize, paddedtext);
334
335 if (cleartext == (memchunk*) 0)
336 {
337 free(paddedtext->data);
338 free(paddedtext);
339 }
340
341 decrypt_end:
342
343 return cleartext;
344 }
345