3
|
1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis |
|
2 * |
|
3 * LibTomCrypt is a library that provides various cryptographic |
|
4 * algorithms in a highly modular and flexible manner. |
|
5 * |
|
6 * The library is free for all purposes without any express |
|
7 * guarantee it works. |
|
8 * |
|
9 * Tom St Denis, [email protected], http://libtomcrypt.org |
|
10 */ |
|
11 |
|
12 /* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b |
|
13 * |
|
14 * All curves taken from NIST recommendation paper of July 1999 |
|
15 * Available at http://csrc.nist.gov/cryptval/dss.htm |
|
16 */ |
|
17 |
|
18 #include "mycrypt.h" |
|
19 |
|
20 #ifdef MECC |
|
21 |
143
|
22 /* size of our temp buffers for exported keys */ |
|
23 #define ECC_BUF_SIZE 160 |
|
24 |
|
25 /* max private key size */ |
|
26 #define ECC_MAXSIZE 66 |
|
27 |
3
|
28 /* This holds the key settings. ***MUST*** be organized by size from smallest to largest. */ |
|
29 static const struct { |
|
30 int size; |
|
31 char *name, *prime, *B, *order, *Gx, *Gy; |
|
32 } sets[] = { |
|
33 #ifdef ECC160 |
|
34 { |
|
35 20, |
|
36 "ECC-160", |
|
37 /* prime */ |
|
38 "G00000000000000000000000007", |
|
39 /* B */ |
|
40 "1oUV2vOaSlWbxr6", |
|
41 /* order */ |
|
42 "G0000000000004sCQUtDxaqDUN5", |
|
43 /* Gx */ |
|
44 "jpqOf1BHus6Yd/pyhyVpP", |
|
45 /* Gy */ |
|
46 "D/wykuuIFfr+vPyx7kQEPu8MixO", |
|
47 }, |
|
48 #endif |
|
49 #ifdef ECC192 |
|
50 { |
|
51 24, |
|
52 "ECC-192", |
|
53 /* prime */ |
|
54 "/////////////////////l//////////", |
|
55 |
|
56 /* B */ |
|
57 "P2456UMSWESFf+chSYGmIVwutkp1Hhcn", |
|
58 |
|
59 /* order */ |
|
60 "////////////////cTxuDXHhoR6qqYWn", |
|
61 |
|
62 /* Gx */ |
|
63 "68se3h0maFPylo3hGw680FJ/2ls2/n0I", |
|
64 |
|
65 /* Gy */ |
|
66 "1nahbV/8sdXZ417jQoJDrNFvTw4UUKWH" |
|
67 }, |
|
68 #endif |
|
69 #ifdef ECC224 |
|
70 { |
|
71 28, |
|
72 "ECC-224", |
|
73 |
|
74 /* prime */ |
|
75 "400000000000000000000000000000000000BV", |
|
76 |
|
77 /* B */ |
|
78 "21HkWGL2CxJIp", |
|
79 |
|
80 /* order */ |
|
81 "4000000000000000000Kxnixk9t8MLzMiV264/", |
|
82 |
|
83 /* Gx */ |
|
84 "jpqOf1BHus6Yd/pyhyVpP", |
|
85 |
|
86 /* Gy */ |
|
87 "3FCtyo2yHA5SFjkCGbYxbOvNeChwS+j6wSIwck", |
|
88 }, |
|
89 #endif |
|
90 #ifdef ECC256 |
|
91 { |
|
92 32, |
|
93 "ECC-256", |
|
94 /* Prime */ |
|
95 "F////y000010000000000000000////////////////", |
|
96 |
|
97 /* B */ |
|
98 "5h6DTYgEfFdi+kzLNQOXhnb7GQmp5EmzZlEF3udqc1B", |
|
99 |
|
100 /* Order */ |
|
101 "F////y00000//////////+yvlgjfnUUXFEvoiByOoLH", |
|
102 |
|
103 /* Gx */ |
|
104 "6iNqVBXB497+BpcvMEaGF9t0ts1BUipeFIXEKNOcCAM", |
|
105 |
|
106 /* Gy */ |
|
107 "4/ZGkB+6d+RZkVhIdmFdXOhpZDNQp5UpiksG6Wtlr7r" |
|
108 }, |
|
109 #endif |
|
110 #ifdef ECC384 |
|
111 { |
|
112 48, |
|
113 "ECC-384", |
|
114 /* prime */ |
|
115 "//////////////////////////////////////////x/////00000000003/" |
|
116 "////", |
|
117 |
|
118 /* B */ |
|
119 "ip4lf+8+v+IOZWLhu/Wj6HWTd6x+WK4I0nG8Zr0JXrh6LZcDYYxHdIg5oEtJ" |
|
120 "x2hl", |
|
121 |
|
122 /* Order */ |
|
123 "////////////////////////////////nsDDWVGtBTzO6WsoIB2dUkpi6MhC" |
|
124 "nIbp", |
|
125 |
|
126 /* Gx and Gy */ |
|
127 "geVA8hwB1JUEiSSUyo2jT6uTEsABfvkOMVT1u89KAZXL0l9TlrKfR3fKNZXo" |
|
128 "TWgt", |
|
129 |
|
130 "DXVUIfOcB6zTdfY/afBSAVZq7RqecXHywTen4xNmkC0AOB7E7Nw1dNf37NoG" |
|
131 "wWvV" |
|
132 }, |
|
133 #endif |
|
134 #ifdef ECC521 |
|
135 { |
|
136 65, |
|
137 "ECC-521", |
|
138 /* prime */ |
|
139 "V///////////////////////////////////////////////////////////" |
|
140 "///////////////////////////", |
|
141 |
|
142 /* B */ |
|
143 "56LFhbXZXoQ7vAQ8Q2sXK3kejfoMvcp5VEuj8cHZl49uLOPEL7iVfDx5bB0l" |
|
144 "JknlmSrSz+8FImqyUz57zHhK3y0", |
|
145 |
|
146 /* Order */ |
|
147 "V//////////////////////////////////////////+b66XuE/BvPhVym1I" |
|
148 "FS9fT0xjScuYPn7hhjljnwHE6G9", |
|
149 |
|
150 /* Gx and Gy */ |
|
151 "CQ5ZWQt10JfpPu+osOZbRH2d6I1EGK/jI7uAAzWQqqzkg5BNdVlvrae/Xt19" |
|
152 "wB/gDupIBF1XMf2c/b+VZ72vRrc", |
|
153 |
|
154 "HWvAMfucZl015oANxGiVHlPcFL4ILURH6WNhxqN9pvcB9VkSfbUz2P0nL2v0" |
|
155 "J+j1s4rF726edB2G8Y+b7QVqMPG", |
|
156 }, |
|
157 #endif |
|
158 { |
|
159 0, |
|
160 NULL, NULL, NULL, NULL, NULL, NULL |
|
161 } |
|
162 }; |
|
163 |
|
164 #if 0 |
|
165 |
|
166 /* you plug in a prime and B value and it finds a pseudo-random base point */ |
|
167 void ecc_find_base(void) |
|
168 { |
|
169 static char *prime = "26959946667150639794667015087019630673637144422540572481103610249951"; |
|
170 static char *order = "26959946667150639794667015087019637467111563745054605861463538557247"; |
|
171 static char *b = "9538957348957353489587"; |
|
172 mp_int pp, p, r, B, tmp1, tmp2, tx, ty, x, y; |
|
173 char buf[4096]; |
|
174 int i; |
|
175 |
|
176 mp_init_multi(&tx, &ty, &x, &y, &p, &pp, &r, &B, &tmp1, &tmp2, NULL); |
|
177 mp_read_radix(&p, prime, 10); |
|
178 mp_read_radix(&r, order, 10); |
|
179 mp_read_radix(&B, b, 10); |
|
180 |
|
181 /* get (p+1)/4 */ |
|
182 mp_add_d(&p, 1, &pp); |
|
183 mp_div_2(&pp, &pp); |
|
184 mp_div_2(&pp, &pp); |
|
185 |
|
186 buf[0] = 0; |
|
187 do { |
|
188 printf("."); fflush(stdout); |
|
189 /* make a random value of x */ |
|
190 for (i = 0; i < 16; i++) buf[i+1] = rand() & 255; |
|
191 mp_read_raw(&x, buf, 17); |
|
192 mp_copy(&x, &tx); |
|
193 |
|
194 /* now compute x^3 - 3x + b */ |
|
195 mp_expt_d(&x, 3, &tmp1); |
|
196 mp_mul_d(&x, 3, &tmp2); |
|
197 mp_sub(&tmp1, &tmp2, &tmp1); |
|
198 mp_add(&tmp1, &B, &tmp1); |
|
199 mp_mod(&tmp1, &p, &tmp1); |
|
200 |
|
201 /* now compute sqrt via x^((p+1)/4) */ |
|
202 mp_exptmod(&tmp1, &pp, &p, &tmp2); |
|
203 mp_copy(&tmp2, &ty); |
|
204 |
|
205 /* now square it */ |
|
206 mp_sqrmod(&tmp2, &p, &tmp2); |
|
207 |
|
208 /* tmp2 should equal tmp1 */ |
|
209 } while (mp_cmp(&tmp1, &tmp2)); |
|
210 |
|
211 /* now output values in way that libtomcrypt wants */ |
|
212 mp_todecimal(&p, buf); |
|
213 printf("\n\np==%s\n", buf); |
|
214 mp_tohex(&B, buf); |
|
215 printf("b==%s\n", buf); |
|
216 mp_todecimal(&r, buf); |
|
217 printf("r==%s\n", buf); |
|
218 mp_tohex(&tx, buf); |
|
219 printf("Gx==%s\n", buf); |
|
220 mp_tohex(&ty, buf); |
|
221 printf("Gy==%s\n", buf); |
|
222 |
|
223 mp_clear_multi(&tx, &ty, &x, &y, &p, &pp, &r, &B, &tmp1, &tmp2, NULL); |
|
224 } |
|
225 |
|
226 #endif |
|
227 |
|
228 static int is_valid_idx(int n) |
|
229 { |
|
230 int x; |
|
231 |
|
232 for (x = 0; sets[x].size != 0; x++); |
|
233 if ((n < 0) || (n >= x)) { |
|
234 return 0; |
|
235 } |
|
236 return 1; |
|
237 } |
|
238 |
|
239 static ecc_point *new_point(void) |
|
240 { |
|
241 ecc_point *p; |
|
242 p = XMALLOC(sizeof(ecc_point)); |
|
243 if (p == NULL) { |
|
244 return NULL; |
|
245 } |
|
246 if (mp_init_multi(&p->x, &p->y, NULL) != MP_OKAY) { |
|
247 XFREE(p); |
|
248 return NULL; |
|
249 } |
|
250 return p; |
|
251 } |
|
252 |
|
253 static void del_point(ecc_point *p) |
|
254 { |
|
255 /* prevents free'ing null arguments */ |
|
256 if (p != NULL) { |
|
257 mp_clear_multi(&p->x, &p->y, NULL); |
|
258 XFREE(p); |
|
259 } |
|
260 } |
|
261 |
|
262 /* double a point R = 2P, R can be P*/ |
|
263 static int dbl_point(ecc_point *P, ecc_point *R, mp_int *modulus, mp_int *mu) |
|
264 { |
|
265 mp_int s, tmp, tmpx; |
|
266 int err; |
|
267 |
|
268 if ((err = mp_init_multi(&s, &tmp, &tmpx, NULL)) != MP_OKAY) { |
|
269 return mpi_to_ltc_error(err); |
|
270 } |
|
271 |
|
272 /* s = (3Xp^2 + a) / (2Yp) */ |
|
273 if ((err = mp_mul_2(&P->y, &tmp)) != MP_OKAY) { goto error; } /* tmp = 2*y */ |
|
274 if ((err = mp_invmod(&tmp, modulus, &tmp)) != MP_OKAY) { goto error; } /* tmp = 1/tmp mod modulus */ |
|
275 if ((err = mp_sqr(&P->x, &s)) != MP_OKAY) { goto error; } /* s = x^2 */ |
|
276 if ((err = mp_reduce(&s, modulus, mu)) != MP_OKAY) { goto error; } |
|
277 if ((err = mp_mul_d(&s,(mp_digit)3, &s)) != MP_OKAY) { goto error; } /* s = 3*(x^2) */ |
|
278 if ((err = mp_sub_d(&s,(mp_digit)3, &s)) != MP_OKAY) { goto error; } /* s = 3*(x^2) - 3 */ |
|
279 if (mp_cmp_d(&s, 0) == MP_LT) { /* if s < 0 add modulus */ |
|
280 if ((err = mp_add(&s, modulus, &s)) != MP_OKAY) { goto error; } |
|
281 } |
|
282 if ((err = mp_mul(&s, &tmp, &s)) != MP_OKAY) { goto error; } /* s = tmp * s mod modulus */ |
|
283 if ((err = mp_reduce(&s, modulus, mu)) != MP_OKAY) { goto error; } |
|
284 |
|
285 /* Xr = s^2 - 2Xp */ |
|
286 if ((err = mp_sqr(&s, &tmpx)) != MP_OKAY) { goto error; } /* tmpx = s^2 */ |
|
287 if ((err = mp_reduce(&tmpx, modulus, mu)) != MP_OKAY) { goto error; } /* tmpx = tmpx mod modulus */ |
|
288 if ((err = mp_sub(&tmpx, &P->x, &tmpx)) != MP_OKAY) { goto error; } /* tmpx = tmpx - x */ |
|
289 if ((err = mp_submod(&tmpx, &P->x, modulus, &tmpx)) != MP_OKAY) { goto error; } /* tmpx = tmpx - x mod modulus */ |
|
290 |
|
291 /* Yr = -Yp + s(Xp - Xr) */ |
|
292 if ((err = mp_sub(&P->x, &tmpx, &tmp)) != MP_OKAY) { goto error; } /* tmp = x - tmpx */ |
|
293 if ((err = mp_mul(&tmp, &s, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp * s */ |
|
294 if ((err = mp_submod(&tmp, &P->y, modulus, &R->y)) != MP_OKAY) { goto error; } /* y = tmp - y mod modulus */ |
|
295 if ((err = mp_copy(&tmpx, &R->x)) != MP_OKAY) { goto error; } /* x = tmpx */ |
|
296 |
|
297 err = CRYPT_OK; |
|
298 goto done; |
|
299 error: |
|
300 err = mpi_to_ltc_error(err); |
|
301 done: |
|
302 mp_clear_multi(&tmpx, &tmp, &s, NULL); |
|
303 return err; |
|
304 } |
|
305 |
|
306 /* add two different points over Z/pZ, R = P + Q, note R can equal either P or Q */ |
|
307 static int add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mp_int *modulus, mp_int *mu) |
|
308 { |
|
309 mp_int s, tmp, tmpx; |
|
310 int err; |
|
311 |
|
312 if ((err = mp_init(&tmp)) != MP_OKAY) { |
|
313 return mpi_to_ltc_error(err); |
|
314 } |
|
315 |
|
316 /* is P==Q or P==-Q? */ |
|
317 if (((err = mp_neg(&Q->y, &tmp)) != MP_OKAY) || ((err = mp_mod(&tmp, modulus, &tmp)) != MP_OKAY)) { |
|
318 mp_clear(&tmp); |
|
319 return mpi_to_ltc_error(err); |
|
320 } |
|
321 |
|
322 if (mp_cmp(&P->x, &Q->x) == MP_EQ) |
|
323 if (mp_cmp(&P->y, &Q->y) == MP_EQ || mp_cmp(&P->y, &tmp) == MP_EQ) { |
|
324 mp_clear(&tmp); |
|
325 return dbl_point(P, R, modulus, mu); |
|
326 } |
|
327 |
|
328 if ((err = mp_init_multi(&tmpx, &s, NULL)) != MP_OKAY) { |
|
329 mp_clear(&tmp); |
|
330 return mpi_to_ltc_error(err); |
|
331 } |
|
332 |
|
333 /* get s = (Yp - Yq)/(Xp-Xq) mod p */ |
|
334 if ((err = mp_sub(&P->x, &Q->x, &tmp)) != MP_OKAY) { goto error; } /* tmp = Px - Qx mod modulus */ |
|
335 if (mp_cmp_d(&tmp, 0) == MP_LT) { /* if tmp<0 add modulus */ |
|
336 if ((err = mp_add(&tmp, modulus, &tmp)) != MP_OKAY) { goto error; } |
|
337 } |
|
338 if ((err = mp_invmod(&tmp, modulus, &tmp)) != MP_OKAY) { goto error; } /* tmp = 1/tmp mod modulus */ |
|
339 if ((err = mp_sub(&P->y, &Q->y, &s)) != MP_OKAY) { goto error; } /* s = Py - Qy mod modulus */ |
|
340 if (mp_cmp_d(&s, 0) == MP_LT) { /* if s<0 add modulus */ |
|
341 if ((err = mp_add(&s, modulus, &s)) != MP_OKAY) { goto error; } |
|
342 } |
|
343 if ((err = mp_mul(&s, &tmp, &s)) != MP_OKAY) { goto error; } /* s = s * tmp mod modulus */ |
|
344 if ((err = mp_reduce(&s, modulus, mu)) != MP_OKAY) { goto error; } |
|
345 |
|
346 /* Xr = s^2 - Xp - Xq */ |
|
347 if ((err = mp_sqr(&s, &tmp)) != MP_OKAY) { goto error; } /* tmp = s^2 mod modulus */ |
|
348 if ((err = mp_reduce(&tmp, modulus, mu)) != MP_OKAY) { goto error; } |
|
349 if ((err = mp_sub(&tmp, &P->x, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp - Px */ |
|
350 if ((err = mp_sub(&tmp, &Q->x, &tmpx)) != MP_OKAY) { goto error; } /* tmpx = tmp - Qx */ |
|
351 |
|
352 /* Yr = -Yp + s(Xp - Xr) */ |
|
353 if ((err = mp_sub(&P->x, &tmpx, &tmp)) != MP_OKAY) { goto error; } /* tmp = Px - tmpx */ |
|
354 if ((err = mp_mul(&tmp, &s, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp * s */ |
|
355 if ((err = mp_submod(&tmp, &P->y, modulus, &R->y)) != MP_OKAY) { goto error; } /* Ry = tmp - Py mod modulus */ |
|
356 if ((err = mp_mod(&tmpx, modulus, &R->x)) != MP_OKAY) { goto error; } /* Rx = tmpx mod modulus */ |
|
357 |
|
358 err = CRYPT_OK; |
|
359 goto done; |
|
360 error: |
|
361 err = mpi_to_ltc_error(err); |
|
362 done: |
|
363 mp_clear_multi(&s, &tmpx, &tmp, NULL); |
|
364 return err; |
|
365 } |
|
366 |
|
367 /* size of sliding window, don't change this! */ |
|
368 #define WINSIZE 4 |
|
369 |
|
370 /* perform R = kG where k == integer and G == ecc_point */ |
|
371 static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus) |
|
372 { |
|
373 ecc_point *tG, *M[8]; |
143
|
374 int i, j, err; |
|
375 mp_int mu; |
|
376 mp_digit buf; |
|
377 int first, bitbuf, bitcpy, bitcnt, mode, digidx; |
3
|
378 |
|
379 /* init barrett reduction */ |
|
380 if ((err = mp_init(&mu)) != MP_OKAY) { |
|
381 return mpi_to_ltc_error(err); |
|
382 } |
|
383 if ((err = mp_reduce_setup(&mu, modulus)) != MP_OKAY) { |
|
384 mp_clear(&mu); |
|
385 return mpi_to_ltc_error(err); |
|
386 } |
|
387 |
|
388 /* alloc ram for window temps */ |
|
389 for (i = 0; i < 8; i++) { |
|
390 M[i] = new_point(); |
|
391 if (M[i] == NULL) { |
|
392 for (j = 0; j < i; j++) { |
|
393 del_point(M[j]); |
|
394 } |
|
395 mp_clear(&mu); |
|
396 return CRYPT_MEM; |
|
397 } |
|
398 } |
|
399 |
|
400 /* make a copy of G incase R==G */ |
|
401 tG = new_point(); |
|
402 if (tG == NULL) { err = CRYPT_MEM; goto done; } |
|
403 |
|
404 /* tG = G */ |
|
405 if ((err = mp_copy(&G->x, &tG->x)) != MP_OKAY) { goto error; } |
|
406 if ((err = mp_copy(&G->y, &tG->y)) != MP_OKAY) { goto error; } |
|
407 |
|
408 /* calc the M tab, which holds kG for k==8..15 */ |
|
409 /* M[0] == 8G */ |
|
410 if ((err = dbl_point(G, M[0], modulus, &mu)) != CRYPT_OK) { goto done; } |
|
411 if ((err = dbl_point(M[0], M[0], modulus, &mu)) != CRYPT_OK) { goto done; } |
|
412 if ((err = dbl_point(M[0], M[0], modulus, &mu)) != CRYPT_OK) { goto done; } |
|
413 |
|
414 /* now find (8+k)G for k=1..7 */ |
|
415 for (j = 9; j < 16; j++) { |
|
416 if ((err = add_point(M[j-9], G, M[j-8], modulus, &mu)) != CRYPT_OK) { goto done; } |
|
417 } |
|
418 |
|
419 /* setup sliding window */ |
|
420 mode = 0; |
|
421 bitcnt = 1; |
|
422 buf = 0; |
|
423 digidx = k->used - 1; |
|
424 bitcpy = bitbuf = 0; |
|
425 first = 1; |
|
426 |
|
427 /* perform ops */ |
|
428 for (;;) { |
|
429 /* grab next digit as required */ |
|
430 if (--bitcnt == 0) { |
|
431 if (digidx == -1) { |
|
432 break; |
|
433 } |
|
434 buf = k->dp[digidx--]; |
|
435 bitcnt = (int) DIGIT_BIT; |
|
436 } |
|
437 |
|
438 /* grab the next msb from the multiplicand */ |
|
439 i = (buf >> (DIGIT_BIT - 1)) & 1; |
|
440 buf <<= 1; |
|
441 |
|
442 /* skip leading zero bits */ |
|
443 if (mode == 0 && i == 0) { |
|
444 continue; |
|
445 } |
|
446 |
|
447 /* if the bit is zero and mode == 1 then we double */ |
|
448 if (mode == 1 && i == 0) { |
|
449 if ((err = dbl_point(R, R, modulus, &mu)) != CRYPT_OK) { goto done; } |
|
450 continue; |
|
451 } |
|
452 |
|
453 /* else we add it to the window */ |
|
454 bitbuf |= (i << (WINSIZE - ++bitcpy)); |
|
455 mode = 2; |
|
456 |
|
457 if (bitcpy == WINSIZE) { |
|
458 /* if this is the first window we do a simple copy */ |
|
459 if (first == 1) { |
|
460 /* R = kG [k = first window] */ |
|
461 if ((err = mp_copy(&M[bitbuf-8]->x, &R->x)) != MP_OKAY) { goto error; } |
|
462 if ((err = mp_copy(&M[bitbuf-8]->y, &R->y)) != MP_OKAY) { goto error; } |
|
463 first = 0; |
|
464 } else { |
|
465 /* normal window */ |
|
466 /* ok window is filled so double as required and add */ |
|
467 /* double first */ |
|
468 for (j = 0; j < WINSIZE; j++) { |
|
469 if ((err = dbl_point(R, R, modulus, &mu)) != CRYPT_OK) { goto done; } |
|
470 } |
|
471 |
|
472 /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */ |
|
473 if ((err = add_point(R, M[bitbuf-8], R, modulus, &mu)) != CRYPT_OK) { goto done; } |
|
474 } |
|
475 /* empty window and reset */ |
|
476 bitcpy = bitbuf = 0; |
|
477 mode = 1; |
|
478 } |
|
479 } |
|
480 |
|
481 /* if bits remain then double/add */ |
|
482 if (mode == 2 && bitcpy > 0) { |
|
483 /* double then add */ |
|
484 for (j = 0; j < bitcpy; j++) { |
|
485 /* only double if we have had at least one add first */ |
|
486 if (first == 0) { |
|
487 if ((err = dbl_point(R, R, modulus, &mu)) != CRYPT_OK) { goto done; } |
|
488 } |
|
489 |
|
490 bitbuf <<= 1; |
|
491 if ((bitbuf & (1 << WINSIZE)) != 0) { |
|
492 if (first == 1){ |
|
493 /* first add, so copy */ |
|
494 if ((err = mp_copy(&tG->x, &R->x)) != MP_OKAY) { goto error; } |
|
495 if ((err = mp_copy(&tG->y, &R->y)) != MP_OKAY) { goto error; } |
|
496 first = 0; |
|
497 } else { |
|
498 /* then add */ |
|
499 if ((err = add_point(R, tG, R, modulus, &mu)) != CRYPT_OK) { goto done; } |
|
500 } |
|
501 } |
|
502 } |
|
503 } |
|
504 err = CRYPT_OK; |
|
505 goto done; |
|
506 error: |
|
507 err = mpi_to_ltc_error(err); |
|
508 done: |
|
509 del_point(tG); |
|
510 for (i = 0; i < 8; i++) { |
|
511 del_point(M[i]); |
|
512 } |
|
513 mp_clear(&mu); |
|
514 return err; |
|
515 } |
|
516 |
|
517 #undef WINSIZE |
|
518 |
|
519 int ecc_test(void) |
|
520 { |
|
521 mp_int modulus, order; |
|
522 ecc_point *G, *GG; |
|
523 int i, err, primality; |
|
524 |
|
525 if ((err = mp_init_multi(&modulus, &order, NULL)) != MP_OKAY) { |
|
526 return mpi_to_ltc_error(err); |
|
527 } |
|
528 |
|
529 G = new_point(); |
|
530 GG = new_point(); |
|
531 if (G == NULL || GG == NULL) { |
|
532 mp_clear_multi(&modulus, &order, NULL); |
|
533 del_point(G); |
|
534 del_point(GG); |
|
535 return CRYPT_MEM; |
|
536 } |
|
537 |
|
538 for (i = 0; sets[i].size; i++) { |
|
539 #if 0 |
|
540 printf("Testing %d\n", sets[i].size); |
|
541 #endif |
|
542 if ((err = mp_read_radix(&modulus, (char *)sets[i].prime, 64)) != MP_OKAY) { goto error; } |
|
543 if ((err = mp_read_radix(&order, (char *)sets[i].order, 64)) != MP_OKAY) { goto error; } |
|
544 |
|
545 /* is prime actually prime? */ |
|
546 if ((err = is_prime(&modulus, &primality)) != CRYPT_OK) { goto done; } |
|
547 if (primality == 0) { |
|
548 err = CRYPT_FAIL_TESTVECTOR; |
|
549 goto done; |
|
550 } |
|
551 |
|
552 /* is order prime ? */ |
|
553 if ((err = is_prime(&order, &primality)) != CRYPT_OK) { goto done; } |
|
554 if (primality == 0) { |
|
555 err = CRYPT_FAIL_TESTVECTOR; |
|
556 goto done; |
|
557 } |
|
558 |
|
559 if ((err = mp_read_radix(&G->x, (char *)sets[i].Gx, 64)) != MP_OKAY) { goto error; } |
|
560 if ((err = mp_read_radix(&G->y, (char *)sets[i].Gy, 64)) != MP_OKAY) { goto error; } |
|
561 |
|
562 /* then we should have G == (order + 1)G */ |
|
563 if ((err = mp_add_d(&order, 1, &order)) != MP_OKAY) { goto error; } |
|
564 if ((err = ecc_mulmod(&order, G, GG, &modulus)) != CRYPT_OK) { goto done; } |
|
565 if (mp_cmp(&G->x, &GG->x) != 0 || mp_cmp(&G->y, &GG->y) != 0) { |
|
566 err = CRYPT_FAIL_TESTVECTOR; |
|
567 goto done; |
|
568 } |
|
569 } |
|
570 err = CRYPT_OK; |
|
571 goto done; |
|
572 error: |
|
573 err = mpi_to_ltc_error(err); |
|
574 done: |
|
575 del_point(GG); |
|
576 del_point(G); |
|
577 mp_clear_multi(&order, &modulus, NULL); |
|
578 return err; |
|
579 } |
|
580 |
|
581 void ecc_sizes(int *low, int *high) |
|
582 { |
|
583 int i; |
|
584 _ARGCHK(low != NULL); |
|
585 _ARGCHK(high != NULL); |
|
586 |
|
587 *low = INT_MAX; |
|
588 *high = 0; |
|
589 for (i = 0; sets[i].size != 0; i++) { |
|
590 if (sets[i].size < *low) { |
|
591 *low = sets[i].size; |
|
592 } |
|
593 if (sets[i].size > *high) { |
|
594 *high = sets[i].size; |
|
595 } |
|
596 } |
|
597 } |
|
598 |
|
599 int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key) |
|
600 { |
143
|
601 int x, err; |
|
602 ecc_point *base; |
|
603 mp_int prime; |
|
604 unsigned char *buf; |
3
|
605 |
|
606 _ARGCHK(key != NULL); |
|
607 |
|
608 /* good prng? */ |
|
609 if ((err = prng_is_valid(wprng)) != CRYPT_OK) { |
|
610 return err; |
|
611 } |
|
612 |
|
613 /* find key size */ |
|
614 for (x = 0; (keysize > sets[x].size) && (sets[x].size != 0); x++); |
|
615 keysize = sets[x].size; |
143
|
616 _ARGCHK(keysize <= ECC_MAXSIZE); |
3
|
617 |
|
618 if (sets[x].size == 0) { |
|
619 return CRYPT_INVALID_KEYSIZE; |
|
620 } |
|
621 key->idx = x; |
|
622 |
143
|
623 /* allocate ram */ |
|
624 base = NULL; |
|
625 buf = XMALLOC(ECC_MAXSIZE); |
|
626 if (buf == NULL) { |
|
627 return CRYPT_MEM; |
|
628 } |
|
629 |
3
|
630 /* make up random string */ |
|
631 if (prng_descriptor[wprng].read(buf, (unsigned long)keysize, prng) != (unsigned long)keysize) { |
143
|
632 err = CRYPT_ERROR_READPRNG; |
|
633 goto __ERR2; |
3
|
634 } |
|
635 |
|
636 /* setup the key variables */ |
|
637 if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->k, &prime, NULL)) != MP_OKAY) { |
143
|
638 err = mpi_to_ltc_error(err); |
|
639 goto __ERR; |
3
|
640 } |
|
641 base = new_point(); |
|
642 if (base == NULL) { |
|
643 mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, &prime, NULL); |
143
|
644 err = CRYPT_MEM; |
|
645 goto __ERR; |
3
|
646 } |
|
647 |
|
648 /* read in the specs for this key */ |
|
649 if ((err = mp_read_radix(&prime, (char *)sets[key->idx].prime, 64)) != MP_OKAY) { goto error; } |
|
650 if ((err = mp_read_radix(&base->x, (char *)sets[key->idx].Gx, 64)) != MP_OKAY) { goto error; } |
|
651 if ((err = mp_read_radix(&base->y, (char *)sets[key->idx].Gy, 64)) != MP_OKAY) { goto error; } |
|
652 if ((err = mp_read_unsigned_bin(&key->k, (unsigned char *)buf, keysize)) != MP_OKAY) { goto error; } |
|
653 |
|
654 /* make the public key */ |
143
|
655 if ((err = ecc_mulmod(&key->k, base, &key->pubkey, &prime)) != CRYPT_OK) { goto __ERR; } |
3
|
656 key->type = PK_PRIVATE; |
|
657 |
|
658 /* shrink key */ |
|
659 if ((err = mp_shrink(&key->k)) != MP_OKAY) { goto error; } |
|
660 if ((err = mp_shrink(&key->pubkey.x)) != MP_OKAY) { goto error; } |
|
661 if ((err = mp_shrink(&key->pubkey.y)) != MP_OKAY) { goto error; } |
|
662 |
|
663 /* free up ram */ |
|
664 err = CRYPT_OK; |
143
|
665 goto __ERR; |
3
|
666 error: |
|
667 err = mpi_to_ltc_error(err); |
143
|
668 __ERR: |
3
|
669 del_point(base); |
|
670 mp_clear(&prime); |
143
|
671 __ERR2: |
3
|
672 #ifdef CLEAN_STACK |
143
|
673 zeromem(buf, ECC_MAXSIZE); |
3
|
674 #endif |
143
|
675 |
|
676 XFREE(buf); |
|
677 |
3
|
678 return err; |
|
679 } |
|
680 |
|
681 void ecc_free(ecc_key *key) |
|
682 { |
|
683 _ARGCHK(key != NULL); |
|
684 mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL); |
|
685 } |
|
686 |
|
687 static int compress_y_point(ecc_point *pt, int idx, int *result) |
|
688 { |
|
689 mp_int tmp, tmp2, p; |
|
690 int err; |
|
691 |
|
692 _ARGCHK(pt != NULL); |
|
693 _ARGCHK(result != NULL); |
|
694 |
|
695 if ((err = mp_init_multi(&tmp, &tmp2, &p, NULL)) != MP_OKAY) { |
|
696 return mpi_to_ltc_error(err); |
|
697 } |
|
698 |
|
699 /* get x^3 - 3x + b */ |
|
700 if ((err = mp_read_radix(&p, (char *)sets[idx].B, 64)) != MP_OKAY) { goto error; } /* p = B */ |
|
701 if ((err = mp_expt_d(&pt->x, 3, &tmp)) != MP_OKAY) { goto error; } /* tmp = pX^3 */ |
|
702 if ((err = mp_mul_d(&pt->x, 3, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = 3*pX^3 */ |
|
703 if ((err = mp_sub(&tmp, &tmp2, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp - tmp2 */ |
|
704 if ((err = mp_add(&tmp, &p, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp + p */ |
|
705 if ((err = mp_read_radix(&p, (char *)sets[idx].prime, 64)) != MP_OKAY) { goto error; } /* p = prime */ |
|
706 if ((err = mp_mod(&tmp, &p, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp mod p */ |
|
707 |
|
708 /* now find square root */ |
|
709 if ((err = mp_add_d(&p, 1, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = p + 1 */ |
|
710 if ((err = mp_div_2d(&tmp2, 2, &tmp2, NULL)) != MP_OKAY) { goto error; } /* tmp2 = (p+1)/4 */ |
|
711 if ((err = mp_exptmod(&tmp, &tmp2, &p, &tmp)) != MP_OKAY) { goto error; } /* tmp = (x^3 - 3x + b)^((p+1)/4) mod p */ |
|
712 |
|
713 /* if tmp equals the y point give a 0, otherwise 1 */ |
|
714 if (mp_cmp(&tmp, &pt->y) == 0) { |
|
715 *result = 0; |
|
716 } else { |
|
717 *result = 1; |
|
718 } |
|
719 |
|
720 err = CRYPT_OK; |
|
721 goto done; |
|
722 error: |
|
723 err = mpi_to_ltc_error(err); |
|
724 done: |
|
725 mp_clear_multi(&p, &tmp, &tmp2, NULL); |
|
726 return err; |
|
727 } |
|
728 |
|
729 static int expand_y_point(ecc_point *pt, int idx, int result) |
|
730 { |
|
731 mp_int tmp, tmp2, p; |
|
732 int err; |
|
733 |
|
734 _ARGCHK(pt != NULL); |
|
735 |
|
736 if ((err = mp_init_multi(&tmp, &tmp2, &p, NULL)) != MP_OKAY) { |
|
737 return CRYPT_MEM; |
|
738 } |
|
739 |
|
740 /* get x^3 - 3x + b */ |
|
741 if ((err = mp_read_radix(&p, (char *)sets[idx].B, 64)) != MP_OKAY) { goto error; } /* p = B */ |
|
742 if ((err = mp_expt_d(&pt->x, 3, &tmp)) != MP_OKAY) { goto error; } /* tmp = pX^3 */ |
|
743 if ((err = mp_mul_d(&pt->x, 3, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = 3*pX^3 */ |
|
744 if ((err = mp_sub(&tmp, &tmp2, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp - tmp2 */ |
|
745 if ((err = mp_add(&tmp, &p, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp + p */ |
|
746 if ((err = mp_read_radix(&p, (char *)sets[idx].prime, 64)) != MP_OKAY) { goto error; } /* p = prime */ |
|
747 if ((err = mp_mod(&tmp, &p, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp mod p */ |
|
748 |
|
749 /* now find square root */ |
|
750 if ((err = mp_add_d(&p, 1, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = p + 1 */ |
|
751 if ((err = mp_div_2d(&tmp2, 2, &tmp2, NULL)) != MP_OKAY) { goto error; } /* tmp2 = (p+1)/4 */ |
|
752 if ((err = mp_exptmod(&tmp, &tmp2, &p, &tmp)) != MP_OKAY) { goto error; } /* tmp = (x^3 - 3x + b)^((p+1)/4) mod p */ |
|
753 |
|
754 /* if result==0, then y==tmp, otherwise y==p-tmp */ |
|
755 if (result == 0) { |
|
756 if ((err = mp_copy(&tmp, &pt->y) != MP_OKAY)) { goto error; } |
|
757 } else { |
|
758 if ((err = mp_sub(&p, &tmp, &pt->y) != MP_OKAY)) { goto error; } |
|
759 } |
|
760 |
|
761 err = CRYPT_OK; |
|
762 goto done; |
|
763 error: |
|
764 err = mpi_to_ltc_error(err); |
|
765 done: |
|
766 mp_clear_multi(&p, &tmp, &tmp2, NULL); |
|
767 return err; |
|
768 } |
|
769 |
|
770 int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key) |
|
771 { |
|
772 unsigned long y, z; |
|
773 int cp, err; |
|
774 |
|
775 _ARGCHK(out != NULL); |
|
776 _ARGCHK(outlen != NULL); |
|
777 _ARGCHK(key != NULL); |
|
778 |
|
779 /* can we store the static header? */ |
|
780 if (*outlen < (PACKET_SIZE + 3)) { |
|
781 return CRYPT_BUFFER_OVERFLOW; |
|
782 } |
|
783 |
|
784 /* type valid? */ |
|
785 if (key->type != PK_PRIVATE && type == PK_PRIVATE) { |
|
786 return CRYPT_PK_TYPE_MISMATCH; |
|
787 } |
|
788 |
|
789 /* output type and magic byte */ |
|
790 y = PACKET_SIZE; |
|
791 out[y++] = (unsigned char)type; |
|
792 out[y++] = (unsigned char)sets[key->idx].size; |
|
793 |
|
794 /* output x coordinate */ |
|
795 OUTPUT_BIGNUM(&(key->pubkey.x), out, y, z); |
|
796 |
|
797 /* compress y and output it */ |
|
798 if ((err = compress_y_point(&key->pubkey, key->idx, &cp)) != CRYPT_OK) { |
|
799 return err; |
|
800 } |
|
801 out[y++] = (unsigned char)cp; |
|
802 |
|
803 if (type == PK_PRIVATE) { |
|
804 OUTPUT_BIGNUM(&key->k, out, y, z); |
|
805 } |
|
806 |
|
807 /* store header */ |
|
808 packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_KEY); |
|
809 *outlen = y; |
|
810 |
|
811 return CRYPT_OK; |
|
812 } |
|
813 |
|
814 int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key) |
|
815 { |
|
816 unsigned long x, y, s; |
|
817 int err; |
|
818 |
|
819 _ARGCHK(in != NULL); |
|
820 _ARGCHK(key != NULL); |
|
821 |
|
822 /* check length */ |
|
823 if ((3+PACKET_SIZE) > inlen) { |
|
824 return CRYPT_INVALID_PACKET; |
|
825 } |
|
826 |
|
827 /* check type */ |
|
828 if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_KEY)) != CRYPT_OK) { |
|
829 return err; |
|
830 } |
|
831 |
|
832 /* init key */ |
|
833 if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL) != MP_OKAY) { |
|
834 return CRYPT_MEM; |
|
835 } |
|
836 |
|
837 y = PACKET_SIZE; |
|
838 key->type = (int)in[y++]; |
|
839 s = (unsigned long)in[y++]; |
|
840 |
|
841 for (x = 0; (s > (unsigned long)sets[x].size) && (sets[x].size != 0); x++); |
|
842 if (sets[x].size == 0) { |
|
843 err = CRYPT_INVALID_KEYSIZE; |
|
844 goto error; |
|
845 } |
|
846 key->idx = (int)x; |
|
847 |
|
848 /* type check both values */ |
|
849 if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE)) { |
|
850 err = CRYPT_INVALID_PACKET; |
|
851 goto error; |
|
852 } |
|
853 |
|
854 /* is the key idx valid? */ |
|
855 if (is_valid_idx(key->idx) != 1) { |
|
856 err = CRYPT_INVALID_PACKET; |
|
857 goto error; |
|
858 } |
|
859 |
|
860 /* load x coordinate */ |
|
861 INPUT_BIGNUM(&key->pubkey.x, in, x, y, inlen); |
|
862 |
|
863 /* load y */ |
|
864 x = (unsigned long)in[y++]; |
|
865 if ((err = expand_y_point(&key->pubkey, key->idx, (int)x)) != CRYPT_OK) { |
|
866 goto error; |
|
867 } |
|
868 |
|
869 if (key->type == PK_PRIVATE) { |
|
870 /* load private key */ |
|
871 INPUT_BIGNUM(&key->k, in, x, y, inlen); |
|
872 } |
|
873 |
|
874 /* eliminate private key if public */ |
|
875 if (key->type == PK_PUBLIC) { |
|
876 mp_clear(&key->k); |
|
877 } |
|
878 |
|
879 return CRYPT_OK; |
|
880 error: |
|
881 mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL); |
|
882 return err; |
|
883 } |
|
884 |
|
885 int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, |
|
886 unsigned char *out, unsigned long *outlen) |
|
887 { |
|
888 unsigned long x, y; |
|
889 ecc_point *result; |
|
890 mp_int prime; |
|
891 int err; |
|
892 |
|
893 _ARGCHK(private_key != NULL); |
|
894 _ARGCHK(public_key != NULL); |
|
895 _ARGCHK(out != NULL); |
|
896 _ARGCHK(outlen != NULL); |
|
897 |
|
898 /* type valid? */ |
|
899 if (private_key->type != PK_PRIVATE) { |
|
900 return CRYPT_PK_NOT_PRIVATE; |
|
901 } |
|
902 |
|
903 if (private_key->idx != public_key->idx) { |
|
904 return CRYPT_PK_TYPE_MISMATCH; |
|
905 } |
|
906 |
|
907 /* make new point */ |
|
908 result = new_point(); |
|
909 if (result == NULL) { |
|
910 return CRYPT_MEM; |
|
911 } |
|
912 |
|
913 if ((err = mp_init(&prime)) != MP_OKAY) { |
|
914 del_point(result); |
|
915 return mpi_to_ltc_error(err); |
|
916 } |
|
917 |
|
918 if ((err = mp_read_radix(&prime, (char *)sets[private_key->idx].prime, 64)) != MP_OKAY) { goto error; } |
|
919 if ((err = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime)) != CRYPT_OK) { goto done1; } |
|
920 |
|
921 x = (unsigned long)mp_unsigned_bin_size(&result->x); |
|
922 y = (unsigned long)mp_unsigned_bin_size(&result->y); |
|
923 |
|
924 if (*outlen < (x+y)) { |
|
925 err = CRYPT_BUFFER_OVERFLOW; |
|
926 goto done1; |
|
927 } |
|
928 *outlen = x+y; |
|
929 if ((err = mp_to_unsigned_bin(&result->x, out)) != MP_OKAY) { goto error; } |
|
930 if ((err = mp_to_unsigned_bin(&result->y, out+x)) != MP_OKAY) { goto error; } |
|
931 |
|
932 err = CRYPT_OK; |
|
933 goto done1; |
|
934 error: |
|
935 err = mpi_to_ltc_error(err); |
|
936 done1: |
|
937 mp_clear(&prime); |
|
938 del_point(result); |
|
939 return err; |
|
940 } |
|
941 |
|
942 int ecc_get_size(ecc_key *key) |
|
943 { |
|
944 _ARGCHK(key != NULL); |
|
945 if (is_valid_idx(key->idx)) |
|
946 return sets[key->idx].size; |
|
947 else |
|
948 return INT_MAX; /* large value known to cause it to fail when passed to ecc_make_key() */ |
|
949 } |
|
950 |
|
951 #include "ecc_sys.c" |
|
952 |
|
953 #endif |
|
954 |
|
955 |