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