OLD | NEW |
| (Empty) |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 | |
5 /* | |
6 * Diffie-Hellman parameter generation, key generation, and secret derivation. | |
7 * KEA secret generation and verification. | |
8 * | |
9 * $Id: dh.c,v 1.12 2012/06/14 18:55:10 wtc%google.com Exp $ | |
10 */ | |
11 #ifdef FREEBL_NO_DEPEND | |
12 #include "stubs.h" | |
13 #endif | |
14 | |
15 #include "prerr.h" | |
16 #include "secerr.h" | |
17 | |
18 #include "blapi.h" | |
19 #include "secitem.h" | |
20 #include "mpi.h" | |
21 #include "mpprime.h" | |
22 #include "secmpi.h" | |
23 | |
24 #define KEA_DERIVED_SECRET_LEN 128 | |
25 | |
26 /* Lengths are in bytes. */ | |
27 static unsigned int | |
28 dh_GetSecretKeyLen(unsigned int primeLen) | |
29 { | |
30 /* Based on Table 2 in NIST SP 800-57. */ | |
31 if (primeLen >= 1920) { /* 15360 bits */ | |
32 return 64; /* 512 bits */ | |
33 } | |
34 if (primeLen >= 960) { /* 7680 bits */ | |
35 return 48; /* 384 bits */ | |
36 } | |
37 if (primeLen >= 384) { /* 3072 bits */ | |
38 return 32; /* 256 bits */ | |
39 } | |
40 if (primeLen >= 256) { /* 2048 bits */ | |
41 return 28; /* 224 bits */ | |
42 } | |
43 return 20; /* 160 bits */ | |
44 } | |
45 | |
46 SECStatus | |
47 DH_GenParam(int primeLen, DHParams **params) | |
48 { | |
49 PRArenaPool *arena; | |
50 DHParams *dhparams; | |
51 unsigned char *pb = NULL; | |
52 unsigned char *ab = NULL; | |
53 unsigned long counter = 0; | |
54 mp_int p, q, a, h, psub1, test; | |
55 mp_err err = MP_OKAY; | |
56 SECStatus rv = SECSuccess; | |
57 if (!params || primeLen < 0) { | |
58 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
59 return SECFailure; | |
60 } | |
61 arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); | |
62 if (!arena) { | |
63 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
64 return SECFailure; | |
65 } | |
66 dhparams = (DHParams *)PORT_ArenaZAlloc(arena, sizeof(DHParams)); | |
67 if (!dhparams) { | |
68 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
69 PORT_FreeArena(arena, PR_TRUE); | |
70 return SECFailure; | |
71 } | |
72 dhparams->arena = arena; | |
73 MP_DIGITS(&p) = 0; | |
74 MP_DIGITS(&q) = 0; | |
75 MP_DIGITS(&a) = 0; | |
76 MP_DIGITS(&h) = 0; | |
77 MP_DIGITS(&psub1) = 0; | |
78 MP_DIGITS(&test) = 0; | |
79 CHECK_MPI_OK( mp_init(&p) ); | |
80 CHECK_MPI_OK( mp_init(&q) ); | |
81 CHECK_MPI_OK( mp_init(&a) ); | |
82 CHECK_MPI_OK( mp_init(&h) ); | |
83 CHECK_MPI_OK( mp_init(&psub1) ); | |
84 CHECK_MPI_OK( mp_init(&test) ); | |
85 /* generate prime with MPI, uses Miller-Rabin to generate strong prime. */ | |
86 pb = PORT_Alloc(primeLen); | |
87 CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(pb, primeLen) ); | |
88 pb[0] |= 0x80; /* set high-order bit */ | |
89 pb[primeLen-1] |= 0x01; /* set low-order bit */ | |
90 CHECK_MPI_OK( mp_read_unsigned_octets(&p, pb, primeLen) ); | |
91 CHECK_MPI_OK( mpp_make_prime(&p, primeLen * 8, PR_TRUE, &counter) ); | |
92 /* construct Sophie-Germain prime q = (p-1)/2. */ | |
93 CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) ); | |
94 CHECK_MPI_OK( mp_div_2(&psub1, &q) ); | |
95 /* construct a generator from the prime. */ | |
96 ab = PORT_Alloc(primeLen); | |
97 /* generate a candidate number a in p's field */ | |
98 CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(ab, primeLen) ); | |
99 CHECK_MPI_OK( mp_read_unsigned_octets(&a, ab, primeLen) ); | |
100 /* force a < p (note that quot(a/p) <= 1) */ | |
101 if ( mp_cmp(&a, &p) > 0 ) | |
102 CHECK_MPI_OK( mp_sub(&a, &p, &a) ); | |
103 do { | |
104 /* check that a is in the range [2..p-1] */ | |
105 if ( mp_cmp_d(&a, 2) < 0 || mp_cmp(&a, &psub1) >= 0) { | |
106 /* a is outside of the allowed range. Set a=3 and keep going. */ | |
107 mp_set(&a, 3); | |
108 } | |
109 /* if a**q mod p != 1 then a is a generator */ | |
110 CHECK_MPI_OK( mp_exptmod(&a, &q, &p, &test) ); | |
111 if ( mp_cmp_d(&test, 1) != 0 ) | |
112 break; | |
113 /* increment the candidate and try again. */ | |
114 CHECK_MPI_OK( mp_add_d(&a, 1, &a) ); | |
115 } while (PR_TRUE); | |
116 MPINT_TO_SECITEM(&p, &dhparams->prime, arena); | |
117 MPINT_TO_SECITEM(&a, &dhparams->base, arena); | |
118 *params = dhparams; | |
119 cleanup: | |
120 mp_clear(&p); | |
121 mp_clear(&q); | |
122 mp_clear(&a); | |
123 mp_clear(&h); | |
124 mp_clear(&psub1); | |
125 mp_clear(&test); | |
126 if (pb) PORT_ZFree(pb, primeLen); | |
127 if (ab) PORT_ZFree(ab, primeLen); | |
128 if (err) { | |
129 MP_TO_SEC_ERROR(err); | |
130 rv = SECFailure; | |
131 } | |
132 if (rv) | |
133 PORT_FreeArena(arena, PR_TRUE); | |
134 return rv; | |
135 } | |
136 | |
137 SECStatus | |
138 DH_NewKey(DHParams *params, DHPrivateKey **privKey) | |
139 { | |
140 PRArenaPool *arena; | |
141 DHPrivateKey *key; | |
142 mp_int g, xa, p, Ya; | |
143 mp_err err = MP_OKAY; | |
144 SECStatus rv = SECSuccess; | |
145 if (!params || !privKey) { | |
146 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
147 return SECFailure; | |
148 } | |
149 arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); | |
150 if (!arena) { | |
151 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
152 return SECFailure; | |
153 } | |
154 key = (DHPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DHPrivateKey)); | |
155 if (!key) { | |
156 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
157 PORT_FreeArena(arena, PR_TRUE); | |
158 return SECFailure; | |
159 } | |
160 key->arena = arena; | |
161 MP_DIGITS(&g) = 0; | |
162 MP_DIGITS(&xa) = 0; | |
163 MP_DIGITS(&p) = 0; | |
164 MP_DIGITS(&Ya) = 0; | |
165 CHECK_MPI_OK( mp_init(&g) ); | |
166 CHECK_MPI_OK( mp_init(&xa) ); | |
167 CHECK_MPI_OK( mp_init(&p) ); | |
168 CHECK_MPI_OK( mp_init(&Ya) ); | |
169 /* Set private key's p */ | |
170 CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->prime, ¶ms->prime) ); | |
171 SECITEM_TO_MPINT(key->prime, &p); | |
172 /* Set private key's g */ | |
173 CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->base, ¶ms->base) ); | |
174 SECITEM_TO_MPINT(key->base, &g); | |
175 /* Generate private key xa */ | |
176 SECITEM_AllocItem(arena, &key->privateValue, | |
177 dh_GetSecretKeyLen(params->prime.len)); | |
178 RNG_GenerateGlobalRandomBytes(key->privateValue.data, | |
179 key->privateValue.len); | |
180 SECITEM_TO_MPINT( key->privateValue, &xa ); | |
181 /* xa < p */ | |
182 CHECK_MPI_OK( mp_mod(&xa, &p, &xa) ); | |
183 /* Compute public key Ya = g ** xa mod p */ | |
184 CHECK_MPI_OK( mp_exptmod(&g, &xa, &p, &Ya) ); | |
185 MPINT_TO_SECITEM(&Ya, &key->publicValue, key->arena); | |
186 *privKey = key; | |
187 cleanup: | |
188 mp_clear(&g); | |
189 mp_clear(&xa); | |
190 mp_clear(&p); | |
191 mp_clear(&Ya); | |
192 if (err) { | |
193 MP_TO_SEC_ERROR(err); | |
194 rv = SECFailure; | |
195 } | |
196 if (rv) | |
197 PORT_FreeArena(arena, PR_TRUE); | |
198 return rv; | |
199 } | |
200 | |
201 SECStatus | |
202 DH_Derive(SECItem *publicValue, | |
203 SECItem *prime, | |
204 SECItem *privateValue, | |
205 SECItem *derivedSecret, | |
206 unsigned int outBytes) | |
207 { | |
208 mp_int p, Xa, Yb, ZZ; | |
209 mp_err err = MP_OKAY; | |
210 int len = 0; | |
211 unsigned int nb; | |
212 unsigned char *secret = NULL; | |
213 if (!publicValue || !prime || !privateValue || !derivedSecret) { | |
214 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
215 return SECFailure; | |
216 } | |
217 memset(derivedSecret, 0, sizeof *derivedSecret); | |
218 MP_DIGITS(&p) = 0; | |
219 MP_DIGITS(&Xa) = 0; | |
220 MP_DIGITS(&Yb) = 0; | |
221 MP_DIGITS(&ZZ) = 0; | |
222 CHECK_MPI_OK( mp_init(&p) ); | |
223 CHECK_MPI_OK( mp_init(&Xa) ); | |
224 CHECK_MPI_OK( mp_init(&Yb) ); | |
225 CHECK_MPI_OK( mp_init(&ZZ) ); | |
226 SECITEM_TO_MPINT(*publicValue, &Yb); | |
227 SECITEM_TO_MPINT(*privateValue, &Xa); | |
228 SECITEM_TO_MPINT(*prime, &p); | |
229 /* ZZ = (Yb)**Xa mod p */ | |
230 CHECK_MPI_OK( mp_exptmod(&Yb, &Xa, &p, &ZZ) ); | |
231 /* number of bytes in the derived secret */ | |
232 len = mp_unsigned_octet_size(&ZZ); | |
233 if (len <= 0) { | |
234 err = MP_BADARG; | |
235 goto cleanup; | |
236 } | |
237 /* allocate a buffer which can hold the entire derived secret. */ | |
238 secret = PORT_Alloc(len); | |
239 /* grab the derived secret */ | |
240 err = mp_to_unsigned_octets(&ZZ, secret, len); | |
241 if (err >= 0) err = MP_OKAY; | |
242 /* | |
243 ** if outBytes is 0 take all of the bytes from the derived secret. | |
244 ** if outBytes is not 0 take exactly outBytes from the derived secret, zero | |
245 ** pad at the beginning if necessary, and truncate beginning bytes | |
246 ** if necessary. | |
247 */ | |
248 if (outBytes > 0) | |
249 nb = outBytes; | |
250 else | |
251 nb = len; | |
252 SECITEM_AllocItem(NULL, derivedSecret, nb); | |
253 if (len < nb) { | |
254 unsigned int offset = nb - len; | |
255 memset(derivedSecret->data, 0, offset); | |
256 memcpy(derivedSecret->data + offset, secret, len); | |
257 } else { | |
258 memcpy(derivedSecret->data, secret + len - nb, nb); | |
259 } | |
260 cleanup: | |
261 mp_clear(&p); | |
262 mp_clear(&Xa); | |
263 mp_clear(&Yb); | |
264 mp_clear(&ZZ); | |
265 if (secret) { | |
266 /* free the buffer allocated for the full secret. */ | |
267 PORT_ZFree(secret, len); | |
268 } | |
269 if (err) { | |
270 MP_TO_SEC_ERROR(err); | |
271 if (derivedSecret->data) | |
272 PORT_ZFree(derivedSecret->data, derivedSecret->len); | |
273 return SECFailure; | |
274 } | |
275 return SECSuccess; | |
276 } | |
277 | |
278 SECStatus | |
279 KEA_Derive(SECItem *prime, | |
280 SECItem *public1, | |
281 SECItem *public2, | |
282 SECItem *private1, | |
283 SECItem *private2, | |
284 SECItem *derivedSecret) | |
285 { | |
286 mp_int p, Y, R, r, x, t, u, w; | |
287 mp_err err; | |
288 unsigned char *secret = NULL; | |
289 unsigned int len = 0, offset; | |
290 if (!prime || !public1 || !public2 || !private1 || !private2 || | |
291 !derivedSecret) { | |
292 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
293 return SECFailure; | |
294 } | |
295 memset(derivedSecret, 0, sizeof *derivedSecret); | |
296 MP_DIGITS(&p) = 0; | |
297 MP_DIGITS(&Y) = 0; | |
298 MP_DIGITS(&R) = 0; | |
299 MP_DIGITS(&r) = 0; | |
300 MP_DIGITS(&x) = 0; | |
301 MP_DIGITS(&t) = 0; | |
302 MP_DIGITS(&u) = 0; | |
303 MP_DIGITS(&w) = 0; | |
304 CHECK_MPI_OK( mp_init(&p) ); | |
305 CHECK_MPI_OK( mp_init(&Y) ); | |
306 CHECK_MPI_OK( mp_init(&R) ); | |
307 CHECK_MPI_OK( mp_init(&r) ); | |
308 CHECK_MPI_OK( mp_init(&x) ); | |
309 CHECK_MPI_OK( mp_init(&t) ); | |
310 CHECK_MPI_OK( mp_init(&u) ); | |
311 CHECK_MPI_OK( mp_init(&w) ); | |
312 SECITEM_TO_MPINT(*prime, &p); | |
313 SECITEM_TO_MPINT(*public1, &Y); | |
314 SECITEM_TO_MPINT(*public2, &R); | |
315 SECITEM_TO_MPINT(*private1, &r); | |
316 SECITEM_TO_MPINT(*private2, &x); | |
317 /* t = DH(Y, r, p) = Y ** r mod p */ | |
318 CHECK_MPI_OK( mp_exptmod(&Y, &r, &p, &t) ); | |
319 /* u = DH(R, x, p) = R ** x mod p */ | |
320 CHECK_MPI_OK( mp_exptmod(&R, &x, &p, &u) ); | |
321 /* w = (t + u) mod p */ | |
322 CHECK_MPI_OK( mp_addmod(&t, &u, &p, &w) ); | |
323 /* allocate a buffer for the full derived secret */ | |
324 len = mp_unsigned_octet_size(&w); | |
325 secret = PORT_Alloc(len); | |
326 /* grab the secret */ | |
327 err = mp_to_unsigned_octets(&w, secret, len); | |
328 if (err > 0) err = MP_OKAY; | |
329 /* allocate output buffer */ | |
330 SECITEM_AllocItem(NULL, derivedSecret, KEA_DERIVED_SECRET_LEN); | |
331 memset(derivedSecret->data, 0, derivedSecret->len); | |
332 /* copy in the 128 lsb of the secret */ | |
333 if (len >= KEA_DERIVED_SECRET_LEN) { | |
334 memcpy(derivedSecret->data, secret + (len - KEA_DERIVED_SECRET_LEN), | |
335 KEA_DERIVED_SECRET_LEN); | |
336 } else { | |
337 offset = KEA_DERIVED_SECRET_LEN - len; | |
338 memcpy(derivedSecret->data + offset, secret, len); | |
339 } | |
340 cleanup: | |
341 mp_clear(&p); | |
342 mp_clear(&Y); | |
343 mp_clear(&R); | |
344 mp_clear(&r); | |
345 mp_clear(&x); | |
346 mp_clear(&t); | |
347 mp_clear(&u); | |
348 mp_clear(&w); | |
349 if (secret) | |
350 PORT_ZFree(secret, len); | |
351 if (err) { | |
352 MP_TO_SEC_ERROR(err); | |
353 return SECFailure; | |
354 } | |
355 return SECSuccess; | |
356 } | |
357 | |
358 PRBool | |
359 KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime) | |
360 { | |
361 mp_int p, q, y, r; | |
362 mp_err err; | |
363 int cmp = 1; /* default is false */ | |
364 if (!Y || !prime || !subPrime) { | |
365 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
366 return SECFailure; | |
367 } | |
368 MP_DIGITS(&p) = 0; | |
369 MP_DIGITS(&q) = 0; | |
370 MP_DIGITS(&y) = 0; | |
371 MP_DIGITS(&r) = 0; | |
372 CHECK_MPI_OK( mp_init(&p) ); | |
373 CHECK_MPI_OK( mp_init(&q) ); | |
374 CHECK_MPI_OK( mp_init(&y) ); | |
375 CHECK_MPI_OK( mp_init(&r) ); | |
376 SECITEM_TO_MPINT(*prime, &p); | |
377 SECITEM_TO_MPINT(*subPrime, &q); | |
378 SECITEM_TO_MPINT(*Y, &y); | |
379 /* compute r = y**q mod p */ | |
380 CHECK_MPI_OK( mp_exptmod(&y, &q, &p, &r) ); | |
381 /* compare to 1 */ | |
382 cmp = mp_cmp_d(&r, 1); | |
383 cleanup: | |
384 mp_clear(&p); | |
385 mp_clear(&q); | |
386 mp_clear(&y); | |
387 mp_clear(&r); | |
388 if (err) { | |
389 MP_TO_SEC_ERROR(err); | |
390 return PR_FALSE; | |
391 } | |
392 return (cmp == 0) ? PR_TRUE : PR_FALSE; | |
393 } | |
OLD | NEW |