travis: Add build tests for NM plugin
[strongswan.git] / src / libstrongswan / plugins / bliss / bliss_public_key.c
1 /*
2 * Copyright (C) 2014-2016 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "bliss_public_key.h"
17 #include "bliss_signature.h"
18 #include "bliss_bitpacker.h"
19 #include "ntt_fft.h"
20 #include "ntt_fft_reduce.h"
21 #include "bliss_utils.h"
22
23 #include <asn1/asn1.h>
24 #include <asn1/asn1_parser.h>
25 #include <asn1/oid.h>
26
27 typedef struct private_bliss_public_key_t private_bliss_public_key_t;
28
29 /**
30 * Private data structure with signing context.
31 */
32 struct private_bliss_public_key_t {
33 /**
34 * Public interface for this signer.
35 */
36 bliss_public_key_t public;
37
38 /**
39 * BLISS signature parameter set
40 */
41 const bliss_param_set_t *set;
42
43 /**
44 * NTT of BLISS public key a (coefficients of polynomial (2g + 1)/f)
45 */
46 uint32_t *A;
47
48 /**
49 * NTT of BLISS public key in Montgomery representation Ar = rA mod
50 */
51 uint32_t *Ar;
52
53 /**
54 * reference counter
55 */
56 refcount_t ref;
57 };
58
59 METHOD(public_key_t, get_type, key_type_t,
60 private_bliss_public_key_t *this)
61 {
62 return KEY_BLISS;
63 }
64
65 /**
66 * Verify a BLISS signature based on a SHA-512 hash
67 */
68 static bool verify_bliss(private_bliss_public_key_t *this, hash_algorithm_t alg,
69 chunk_t data, chunk_t signature)
70 {
71 int i, n;
72 int32_t *z1, *u;
73 int16_t *ud, *z2d;
74 uint16_t q, q2, p, *c_indices, *indices;
75 uint32_t *az;
76 uint8_t data_hash_buf[HASH_SIZE_SHA512];
77 chunk_t data_hash;
78 hasher_t *hasher;
79 ext_out_function_t oracle_alg;
80 ntt_fft_t *fft;
81 bliss_signature_t *sig;
82 bool success = FALSE;
83
84 /* Create data hash using configurable hash algorithm */
85 hasher = lib->crypto->create_hasher(lib->crypto, alg);
86 if (!hasher )
87 {
88 return FALSE;
89 }
90 data_hash = chunk_create(data_hash_buf, hasher->get_hash_size(hasher));
91
92 if (!hasher->get_hash(hasher, data, data_hash_buf))
93 {
94 hasher->destroy(hasher);
95 return FALSE;
96 }
97 hasher->destroy(hasher);
98
99 sig = bliss_signature_create_from_data(this->set, signature);
100 if (!sig)
101 {
102 return FALSE;
103 }
104 sig->get_parameters(sig, &z1, &z2d, &c_indices);
105
106 if (!bliss_utils_check_norms(this->set, z1, z2d))
107 {
108 sig->destroy(sig);
109 return FALSE;
110 }
111
112 /* MGF1 hash algorithm to be used for random oracle */
113 oracle_alg = XOF_MGF1_SHA512;
114
115 /* Initialize a couple of needed variables */
116 n = this->set->n;
117 q = this->set->q;
118 p = this->set->p;
119 q2 = 2 * q;
120 az = malloc(n * sizeof(uint32_t));
121 u = malloc(n * sizeof(int32_t));
122 ud = malloc(n * sizeof(int16_t));
123 indices = malloc(this->set->kappa * sizeof(uint16_t));
124
125 for (i = 0; i < n; i++)
126 {
127 az[i] = z1[i] < 0 ? q + z1[i] : z1[i];
128 }
129 fft = ntt_fft_create(this->set->fft_params);
130 fft->transform(fft, az, az, FALSE);
131
132 for (i = 0; i < n; i++)
133 {
134 az[i] = ntt_fft_mreduce(this->Ar[i] * az[i], this->set->fft_params);
135 }
136 fft->transform(fft, az, az, TRUE);
137
138 for (i = 0; i < n; i++)
139 {
140 u[i] = (2 * this->set->q2_inv * az[i]) % q2;
141 }
142
143 for (i = 0; i < this->set->kappa; i++)
144 {
145 u[c_indices[i]] = (u[c_indices[i]] + q * this->set->q2_inv) % q2;
146 }
147 bliss_utils_round_and_drop(this->set, u, ud);
148
149 for (i = 0; i < n; i++)
150 {
151 ud[i] += z2d[i];
152 if (ud[i] < 0)
153 {
154 ud[i] += p;
155 }
156 else if (ud[i] >= p)
157 {
158 ud[i] -= p;
159 }
160 }
161
162 /* Detailed debugging information */
163 DBG3(DBG_LIB, " i u[i] ud[i] z2d[i]");
164 for (i = 0; i < n; i++)
165 {
166 DBG3(DBG_LIB, "%3d %6d %4d %4d", i, u[i], ud[i], z2d[i]);
167 }
168
169 if (!bliss_utils_generate_c(oracle_alg, data_hash, ud, this->set, indices))
170 {
171 goto end;
172 }
173
174 for (i = 0; i < this->set->kappa; i++)
175 {
176 if (indices[i] != c_indices[i])
177 {
178 DBG1(DBG_LIB, "signature verification failed");
179 goto end;
180 }
181 }
182 success = TRUE;
183
184 end:
185 /* cleanup */
186 sig->destroy(sig);
187 fft->destroy(fft);
188 free(az);
189 free(u);
190 free(ud);
191 free(indices);
192
193 return success;
194 }
195
196 METHOD(public_key_t, verify, bool,
197 private_bliss_public_key_t *this, signature_scheme_t scheme, void *params,
198 chunk_t data, chunk_t signature)
199 {
200 switch (scheme)
201 {
202 case SIGN_BLISS_WITH_SHA2_256:
203 return verify_bliss(this, HASH_SHA256, data, signature);
204 case SIGN_BLISS_WITH_SHA2_384:
205 return verify_bliss(this, HASH_SHA384, data, signature);
206 case SIGN_BLISS_WITH_SHA2_512:
207 return verify_bliss(this, HASH_SHA512, data, signature);
208 case SIGN_BLISS_WITH_SHA3_256:
209 return verify_bliss(this, HASH_SHA3_256, data, signature);
210 case SIGN_BLISS_WITH_SHA3_384:
211 return verify_bliss(this, HASH_SHA3_384, data, signature);
212 case SIGN_BLISS_WITH_SHA3_512:
213 return verify_bliss(this, HASH_SHA3_512, data, signature);
214 default:
215 DBG1(DBG_LIB, "signature scheme %N not supported by BLISS",
216 signature_scheme_names, scheme);
217 return FALSE;
218 }
219 }
220
221 METHOD(public_key_t, encrypt_, bool,
222 private_bliss_public_key_t *this, encryption_scheme_t scheme,
223 chunk_t plain, chunk_t *crypto)
224 {
225 DBG1(DBG_LIB, "encryption scheme %N not supported",
226 encryption_scheme_names, scheme);
227 return FALSE;
228 }
229
230 METHOD(public_key_t, get_keysize, int,
231 private_bliss_public_key_t *this)
232 {
233 return this->set->strength;
234 }
235
236 METHOD(public_key_t, get_encoding, bool,
237 private_bliss_public_key_t *this, cred_encoding_type_t type,
238 chunk_t *encoding)
239 {
240 bool success = TRUE;
241
242 *encoding = bliss_public_key_info_encode(this->set->oid, this->A, this->set);
243
244 if (type != PUBKEY_SPKI_ASN1_DER)
245 {
246 chunk_t asn1_encoding = *encoding;
247
248 success = lib->encoding->encode(lib->encoding, type,
249 NULL, encoding, CRED_PART_BLISS_PUB_ASN1_DER,
250 asn1_encoding, CRED_PART_END);
251 chunk_clear(&asn1_encoding);
252 }
253 return success;
254 }
255
256 METHOD(public_key_t, get_fingerprint, bool,
257 private_bliss_public_key_t *this, cred_encoding_type_t type, chunk_t *fp)
258 {
259 bool success;
260
261 if (lib->encoding->get_cache(lib->encoding, type, this, fp))
262 {
263 return TRUE;
264 }
265 success = bliss_public_key_fingerprint(this->set->oid, this->A,
266 this->set, type, fp);
267 if (success)
268 {
269 lib->encoding->cache(lib->encoding, type, this, *fp);
270 }
271 return success;
272 }
273
274 METHOD(public_key_t, get_ref, public_key_t*,
275 private_bliss_public_key_t *this)
276 {
277 ref_get(&this->ref);
278 return &this->public.key;
279 }
280
281 METHOD(public_key_t, destroy, void,
282 private_bliss_public_key_t *this)
283 {
284 if (ref_put(&this->ref))
285 {
286 lib->encoding->clear_cache(lib->encoding, this);
287 free(this->A);
288 free(this->Ar);
289 free(this);
290 }
291 }
292
293 /**
294 * ASN.1 definition of a BLISS public key
295 */
296 static const asn1Object_t pubkeyObjects[] = {
297 { 0, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
298 { 1, "algorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
299 { 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_BODY }, /* 2 */
300 { 0, "exit", ASN1_EOC, ASN1_EXIT }
301 };
302 #define BLISS_SUBJECT_PUBLIC_KEY_ALGORITHM 1
303 #define BLISS_SUBJECT_PUBLIC_KEY 2
304
305 /**
306 * See header.
307 */
308 bliss_public_key_t *bliss_public_key_load(key_type_t type, va_list args)
309 {
310 private_bliss_public_key_t *this;
311 chunk_t blob = chunk_empty, object, param;
312 asn1_parser_t *parser;
313 bool success = FALSE;
314 int objectID, oid, i;
315 uint32_t r2;
316
317 while (TRUE)
318 {
319 switch (va_arg(args, builder_part_t))
320 {
321 case BUILD_BLOB_ASN1_DER:
322 blob = va_arg(args, chunk_t);
323 continue;
324 case BUILD_END:
325 break;
326 default:
327 return NULL;
328 }
329 break;
330 }
331
332 if (blob.len == 0)
333 {
334 return NULL;
335 }
336
337 INIT(this,
338 .public = {
339 .key = {
340 .get_type = _get_type,
341 .verify = _verify,
342 .encrypt = _encrypt_,
343 .equals = public_key_equals,
344 .get_keysize = _get_keysize,
345 .get_fingerprint = _get_fingerprint,
346 .has_fingerprint = public_key_has_fingerprint,
347 .get_encoding = _get_encoding,
348 .get_ref = _get_ref,
349 .destroy = _destroy,
350 },
351 },
352 .ref = 1,
353 );
354
355 parser = asn1_parser_create(pubkeyObjects, blob);
356
357 while (parser->iterate(parser, &objectID, &object))
358 {
359 switch (objectID)
360 {
361 case BLISS_SUBJECT_PUBLIC_KEY_ALGORITHM:
362 {
363 oid = asn1_parse_algorithmIdentifier(object,
364 parser->get_level(parser)+1, &param);
365 if (oid != OID_BLISS_PUBLICKEY)
366 {
367 goto end;
368 }
369 if (!asn1_parse_simple_object(&param, ASN1_OID,
370 parser->get_level(parser)+3, "blissKeyType"))
371 {
372 goto end;
373 }
374 oid = asn1_known_oid(param);
375 if (oid == OID_UNKNOWN)
376 {
377 goto end;
378 }
379 this->set = bliss_param_set_get_by_oid(oid);
380 if (this->set == NULL)
381 {
382 goto end;
383 }
384 break;
385 }
386 case BLISS_SUBJECT_PUBLIC_KEY:
387 if (!bliss_public_key_from_asn1(object, this->set, &this->A))
388 {
389 goto end;
390 }
391 this->Ar = malloc(this->set->n * sizeof(uint32_t));
392 r2 = this->set->fft_params->r2;
393
394 for (i = 0; i < this->set->n; i++)
395 {
396 this->Ar[i] = ntt_fft_mreduce(this->A[i] * r2,
397 this->set->fft_params);
398 }
399 break;
400 }
401 }
402 success = parser->success(parser);
403
404 end:
405 parser->destroy(parser);
406 if (!success)
407 {
408 destroy(this);
409 return NULL;
410 }
411
412 return &this->public;
413 }
414
415 /**
416 * See header.
417 */
418 bool bliss_public_key_from_asn1(chunk_t object, const bliss_param_set_t *set,
419 uint32_t **pubkey)
420 {
421 bliss_bitpacker_t *packer;
422 uint32_t coefficient;
423 uint16_t needed_bits;
424 int i;
425
426 /* skip initial bit string octet defining unused bits */
427 object = chunk_skip(object, 1);
428
429 needed_bits = set->n * set->q_bits;
430
431 if (8 * object.len < needed_bits)
432 {
433 return FALSE;
434 }
435 *pubkey = malloc(set->n * sizeof(uint32_t));
436
437 packer = bliss_bitpacker_create_from_data(object);
438
439 for (i = 0; i < set->n; i++)
440 {
441 packer->read_bits(packer, &coefficient, set->q_bits);
442 if (coefficient >= set->q)
443 {
444 packer->destroy(packer);
445 return FALSE;
446 }
447 (*pubkey)[i] = coefficient;
448 }
449 packer->destroy(packer);
450
451 return TRUE;
452 }
453
454 /**
455 * See header.
456 */
457 chunk_t bliss_public_key_encode(uint32_t *pubkey, const bliss_param_set_t *set)
458 {
459 bliss_bitpacker_t *packer;
460 chunk_t encoding;
461 int i;
462
463 packer = bliss_bitpacker_create(set->n * set->q_bits);
464
465 for (i = 0; i < set->n; i++)
466 {
467 packer->write_bits(packer, pubkey[i], set->q_bits);
468 }
469 encoding = packer->extract_buf(packer);
470 packer->destroy(packer);
471
472 return encoding;
473 }
474
475 /**
476 * See header.
477 */
478 chunk_t bliss_public_key_info_encode(int oid, uint32_t *pubkey,
479 const bliss_param_set_t *set)
480 {
481 chunk_t encoding, pubkey_encoding;
482
483 pubkey_encoding = bliss_public_key_encode(pubkey, set);
484
485 encoding = asn1_wrap(ASN1_SEQUENCE, "mm",
486 asn1_wrap(ASN1_SEQUENCE, "mm",
487 asn1_build_known_oid(OID_BLISS_PUBLICKEY),
488 asn1_build_known_oid(oid)),
489 asn1_bitstring("m", pubkey_encoding));
490
491 return encoding;
492 }
493
494 /**
495 * See header.
496 */
497 bool bliss_public_key_fingerprint(int oid, uint32_t *pubkey,
498 const bliss_param_set_t *set,
499 cred_encoding_type_t type, chunk_t *fp)
500 {
501 hasher_t *hasher;
502 chunk_t key;
503
504 switch (type)
505 {
506 case KEYID_PUBKEY_SHA1:
507 key = bliss_public_key_encode(pubkey, set);
508 break;
509 case KEYID_PUBKEY_INFO_SHA1:
510 key = bliss_public_key_info_encode(oid, pubkey, set);
511 break;
512 default:
513 return FALSE;
514 }
515
516 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
517 if (!hasher || !hasher->allocate_hash(hasher, key, fp))
518 {
519 DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed");
520 DESTROY_IF(hasher);
521 free(key.ptr);
522
523 return FALSE;
524 }
525 hasher->destroy(hasher);
526 free(key.ptr);
527
528 return TRUE;
529 }
530