Annotation of embedaddon/strongswan/src/libstrongswan/plugins/newhope/newhope_ke.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2016 Andreas Steffen
3: * HSR Hochschule fuer Technik Rapperswil
4: *
5: * Based on public domain code by Erdem Alkim, Léo Ducas, Thomas Pöppelmann,
6: * and Peter Schwabe.
7: *
8: * This program is free software; you can redistribute it and/or modify it
9: * under the terms of the GNU General Public License as published by the
10: * Free Software Foundation; either version 2 of the License, or (at your
11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12: *
13: * This program is distributed in the hope that it will be useful, but
14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16: * for more details.
17: */
18:
19: #include "newhope_ke.h"
20: #include "newhope_noise.h"
21: #include "newhope_reconciliation.h"
22:
23: #include <ntt_fft.h>
24: #include <ntt_fft_reduce.h>
25: #include <crypto/diffie_hellman.h>
26: #include <utils/debug.h>
27:
28: static const int seed_len = 32; /* 256 bits */
29: static const int poly_len = 1792; /* size of 1024 packed 14-bit coefficients */
30: static const int rec_len = 256; /* size of 1024 packed 2-bit coefficients */
31:
32: typedef struct private_newhope_ke_t private_newhope_ke_t;
33:
34: /**
35: * Private data of an newhope_ke_t object.
36: */
37: struct private_newhope_ke_t {
38:
39: /**
40: * Public newhope_ke_t interface.
41: */
42: newhope_ke_t public;
43:
44: /**
45: * FFT parameter set
46: */
47: const ntt_fft_params_t *params;
48:
49: /**
50: * Secret noise polynomial s
51: */
52: uint32_t *s;
53:
54: /**
55: * Output polynomial u = a * NTT(s') + NTT(e')
56: */
57: uint32_t *u;
58:
59: /**
60: * Error reconciliation help bits
61: */
62: uint8_t *r;
63:
64: /**
65: * Shared secret
66: */
67: chunk_t shared_secret;
68:
69: };
70:
71: /**
72: * Derive 14-bit coefficients of polynomial a from 256 bit random seed
73: * using the SHAKE128 extended output function
74: */
75: static uint32_t* derive_a_poly(private_newhope_ke_t *this, chunk_t seed)
76: {
77: uint32_t *a;
78: uint8_t x[2];
79: int i = 0;
80: xof_t *xof;
81:
82: xof = lib->crypto->create_xof(lib->crypto, XOF_SHAKE_128);
83: if (!xof)
84: {
85: DBG1(DBG_LIB, "could not instantiate SHAKE128 XOF");
86: return NULL;
87: }
88:
89: if (!xof->set_seed(xof, seed))
90: {
91: DBG1(DBG_LIB, "could not set seed of SHAKE128 XOF");
92: xof->destroy(xof);
93: return NULL;
94: }
95:
96: /* allocate dynamic memory for polynomial a */
97: a = (uint32_t*)malloc(this->params->n * sizeof(uint32_t));
98:
99: while (i < this->params->n)
100: {
101: if (!xof->get_bytes(xof, sizeof(x), x))
102: {
103: DBG1(DBG_LIB, "could not get bytes from SHAKE128 XOF");
104: xof->destroy(xof);
105: free(a);
106: return NULL;
107: }
108:
109: /*
110: * Treat x as a 16 bit unsigned little endian integer
111: * and truncate to 14 bits
112: */
113: a[i] = uletoh16(x) & 0x3fff;
114:
115: if (a[i] < this->params->q)
116: {
117: i++;
118: }
119: }
120: xof->destroy(xof);
121:
122: return a;
123: }
124:
125: /**
126: * Pack four 14-bit coefficients into seven consecutive bytes
127: *
128: * 1 2 3
129: * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
130: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
131: * |L 0 0 0 0 0 0 0|L 1 H 0 0 0 0 0|M 1 1 1 1 1 1 1|L 2 2 2 H 1 1 1|
132: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
133: * |M 2 2 2 2 2 2 2|L 3 3 3 3 3 H 2|H 3 3 3 3 3 3 3|L 0 0 0 0 0 0 0|
134: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
135: */
136: static void pack_poly(private_newhope_ke_t *this, uint8_t *x, uint32_t *p)
137: {
138: int i;
139:
140: for (i = 0; i < this->params->n; i += 4)
141: {
142: *x++ = (p[i] & 0xff );
143: *x++ = (p[i] >> 8) | (p[i+1] << 6);
144: *x++ = (p[i+1] >> 2);
145: *x++ = (p[i+1] >> 10) | (p[i+2] << 4);
146: *x++ = (p[i+2] >> 4);
147: *x++ = (p[i+2] >> 12) | (p[i+3] << 2);
148: *x++ = (p[i+3] >> 6);
149: }
150: }
151:
152: /**
153: * Unpack seven consecutive bytes into four 14-bit coefficients
154: */
155: static uint32_t* unpack_poly(private_newhope_ke_t * this, uint8_t *x)
156: {
157: uint32_t *p;
158: int i;
159:
160: p = (uint32_t*)malloc(this->params->n * sizeof(uint32_t));
161:
162: for (i = 0; i < this->params->n; i += 4)
163: {
164: p[i] = x[0] | (((uint32_t)x[1] & 0x3f) << 8);
165: p[i+1] = (x[1] >> 6) | (((uint32_t)x[2]) << 2)
166: | (((uint32_t)x[3] & 0x0f) << 10);
167: p[i+2] = (x[3] >> 4) | (((uint32_t)x[4]) << 4)
168: | (((uint32_t)x[5] & 0x03) << 12);
169: p[i+3] = (x[5] >> 2) | (((uint32_t)x[6]) << 6);
170: x += 7;
171: }
172: for (i = 0; i < this->params->n; i++)
173: {
174: if (p[i] >= this->params->q)
175: {
176: DBG1(DBG_LIB, "polynomial coefficient must be smaller than %u",
177: this->params->q);
178: free(p);
179: return NULL;
180: }
181: }
182: return p;
183: }
184:
185: /**
186: * Multiply and add polynomials in the frequency domain
187: */
188: static uint32_t* multiply_add_poly(private_newhope_ke_t *this,
189: uint32_t *a, uint32_t *e)
190: {
191: ntt_fft_t *fft;
192: uint32_t *b, t;
193: int i;
194:
195: /* transform s and h to frequency domain */
196: fft = ntt_fft_create(this->params);
197: fft->transform(fft, this->s, this->s, FALSE);
198: fft->transform(fft, e, e, FALSE);
199: fft->destroy(fft);
200:
201: b = (uint32_t*)malloc(this->params->n * sizeof(uint32_t));
202:
203: /* compute b = a * s + e in the frequency domain */
204: for (i = 0; i < this->params->n; i++)
205: {
206: /* convert a[i] to Montgomery domain */
207: t = ntt_fft_mreduce(a[i] * this->params->r2, this->params);
208:
209: /* compute b[i] = a[i] * s[i] + e[i] in Montgomery domain */
210: t = ntt_fft_mreduce(t * this->s[i], this->params) + e[i];
211:
212: /* exit Montgomery domain before transmitting polynomial b */
213: b[i] = ntt_fft_mreduce(t, this->params);
214: }
215: memwipe(e, this->params->n * sizeof(uint32_t));
216:
217: return b;
218: }
219:
220: /**
221: * Multiply polynomials in the frequency domain and return to time domain
222: */
223: static uint32_t* multiply_ntt_inv_poly(private_newhope_ke_t *this, uint32_t *b)
224: {
225: ntt_fft_t *fft;
226: uint32_t *v, t;
227: int i;
228:
229: v = (uint32_t*)malloc(this->params->n * sizeof(uint32_t));
230:
231: for (i = 0; i < this->params->n; i++)
232: {
233: /* convert b[i] to Montgomery domain */
234: t = ntt_fft_mreduce(b[i] * this->params->r2, this->params);
235:
236: /* compute v[i] = b[i] * s[i] in Montgomery domain */
237: v[i] = ntt_fft_mreduce(t * this->s[i], this->params);
238: }
239:
240: /* transform v back to time domain */
241: fft = ntt_fft_create(this->params);
242: fft->transform(fft, v, v, TRUE);
243: fft->destroy(fft);
244:
245: return v;
246: }
247:
248: /**
249: * Pack four 2-bit coefficients into one byte
250: */
251: static void pack_rec(private_newhope_ke_t *this, uint8_t *x, uint8_t *r)
252: {
253: int i;
254:
255: for (i = 0; i < this->params->n; i += 4)
256: {
257: *x++ = r[i] | r[i+1] << 2 | r[i+2] << 4 | r[i+3] << 6;
258: }
259: }
260:
261: static uint8_t* unpack_rec(private_newhope_ke_t *this, uint8_t *x)
262: {
263: uint8_t *r;
264: int i;
265:
266: r = (uint8_t*)malloc(this->params->n);
267:
268: for (i = 0; i < this->params->n; i += 4)
269: {
270: r[i] = (*x) & 0x03;
271: r[i+1] = (*x >> 2) & 0x03;
272: r[i+2] = (*x >> 4) & 0x03;
273: r[i+3] = (*x >> 6) & 0x03;
274: x++;
275: }
276:
277: return r;
278: }
279:
280: METHOD(diffie_hellman_t, get_my_public_value, bool,
281: private_newhope_ke_t *this, chunk_t *value)
282: {
283: uint16_t n, q;
284: int i;
285:
286: /* Define some often-used constants */
287: n = this->params->n;
288: q = this->params->q;
289:
290: /* are we the initiator? */
291: if (this->u == NULL)
292: {
293: rng_t *rng;
294: uint32_t *a = NULL, *b = NULL, *e = NULL;
295: uint8_t noise_seed_buf[seed_len];
296: chunk_t noise_seed = { noise_seed_buf, seed_len};
297: chunk_t a_seed;
298: newhope_noise_t *noise = NULL;
299: bool success = FALSE;
300:
301: /* allocate space for public output value */
302: *value = chunk_alloc(poly_len + seed_len);
303: a_seed = chunk_create(value->ptr + poly_len, seed_len);
304:
305: /* create polynomial a from 256 bit random seed */
306: rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
307: if (!rng)
308: {
309: DBG1(DBG_LIB, "could not instantiate random source");
310: return FALSE;
311: }
312: if (!rng->get_bytes(rng, seed_len, a_seed.ptr))
313: {
314: DBG1(DBG_LIB, "could not generate seed for polynomial a");
315: goto end;
316: }
317:
318: a = derive_a_poly(this, a_seed);
319: if (a == NULL)
320: {
321: goto end;
322: }
323:
324: /* generate random seed for the derivation of noise polynomials */
325: if (!rng->get_bytes(rng, seed_len, noise_seed.ptr))
326: {
327: DBG1(DBG_LIB, "could not generate seed for noise polynomials");
328: goto end;
329: }
330:
331: /* create noise polynomial generator */
332: noise = newhope_noise_create(noise_seed);
333: if (!noise)
334: {
335: goto end;
336: }
337:
338: /* create noise polynomial s from seed with nonce = 0x00 */
339: this->s = noise->get_binomial_words(noise, 0x00, n, q);
340: if (this->s == NULL)
341: {
342: goto end;
343: }
344:
345: /* create noise polynomial e from seed with nonce = 0x01 */
346: e = noise->get_binomial_words(noise, 0x01, n, q);
347: if (e == NULL)
348: {
349: goto end;
350: }
351:
352: /* compute b = a * NTT(s) + NTT(e) */
353: b = multiply_add_poly(this, a, e);
354:
355: DBG3(DBG_LIB, " i a[i] b[i]");
356: for (i = 0; i < n; i++)
357: {
358: DBG3(DBG_LIB, "%4d %5u %5u", i, a[i], b[i]);
359: }
360:
361: /* pack coefficients of polynomial b */
362: pack_poly(this, value->ptr, b);
363: success = TRUE;
364:
365: end:
366: rng->destroy(rng);
367: DESTROY_IF(noise);
368: free(a);
369: free(b);
370: free(e);
371:
372: if (!success)
373: {
374: chunk_free(value);
375: }
376: return success;
377: }
378: else
379: {
380: DBG3(DBG_LIB, " i u[i] r[i]");
381: for (i = 0; i < n; i++)
382: {
383: DBG3(DBG_LIB, "%4d %5u %5u", i, this->u[i], this->r[i]);
384: }
385:
386: /* allocate space for public output value */
387: *value = chunk_alloc(poly_len + rec_len);
388:
389: /* pack coefficients of polynomial u */
390: pack_poly(this, value->ptr, this->u);
391:
392: /* pack coefficients of polynomial r */
393: pack_rec(this, value->ptr + poly_len, this->r);
394:
395: return TRUE;
396: }
397: }
398:
399: METHOD(diffie_hellman_t, get_shared_secret, bool,
400: private_newhope_ke_t *this, chunk_t *secret)
401: {
402: if (this->shared_secret.len == 0)
403: {
404: *secret = chunk_empty;
405: return FALSE;
406: }
407: *secret = chunk_clone(this->shared_secret);
408:
409: return TRUE;
410: }
411:
412: METHOD(diffie_hellman_t, set_other_public_value, bool,
413: private_newhope_ke_t *this, chunk_t value)
414: {
415: newhope_reconciliation_t * rec;
416: uint16_t n, q;
417: int i;
418:
419: /* Define some often-used constants */
420: n = this->params->n;
421: q = this->params->q;
422:
423: /* are we the responder? */
424: if (this->s == NULL)
425: {
426: uint32_t *a = NULL, *b = NULL, *e1 = NULL, *e2 = NULL, *v = NULL, t;
427: uint8_t *rbits = NULL;
428: uint8_t noise_seed_buf[seed_len];
429: chunk_t noise_seed = { noise_seed_buf, seed_len };
430: chunk_t a_seed;
431: newhope_noise_t *noise = NULL;
432: rng_t *rng = NULL;
433: bool success = FALSE;
434:
435: if (value.len != poly_len + seed_len)
436: {
437: DBG1(DBG_LIB, "received %N KE payload of incorrect size",
438: diffie_hellman_group_names, NH_128_BIT);
439: return FALSE;
440: }
441: a_seed = chunk_create(value.ptr + poly_len, seed_len);
442:
443: a = derive_a_poly(this, a_seed);
444: if (a == NULL)
445: {
446: return FALSE;
447: }
448:
449: b = unpack_poly(this, value.ptr);
450: if (b == NULL)
451: {
452: goto end;
453: }
454:
455: /* debug output of polynomials a and b */
456: DBG3(DBG_LIB, " i a[i] b[i]");
457: for (i = 0; i < n; i++)
458: {
459: DBG3(DBG_LIB, "%4d %5u %5u", i, a[i], b[i]);
460: }
461:
462: /* generate random seed for the derivation of noise polynomials */
463: rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
464: if (!rng)
465: {
466: DBG1(DBG_LIB, "could not instantiate random source");
467: goto end;
468: }
469: if (!rng->get_bytes(rng, seed_len, noise_seed.ptr))
470: {
471: DBG1(DBG_LIB, "could not generate seed for noise polynomials");
472: goto end;
473: }
474:
475: /* create noise polynomial generator */
476: noise = newhope_noise_create(noise_seed);
477: if (!noise)
478: {
479: goto end;
480: }
481:
482: /* create noise polynomial s' from seed with nonce = 0x00 */
483: this->s = noise->get_binomial_words(noise, 0x00, n, q);
484: if (this->s == NULL)
485: {
486: goto end;
487: }
488:
489: /* create noise polynomial e' from seed with nonce = 0x01 */
490: e1 = noise->get_binomial_words(noise, 0x01, n, q);
491: if (e1 == NULL)
492: {
493: goto end;
494: }
495:
496: /* create noise polynomial e'' from seed with nonce = 0x02 */
497: e2 = noise->get_binomial_words(noise, 0x02, n, q);
498: if (e2 == NULL)
499: {
500: goto end;
501: }
502:
503: /* compute u = a * NTT(s') + NTT(e') */
504: this->u = multiply_add_poly(this, a, e1);
505:
506: /* compute v = NTT_inv( b * NTT(s') ) */
507: v = multiply_ntt_inv_poly(this, b);
508:
509: /* compute v = v + e'' */
510: for (i = 0; i < n; i++)
511: {
512: t = v[i] + e2[i];
513: v[i] = (t < q) ? t : t - q;
514: }
515: memwipe(e2, n * sizeof(uint32_t));
516:
517: /* create uniform noise bytes from seed with nonce = 0x02 */
518: rbits = noise->get_uniform_bytes(noise, 0x03, n/(4*8));
519:
520: rec = newhope_reconciliation_create(n, q);
521: this->r = rec->help_reconcile(rec, v, rbits);
522: free(rbits);
523: this->shared_secret = rec->reconcile(rec, v, this->r);
524: rec->destroy(rec);
525:
526: DBG4(DBG_LIB, "key: %B", &this->shared_secret);
527: success = TRUE;
528:
529: end:
530: DESTROY_IF(rng);
531: DESTROY_IF(noise);
532: free(a);
533: free(b);
534: free(e1);
535: free(e2);
536: free(v);
537:
538: return success;
539: }
540: else
541: {
542: uint32_t *v;
543:
544: if (value.len != poly_len + rec_len)
545: {
546: DBG1(DBG_LIB, "received %N KE payload of incorrect size",
547: diffie_hellman_group_names, NH_128_BIT);
548: return FALSE;
549: }
550:
551: this->u = unpack_poly(this, value.ptr);
552: if (this->u == NULL)
553: {
554: return FALSE;
555: }
556:
557: this->r = unpack_rec(this, value.ptr + poly_len);
558: if (this->r == NULL)
559: {
560: return FALSE;
561: }
562:
563: DBG3(DBG_LIB, " i u[i] r[i]");
564: for (i = 0; i < n; i++)
565: {
566: DBG3(DBG_LIB, "%4d %5u %5u", i, this->u[i], this->r[i]);
567: }
568:
569: /* compute v' = NTT_inv( u * NTT(s) ) */
570: v = multiply_ntt_inv_poly(this, this->u);
571:
572: rec = newhope_reconciliation_create(n, q);
573: this->shared_secret = rec->reconcile(rec, v, this->r);
574: free(v);
575: rec->destroy(rec);
576:
577: DBG4(DBG_LIB, "key: %B", &this->shared_secret);
578:
579: return TRUE;
580: }
581: }
582:
583: METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
584: private_newhope_ke_t *this)
585: {
586: return NH_128_BIT;
587: }
588:
589: METHOD(diffie_hellman_t, destroy, void,
590: private_newhope_ke_t *this)
591: {
592: chunk_clear(&this->shared_secret);
593: memwipe(this->s, this->params->n * sizeof(uint32_t));
594: free(this->s);
595: free(this->u);
596: free(this->r);
597: free(this);
598: }
599:
600: /*
601: * Described in header.
602: */
603: newhope_ke_t *newhope_ke_create(diffie_hellman_group_t group, chunk_t g, chunk_t p)
604: {
605: private_newhope_ke_t *this;
606:
607: INIT(this,
608: .public = {
609: .dh = {
610: .get_shared_secret = _get_shared_secret,
611: .set_other_public_value = _set_other_public_value,
612: .get_my_public_value = _get_my_public_value,
613: .get_dh_group = _get_dh_group,
614: .destroy = _destroy,
615: },
616: },
617: .params = &ntt_fft_12289_1024,
618:
619: );
620:
621: return &this->public;
622: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>