]>
Commit | Line | Data |
---|---|---|
552cc11b | 1 | /* |
5955db5b | 2 | * Copyright (C) 2017-2018 Tobias Brunner |
552cc11b | 3 | * Copyright (C) 2005 Jan Hutter |
48b23d06 | 4 | * Copyright (C) 2005-2009 Martin Willi |
e36af6fc | 5 | * Copyright (C) 2012-2019 Andreas Steffen |
48b23d06 | 6 | * HSR Hochschule fuer Technik Rapperswil |
552cc11b MW |
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. | |
552cc11b MW |
17 | */ |
18 | ||
19 | #include <gmp.h> | |
20 | #include <sys/stat.h> | |
21 | #include <unistd.h> | |
22 | #include <string.h> | |
23 | ||
24 | #include "gmp_rsa_private_key.h" | |
25 | #include "gmp_rsa_public_key.h" | |
26 | ||
f05b4272 | 27 | #include <utils/debug.h> |
d3d7e46b | 28 | #include <asn1/oid.h> |
552cc11b | 29 | #include <asn1/asn1.h> |
d3d7e46b | 30 | #include <asn1/asn1_parser.h> |
154ee7f6 | 31 | #include <credentials/keys/signature_params.h> |
552cc11b | 32 | |
3e35a6e7 MW |
33 | #ifdef HAVE_MPZ_POWM_SEC |
34 | # undef mpz_powm | |
35 | # define mpz_powm mpz_powm_sec | |
36 | #endif | |
37 | ||
552cc11b MW |
38 | /** |
39 | * Public exponent to use for key generation. | |
40 | */ | |
41 | #define PUBLIC_EXPONENT 0x10001 | |
42 | ||
43 | typedef struct private_gmp_rsa_private_key_t private_gmp_rsa_private_key_t; | |
44 | ||
45 | /** | |
46 | * Private data of a gmp_rsa_private_key_t object. | |
47 | */ | |
48 | struct private_gmp_rsa_private_key_t { | |
49 | /** | |
50 | * Public interface for this signer. | |
51 | */ | |
52 | gmp_rsa_private_key_t public; | |
7daf5226 | 53 | |
552cc11b MW |
54 | /** |
55 | * Public modulus. | |
56 | */ | |
57 | mpz_t n; | |
7daf5226 | 58 | |
552cc11b MW |
59 | /** |
60 | * Public exponent. | |
61 | */ | |
62 | mpz_t e; | |
7daf5226 | 63 | |
552cc11b MW |
64 | /** |
65 | * Private prime 1. | |
66 | */ | |
67 | mpz_t p; | |
7daf5226 | 68 | |
552cc11b MW |
69 | /** |
70 | * Private Prime 2. | |
71 | */ | |
72 | mpz_t q; | |
7daf5226 | 73 | |
552cc11b | 74 | /** |
48b23d06 AS |
75 | * Carmichael function m = lambda(n) = lcm(p-1,q-1). |
76 | */ | |
77 | mpz_t m; | |
78 | ||
79 | /** | |
80 | * Private exponent and optional secret sharing polynomial coefficients. | |
552cc11b | 81 | */ |
48b23d06 | 82 | mpz_t *d; |
7daf5226 | 83 | |
552cc11b MW |
84 | /** |
85 | * Private exponent 1. | |
86 | */ | |
87 | mpz_t exp1; | |
7daf5226 | 88 | |
552cc11b MW |
89 | /** |
90 | * Private exponent 2. | |
91 | */ | |
92 | mpz_t exp2; | |
7daf5226 | 93 | |
552cc11b MW |
94 | /** |
95 | * Private coefficient. | |
96 | */ | |
97 | mpz_t coeff; | |
7daf5226 | 98 | |
48b23d06 AS |
99 | /** |
100 | * Total number of private key shares | |
101 | */ | |
102 | u_int shares; | |
103 | ||
104 | /** | |
105 | * Secret sharing threshold | |
106 | */ | |
107 | u_int threshold; | |
108 | ||
109 | /** | |
110 | * Optional verification key (threshold > 1). | |
111 | */ | |
112 | mpz_t v; | |
113 | ||
552cc11b MW |
114 | /** |
115 | * Keysize in bytes. | |
116 | */ | |
117 | size_t k; | |
7daf5226 | 118 | |
552cc11b MW |
119 | /** |
120 | * reference count | |
121 | */ | |
741680d1 | 122 | refcount_t ref; |
552cc11b MW |
123 | }; |
124 | ||
552cc11b | 125 | /** |
741680d1 | 126 | * Convert a MP integer into a chunk_t |
552cc11b | 127 | */ |
741680d1 MW |
128 | chunk_t gmp_mpz_to_chunk(const mpz_t value) |
129 | { | |
130 | chunk_t n; | |
7daf5226 | 131 | |
741680d1 MW |
132 | n.len = 1 + mpz_sizeinbase(value, 2) / BITS_PER_BYTE; |
133 | n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, value); | |
134 | if (n.ptr == NULL) | |
135 | { /* if we have zero in "value", gmp returns NULL */ | |
136 | n.len = 0; | |
137 | } | |
138 | return n; | |
139 | } | |
552cc11b MW |
140 | |
141 | /** | |
6a365f07 | 142 | * Auxiliary function overwriting private key material with zero bytes |
552cc11b | 143 | */ |
741680d1 | 144 | static void mpz_clear_sensitive(mpz_t z) |
552cc11b MW |
145 | { |
146 | size_t len = mpz_size(z) * GMP_LIMB_BITS / BITS_PER_BYTE; | |
b12c53ce | 147 | uint8_t *zeros = alloca(len); |
7daf5226 | 148 | |
48b23d06 | 149 | memset(zeros, 0, len); |
6a365f07 | 150 | /* overwrite mpz_t with zero bytes before clearing it */ |
48b23d06 | 151 | mpz_import(z, len, 1, 1, 1, 0, zeros); |
552cc11b | 152 | mpz_clear(z); |
552cc11b MW |
153 | } |
154 | ||
155 | /** | |
156 | * Create a mpz prime of at least prime_size | |
157 | */ | |
e36af6fc | 158 | static status_t compute_prime(drbg_t *drbg, size_t prime_size, bool safe, mpz_t *p, mpz_t *q) |
552cc11b | 159 | { |
552cc11b | 160 | chunk_t random_bytes; |
48b23d06 | 161 | int count = 0; |
7daf5226 | 162 | |
48b23d06 AS |
163 | mpz_init(*p); |
164 | mpz_init(*q); | |
e36af6fc | 165 | random_bytes = chunk_alloc(prime_size); |
168ee460 | 166 | |
552cc11b MW |
167 | do |
168 | { | |
e36af6fc | 169 | if (!drbg->generate(drbg, random_bytes.len, random_bytes.ptr)) |
5025135f TB |
170 | { |
171 | DBG1(DBG_LIB, "failed to allocate random prime"); | |
48b23d06 AS |
172 | mpz_clear(*p); |
173 | mpz_clear(*q); | |
e36af6fc | 174 | chunk_free(&random_bytes); |
5025135f TB |
175 | return FAILED; |
176 | } | |
7daf5226 | 177 | |
168ee460 AS |
178 | /* make sure the two most significant bits are set */ |
179 | if (safe) | |
180 | { | |
181 | random_bytes.ptr[0] &= 0x7F; | |
182 | random_bytes.ptr[0] |= 0x60; | |
48b23d06 | 183 | mpz_import(*q, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr); |
168ee460 AS |
184 | do |
185 | { | |
48b23d06 AS |
186 | count++; |
187 | mpz_nextprime (*q, *q); | |
188 | mpz_mul_ui(*p, *q, 2); | |
189 | mpz_add_ui(*p, *p, 1); | |
168ee460 | 190 | } |
48b23d06 AS |
191 | while (mpz_probab_prime_p(*p, 10) == 0); |
192 | DBG2(DBG_LIB, "safe prime found after %d iterations", count); | |
168ee460 AS |
193 | } |
194 | else | |
195 | { | |
196 | random_bytes.ptr[0] |= 0xC0; | |
48b23d06 AS |
197 | mpz_import(*p, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr); |
198 | mpz_nextprime (*p, *p); | |
168ee460 | 199 | } |
552cc11b | 200 | } |
168ee460 | 201 | /* check if the prime isn't too large */ |
48b23d06 | 202 | while (((mpz_sizeinbase(*p, 2) + 7) / 8) > prime_size); |
7daf5226 | 203 | |
e36af6fc | 204 | chunk_clear(&random_bytes); |
48b23d06 | 205 | |
ef33a4ab | 206 | /* additionally return p-1 */ |
48b23d06 | 207 | mpz_sub_ui(*q, *p, 1); |
168ee460 | 208 | |
552cc11b MW |
209 | return SUCCESS; |
210 | } | |
211 | ||
212 | /** | |
213 | * PKCS#1 RSADP function | |
214 | */ | |
215 | static chunk_t rsadp(private_gmp_rsa_private_key_t *this, chunk_t data) | |
216 | { | |
217 | mpz_t t1, t2; | |
218 | chunk_t decrypted; | |
7daf5226 | 219 | |
552cc11b MW |
220 | mpz_init(t1); |
221 | mpz_init(t2); | |
7daf5226 | 222 | |
552cc11b | 223 | mpz_import(t1, data.len, 1, 1, 1, 0, data.ptr); |
7daf5226 | 224 | |
552cc11b MW |
225 | mpz_powm(t2, t1, this->exp1, this->p); /* m1 = c^dP mod p */ |
226 | mpz_powm(t1, t1, this->exp2, this->q); /* m2 = c^dQ mod Q */ | |
227 | mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */ | |
228 | mpz_mod(t2, t2, this->p); | |
229 | mpz_mul(t2, t2, this->coeff); | |
230 | mpz_mod(t2, t2, this->p); | |
7daf5226 | 231 | |
552cc11b MW |
232 | mpz_mul(t2, t2, this->q); /* m = m2 + h q */ |
233 | mpz_add(t1, t1, t2); | |
7daf5226 | 234 | |
552cc11b MW |
235 | decrypted.len = this->k; |
236 | decrypted.ptr = mpz_export(NULL, NULL, 1, decrypted.len, 1, 0, t1); | |
73f6886a MW |
237 | if (decrypted.ptr == NULL) |
238 | { | |
239 | decrypted.len = 0; | |
240 | } | |
7daf5226 | 241 | |
741680d1 MW |
242 | mpz_clear_sensitive(t1); |
243 | mpz_clear_sensitive(t2); | |
7daf5226 | 244 | |
552cc11b MW |
245 | return decrypted; |
246 | } | |
247 | ||
248 | /** | |
249 | * PKCS#1 RSASP1 function | |
250 | */ | |
251 | static chunk_t rsasp1(private_gmp_rsa_private_key_t *this, chunk_t data) | |
252 | { | |
253 | return rsadp(this, data); | |
254 | } | |
255 | ||
256 | /** | |
5955db5b TB |
257 | * Hashes the data and builds the plaintext signature value with EMSA |
258 | * PKCS#1 v1.5 padding. | |
259 | * | |
260 | * Allocates the signature data. | |
552cc11b | 261 | */ |
5955db5b TB |
262 | bool gmp_emsa_pkcs1_signature_data(hash_algorithm_t hash_algorithm, |
263 | chunk_t data, size_t keylen, chunk_t *em) | |
552cc11b | 264 | { |
8b799d55 | 265 | chunk_t digestInfo = chunk_empty; |
552cc11b | 266 | |
8b799d55 | 267 | if (hash_algorithm != HASH_UNKNOWN) |
552cc11b | 268 | { |
8b799d55 AS |
269 | hasher_t *hasher; |
270 | chunk_t hash; | |
271 | int hash_oid = hasher_algorithm_to_oid(hash_algorithm); | |
7daf5226 | 272 | |
8b799d55 AS |
273 | if (hash_oid == OID_UNKNOWN) |
274 | { | |
275 | return FALSE; | |
276 | } | |
277 | ||
278 | hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); | |
87dd205b | 279 | if (!hasher || !hasher->allocate_hash(hasher, data, &hash)) |
8b799d55 | 280 | { |
87dd205b | 281 | DESTROY_IF(hasher); |
8b799d55 AS |
282 | return FALSE; |
283 | } | |
8b799d55 | 284 | hasher->destroy(hasher); |
7daf5226 | 285 | |
8b799d55 | 286 | /* build DER-encoded digestInfo */ |
eb73685d | 287 | digestInfo = asn1_wrap(ASN1_SEQUENCE, "mm", |
8b799d55 | 288 | asn1_algorithmIdentifier(hash_oid), |
5955db5b TB |
289 | asn1_wrap(ASN1_OCTET_STRING, "m", hash)); |
290 | ||
8b799d55 AS |
291 | data = digestInfo; |
292 | } | |
552cc11b | 293 | |
129ab919 | 294 | if (keylen < 11 || data.len > keylen - 11) |
3176e442 | 295 | { |
5955db5b TB |
296 | chunk_free(&digestInfo); |
297 | DBG1(DBG_LIB, "signature value of %zu bytes is too long for key of " | |
298 | "%zu bytes", data.len, keylen); | |
3176e442 MW |
299 | return FALSE; |
300 | } | |
7daf5226 | 301 | |
5955db5b TB |
302 | /* EM = 0x00 || 0x01 || PS || 0x00 || T. |
303 | * PS = 0xFF padding, with length to fill em (at least 8 bytes) | |
552cc11b MW |
304 | * T = encoded_hash |
305 | */ | |
5955db5b | 306 | *em = chunk_alloc(keylen); |
7daf5226 | 307 | |
552cc11b | 308 | /* fill em with padding */ |
5955db5b | 309 | memset(em->ptr, 0xFF, em->len); |
552cc11b | 310 | /* set magic bytes */ |
5955db5b TB |
311 | *(em->ptr) = 0x00; |
312 | *(em->ptr+1) = 0x01; | |
313 | *(em->ptr + em->len - data.len - 1) = 0x00; | |
314 | /* set encoded hash */ | |
315 | memcpy(em->ptr + em->len - data.len, data.ptr, data.len); | |
316 | ||
317 | chunk_clear(&digestInfo); | |
318 | return TRUE; | |
319 | } | |
320 | ||
321 | /** | |
322 | * Build a signature using the PKCS#1 EMSA scheme | |
323 | */ | |
324 | static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, | |
325 | hash_algorithm_t hash_algorithm, | |
326 | chunk_t data, chunk_t *signature) | |
327 | { | |
328 | chunk_t em; | |
329 | ||
330 | if (!gmp_emsa_pkcs1_signature_data(hash_algorithm, data, this->k, &em)) | |
331 | { | |
332 | return FALSE; | |
333 | } | |
552cc11b MW |
334 | |
335 | /* build signature */ | |
336 | *signature = rsasp1(this, em); | |
7daf5226 | 337 | |
5955db5b | 338 | chunk_free(&em); |
7daf5226 | 339 | return TRUE; |
552cc11b MW |
340 | } |
341 | ||
154ee7f6 TB |
342 | /** |
343 | * Build a signature using the PKCS#1 EMSA PSS scheme | |
344 | */ | |
345 | static bool build_emsa_pss_signature(private_gmp_rsa_private_key_t *this, | |
346 | rsa_pss_params_t *params, chunk_t data, | |
347 | chunk_t *signature) | |
348 | { | |
349 | ext_out_function_t xof; | |
350 | hasher_t *hasher = NULL; | |
351 | rng_t *rng = NULL; | |
352 | xof_t *mgf = NULL; | |
353 | chunk_t hash, salt = chunk_empty, m, ps, db, dbmask, em; | |
354 | size_t embits, emlen, maskbits; | |
355 | bool success = FALSE; | |
356 | ||
357 | if (!params) | |
358 | { | |
359 | return FALSE; | |
360 | } | |
126fd8af TB |
361 | xof = xof_mgf1_from_hash_algorithm(params->mgf1_hash); |
362 | if (xof == XOF_UNDEFINED) | |
154ee7f6 | 363 | { |
126fd8af TB |
364 | DBG1(DBG_LIB, "%N is not supported for MGF1", hash_algorithm_names, |
365 | params->mgf1_hash); | |
366 | return FALSE; | |
154ee7f6 TB |
367 | } |
368 | /* emBits = modBits - 1 */ | |
369 | embits = mpz_sizeinbase(this->n, 2) - 1; | |
370 | /* emLen = ceil(emBits/8) */ | |
371 | emlen = (embits + 7) / BITS_PER_BYTE; | |
372 | /* mHash = Hash(M) */ | |
373 | hasher = lib->crypto->create_hasher(lib->crypto, params->hash); | |
374 | if (!hasher) | |
375 | { | |
376 | DBG1(DBG_LIB, "hash algorithm %N not supported", | |
377 | hash_algorithm_names, params->hash); | |
378 | return FALSE; | |
379 | } | |
380 | hash = chunk_alloca(hasher->get_hash_size(hasher)); | |
381 | if (!hasher->get_hash(hasher, data, hash.ptr)) | |
382 | { | |
383 | goto error; | |
384 | } | |
385 | ||
ecfe6755 | 386 | salt.len = params->salt_len; |
f241a981 TB |
387 | if (params->salt.len) |
388 | { | |
389 | salt = params->salt; | |
390 | } | |
154ee7f6 TB |
391 | if (emlen < (hash.len + salt.len + 2)) |
392 | { /* too long */ | |
393 | goto error; | |
394 | } | |
f241a981 | 395 | if (salt.len && !params->salt.len) |
154ee7f6 TB |
396 | { |
397 | salt = chunk_alloca(salt.len); | |
398 | rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); | |
399 | if (!rng || !rng->get_bytes(rng, salt.len, salt.ptr)) | |
400 | { | |
401 | goto error; | |
402 | } | |
403 | } | |
404 | /* M' = 0x0000000000000000 | mHash | salt */ | |
405 | m = chunk_cata("ccc", | |
406 | chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00), | |
407 | hash, salt); | |
408 | /* H = Hash(M') */ | |
409 | if (!hasher->get_hash(hasher, m, hash.ptr)) | |
410 | { | |
411 | goto error; | |
412 | } | |
413 | /* PS = 00...<padding depending on hash and salt length> */ | |
414 | ps = chunk_alloca(emlen - salt.len - hash.len - 2); | |
415 | memset(ps.ptr, 0, ps.len); | |
416 | /* DB = PS | 0x01 | salt */ | |
417 | db = chunk_cata("ccc", ps, chunk_from_chars(0x01), salt); | |
418 | /* dbMask = MGF(H, emLen - hLen - 1) */ | |
419 | mgf = lib->crypto->create_xof(lib->crypto, xof); | |
420 | dbmask = chunk_alloca(db.len); | |
421 | if (!mgf) | |
422 | { | |
423 | DBG1(DBG_LIB, "%N not supported", ext_out_function_names, xof); | |
424 | goto error; | |
425 | } | |
426 | if (!mgf->set_seed(mgf, hash) || | |
427 | !mgf->get_bytes(mgf, dbmask.len, dbmask.ptr)) | |
428 | { | |
429 | goto error; | |
430 | } | |
431 | /* maskedDB = DB xor dbMask */ | |
432 | memxor(db.ptr, dbmask.ptr, db.len); | |
433 | /* zero out unused bits */ | |
434 | maskbits = (8 * emlen) - embits; | |
435 | if (maskbits) | |
436 | { | |
437 | db.ptr[0] &= (0xff >> maskbits); | |
438 | } | |
439 | /* EM = maskedDB | H | 0xbc */ | |
440 | em = chunk_cata("ccc", db, hash, chunk_from_chars(0xbc)); | |
441 | /* S = RSASP1(K, EM) */ | |
442 | *signature = rsasp1(this, em); | |
443 | success = TRUE; | |
444 | ||
445 | error: | |
446 | DESTROY_IF(hasher); | |
447 | DESTROY_IF(rng); | |
448 | DESTROY_IF(mgf); | |
449 | return success; | |
450 | } | |
451 | ||
876b61e1 MW |
452 | METHOD(private_key_t, get_type, key_type_t, |
453 | private_gmp_rsa_private_key_t *this) | |
552cc11b MW |
454 | { |
455 | return KEY_RSA; | |
456 | } | |
457 | ||
876b61e1 MW |
458 | METHOD(private_key_t, sign, bool, |
459 | private_gmp_rsa_private_key_t *this, signature_scheme_t scheme, | |
de280c2e | 460 | void *params, chunk_t data, chunk_t *signature) |
552cc11b MW |
461 | { |
462 | switch (scheme) | |
463 | { | |
8b799d55 AS |
464 | case SIGN_RSA_EMSA_PKCS1_NULL: |
465 | return build_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature); | |
40f2589a | 466 | case SIGN_RSA_EMSA_PKCS1_SHA2_224: |
b6f739c1 | 467 | return build_emsa_pkcs1_signature(this, HASH_SHA224, data, signature); |
40f2589a | 468 | case SIGN_RSA_EMSA_PKCS1_SHA2_256: |
552cc11b | 469 | return build_emsa_pkcs1_signature(this, HASH_SHA256, data, signature); |
40f2589a | 470 | case SIGN_RSA_EMSA_PKCS1_SHA2_384: |
552cc11b | 471 | return build_emsa_pkcs1_signature(this, HASH_SHA384, data, signature); |
40f2589a | 472 | case SIGN_RSA_EMSA_PKCS1_SHA2_512: |
552cc11b | 473 | return build_emsa_pkcs1_signature(this, HASH_SHA512, data, signature); |
40f2589a AS |
474 | case SIGN_RSA_EMSA_PKCS1_SHA3_224: |
475 | return build_emsa_pkcs1_signature(this, HASH_SHA3_224, data, signature); | |
476 | case SIGN_RSA_EMSA_PKCS1_SHA3_256: | |
477 | return build_emsa_pkcs1_signature(this, HASH_SHA3_256, data, signature); | |
478 | case SIGN_RSA_EMSA_PKCS1_SHA3_384: | |
479 | return build_emsa_pkcs1_signature(this, HASH_SHA3_384, data, signature); | |
480 | case SIGN_RSA_EMSA_PKCS1_SHA3_512: | |
481 | return build_emsa_pkcs1_signature(this, HASH_SHA3_512, data, signature); | |
482 | case SIGN_RSA_EMSA_PKCS1_SHA1: | |
483 | return build_emsa_pkcs1_signature(this, HASH_SHA1, data, signature); | |
552cc11b MW |
484 | case SIGN_RSA_EMSA_PKCS1_MD5: |
485 | return build_emsa_pkcs1_signature(this, HASH_MD5, data, signature); | |
154ee7f6 TB |
486 | case SIGN_RSA_EMSA_PSS: |
487 | return build_emsa_pss_signature(this, params, data, signature); | |
552cc11b | 488 | default: |
8b0e0910 | 489 | DBG1(DBG_LIB, "signature scheme %N not supported in RSA", |
552cc11b MW |
490 | signature_scheme_names, scheme); |
491 | return FALSE; | |
492 | } | |
493 | } | |
494 | ||
876b61e1 | 495 | METHOD(private_key_t, decrypt, bool, |
33ddaaab | 496 | private_gmp_rsa_private_key_t *this, encryption_scheme_t scheme, |
4abb29f6 | 497 | void *params, chunk_t crypto, chunk_t *plain) |
552cc11b | 498 | { |
d615ffdc AS |
499 | chunk_t em, stripped; |
500 | bool success = FALSE; | |
7daf5226 | 501 | |
33ddaaab MW |
502 | if (scheme != ENCRYPT_RSA_PKCS1) |
503 | { | |
504 | DBG1(DBG_LIB, "encryption scheme %N not supported", | |
505 | encryption_scheme_names, scheme); | |
506 | return FALSE; | |
507 | } | |
d615ffdc AS |
508 | /* rsa decryption using PKCS#1 RSADP */ |
509 | stripped = em = rsadp(this, crypto); | |
510 | ||
511 | /* PKCS#1 v1.5 8.1 encryption-block formatting (EB = 00 || 02 || PS || 00 || D) */ | |
512 | ||
513 | /* check for hex pattern 00 02 in decrypted message */ | |
514 | if ((*stripped.ptr++ != 0x00) || (*(stripped.ptr++) != 0x02)) | |
515 | { | |
8b0e0910 | 516 | DBG1(DBG_LIB, "incorrect padding - probably wrong rsa key"); |
d615ffdc AS |
517 | goto end; |
518 | } | |
519 | stripped.len -= 2; | |
520 | ||
521 | /* the plaintext data starts after first 0x00 byte */ | |
522 | while (stripped.len-- > 0 && *stripped.ptr++ != 0x00) | |
523 | ||
524 | if (stripped.len == 0) | |
525 | { | |
8b0e0910 | 526 | DBG1(DBG_LIB, "no plaintext data"); |
d615ffdc AS |
527 | goto end; |
528 | } | |
529 | ||
530 | *plain = chunk_clone(stripped); | |
531 | success = TRUE; | |
532 | ||
533 | end: | |
534 | chunk_clear(&em); | |
535 | return success; | |
552cc11b MW |
536 | } |
537 | ||
a944d209 | 538 | METHOD(private_key_t, get_keysize, int, |
876b61e1 | 539 | private_gmp_rsa_private_key_t *this) |
552cc11b | 540 | { |
a944d209 | 541 | return mpz_sizeinbase(this->n, 2); |
552cc11b MW |
542 | } |
543 | ||
876b61e1 MW |
544 | METHOD(private_key_t, get_public_key, public_key_t*, |
545 | private_gmp_rsa_private_key_t *this) | |
552cc11b | 546 | { |
831520d8 MW |
547 | chunk_t n, e; |
548 | public_key_t *public; | |
7daf5226 | 549 | |
831520d8 MW |
550 | n = gmp_mpz_to_chunk(this->n); |
551 | e = gmp_mpz_to_chunk(this->e); | |
7daf5226 | 552 | |
831520d8 MW |
553 | public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, |
554 | BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END); | |
555 | chunk_free(&n); | |
556 | chunk_free(&e); | |
7daf5226 | 557 | |
831520d8 | 558 | return public; |
552cc11b MW |
559 | } |
560 | ||
876b61e1 MW |
561 | METHOD(private_key_t, get_encoding, bool, |
562 | private_gmp_rsa_private_key_t *this, cred_encoding_type_t type, | |
563 | chunk_t *encoding) | |
741680d1 MW |
564 | { |
565 | chunk_t n, e, d, p, q, exp1, exp2, coeff; | |
dd04a68f | 566 | bool success; |
7daf5226 | 567 | |
741680d1 MW |
568 | n = gmp_mpz_to_chunk(this->n); |
569 | e = gmp_mpz_to_chunk(this->e); | |
48b23d06 | 570 | d = gmp_mpz_to_chunk(*this->d); |
741680d1 MW |
571 | p = gmp_mpz_to_chunk(this->p); |
572 | q = gmp_mpz_to_chunk(this->q); | |
573 | exp1 = gmp_mpz_to_chunk(this->exp1); | |
574 | exp2 = gmp_mpz_to_chunk(this->exp2); | |
575 | coeff = gmp_mpz_to_chunk(this->coeff); | |
7daf5226 | 576 | |
741680d1 | 577 | success = lib->encoding->encode(lib->encoding, |
da9724e6 MW |
578 | type, NULL, encoding, CRED_PART_RSA_MODULUS, n, |
579 | CRED_PART_RSA_PUB_EXP, e, CRED_PART_RSA_PRIV_EXP, d, | |
580 | CRED_PART_RSA_PRIME1, p, CRED_PART_RSA_PRIME2, q, | |
581 | CRED_PART_RSA_EXP1, exp1, CRED_PART_RSA_EXP2, exp2, | |
582 | CRED_PART_RSA_COEFF, coeff, CRED_PART_END); | |
741680d1 MW |
583 | chunk_free(&n); |
584 | chunk_free(&e); | |
585 | chunk_clear(&d); | |
586 | chunk_clear(&p); | |
587 | chunk_clear(&q); | |
588 | chunk_clear(&exp1); | |
589 | chunk_clear(&exp2); | |
590 | chunk_clear(&coeff); | |
7daf5226 | 591 | |
741680d1 | 592 | return success; |
552cc11b MW |
593 | } |
594 | ||
876b61e1 MW |
595 | METHOD(private_key_t, get_fingerprint, bool, |
596 | private_gmp_rsa_private_key_t *this, cred_encoding_type_t type, chunk_t *fp) | |
552cc11b | 597 | { |
741680d1 MW |
598 | chunk_t n, e; |
599 | bool success; | |
7daf5226 | 600 | |
741680d1 MW |
601 | if (lib->encoding->get_cache(lib->encoding, type, this, fp)) |
602 | { | |
603 | return TRUE; | |
604 | } | |
605 | n = gmp_mpz_to_chunk(this->n); | |
606 | e = gmp_mpz_to_chunk(this->e); | |
7daf5226 | 607 | |
741680d1 | 608 | success = lib->encoding->encode(lib->encoding, type, this, fp, |
da9724e6 | 609 | CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END); |
741680d1 MW |
610 | chunk_free(&n); |
611 | chunk_free(&e); | |
7daf5226 | 612 | |
741680d1 | 613 | return success; |
552cc11b MW |
614 | } |
615 | ||
876b61e1 MW |
616 | METHOD(private_key_t, get_ref, private_key_t*, |
617 | private_gmp_rsa_private_key_t *this) | |
552cc11b MW |
618 | { |
619 | ref_get(&this->ref); | |
876b61e1 | 620 | return &this->public.key; |
552cc11b MW |
621 | } |
622 | ||
876b61e1 MW |
623 | METHOD(private_key_t, destroy, void, |
624 | private_gmp_rsa_private_key_t *this) | |
552cc11b MW |
625 | { |
626 | if (ref_put(&this->ref)) | |
627 | { | |
48b23d06 AS |
628 | int i; |
629 | ||
630 | mpz_clear(this->n); | |
631 | mpz_clear(this->e); | |
632 | mpz_clear(this->v); | |
741680d1 MW |
633 | mpz_clear_sensitive(this->p); |
634 | mpz_clear_sensitive(this->q); | |
48b23d06 | 635 | mpz_clear_sensitive(this->m); |
741680d1 MW |
636 | mpz_clear_sensitive(this->exp1); |
637 | mpz_clear_sensitive(this->exp2); | |
638 | mpz_clear_sensitive(this->coeff); | |
48b23d06 AS |
639 | |
640 | for (i = 0; i < this->threshold; i++) | |
641 | { | |
642 | mpz_clear_sensitive(*this->d + i); | |
643 | } | |
644 | free(this->d); | |
645 | ||
741680d1 | 646 | lib->encoding->clear_cache(lib->encoding, this); |
552cc11b MW |
647 | free(this); |
648 | } | |
649 | } | |
650 | ||
651 | /** | |
652 | * Check the loaded key if it is valid and usable | |
653 | */ | |
654 | static status_t check(private_gmp_rsa_private_key_t *this) | |
655 | { | |
48b23d06 | 656 | mpz_t u, p1, q1; |
552cc11b | 657 | status_t status = SUCCESS; |
7daf5226 | 658 | |
552cc11b | 659 | /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets. |
1d56d328 TB |
660 | * We actually require more (for security). |
661 | */ | |
8b799d55 | 662 | if (this->k < 512 / BITS_PER_BYTE) |
552cc11b | 663 | { |
8b0e0910 | 664 | DBG1(DBG_LIB, "key shorter than 512 bits"); |
552cc11b MW |
665 | return FAILED; |
666 | } | |
7daf5226 | 667 | |
552cc11b | 668 | /* we picked a max modulus size to simplify buffer allocation */ |
8b799d55 | 669 | if (this->k > 8192 / BITS_PER_BYTE) |
552cc11b | 670 | { |
8b0e0910 | 671 | DBG1(DBG_LIB, "key larger than 8192 bits"); |
552cc11b MW |
672 | return FAILED; |
673 | } | |
7daf5226 | 674 | |
552cc11b | 675 | mpz_init(u); |
48b23d06 | 676 | mpz_init(p1); |
552cc11b | 677 | mpz_init(q1); |
7daf5226 | 678 | |
48b23d06 AS |
679 | /* precompute p1 = p-1 and q1 = q-1 */ |
680 | mpz_sub_ui(p1, this->p, 1); | |
681 | mpz_sub_ui(q1, this->q, 1); | |
682 | ||
552cc11b MW |
683 | /* check that n == p * q */ |
684 | mpz_mul(u, this->p, this->q); | |
685 | if (mpz_cmp(u, this->n) != 0) | |
686 | { | |
687 | status = FAILED; | |
688 | } | |
7daf5226 | 689 | |
552cc11b | 690 | /* check that e divides neither p-1 nor q-1 */ |
48b23d06 AS |
691 | mpz_mod(u, p1, this->e); |
692 | if (mpz_cmp_ui(u, 0) == 0) | |
552cc11b MW |
693 | { |
694 | status = FAILED; | |
695 | } | |
7daf5226 | 696 | |
48b23d06 AS |
697 | mpz_mod(u, q1, this->e); |
698 | if (mpz_cmp_ui(u, 0) == 0) | |
552cc11b MW |
699 | { |
700 | status = FAILED; | |
701 | } | |
7daf5226 | 702 | |
552cc11b MW |
703 | /* check that d is e^-1 (mod lcm(p-1, q-1)) */ |
704 | /* see PKCS#1v2, aka RFC 2437, for the "lcm" */ | |
48b23d06 AS |
705 | mpz_lcm(this->m, p1, q1); |
706 | mpz_mul(u, *this->d, this->e); | |
707 | mpz_mod(u, u, this->m); | |
708 | if (mpz_cmp_ui(u, 1) != 0) | |
552cc11b MW |
709 | { |
710 | status = FAILED; | |
711 | } | |
7daf5226 | 712 | |
552cc11b | 713 | /* check that exp1 is d mod (p-1) */ |
48b23d06 AS |
714 | mpz_mod(u, *this->d, p1); |
715 | if (mpz_cmp(u, this->exp1) != 0) | |
552cc11b MW |
716 | { |
717 | status = FAILED; | |
718 | } | |
7daf5226 | 719 | |
552cc11b | 720 | /* check that exp2 is d mod (q-1) */ |
48b23d06 AS |
721 | mpz_mod(u, *this->d, q1); |
722 | if (mpz_cmp(u, this->exp2) != 0) | |
552cc11b MW |
723 | { |
724 | status = FAILED; | |
725 | } | |
7daf5226 | 726 | |
552cc11b | 727 | /* check that coeff is (q^-1) mod p */ |
48b23d06 AS |
728 | mpz_mul(u, this->coeff, this->q); |
729 | mpz_mod(u, u, this->p); | |
730 | if (mpz_cmp_ui(u, 1) != 0) | |
552cc11b MW |
731 | { |
732 | status = FAILED; | |
733 | } | |
7daf5226 | 734 | |
741680d1 | 735 | mpz_clear_sensitive(u); |
48b23d06 | 736 | mpz_clear_sensitive(p1); |
741680d1 | 737 | mpz_clear_sensitive(q1); |
48b23d06 | 738 | |
552cc11b MW |
739 | if (status != SUCCESS) |
740 | { | |
8b0e0910 | 741 | DBG1(DBG_LIB, "key integrity tests failed"); |
552cc11b MW |
742 | } |
743 | return status; | |
744 | } | |
745 | ||
746 | /** | |
747 | * Internal generic constructor | |
748 | */ | |
749 | static private_gmp_rsa_private_key_t *gmp_rsa_private_key_create_empty(void) | |
750 | { | |
876b61e1 | 751 | private_gmp_rsa_private_key_t *this; |
7daf5226 | 752 | |
876b61e1 | 753 | INIT(this, |
ba31fe1f MW |
754 | .public = { |
755 | .key = { | |
756 | .get_type = _get_type, | |
757 | .sign = _sign, | |
758 | .decrypt = _decrypt, | |
759 | .get_keysize = _get_keysize, | |
760 | .get_public_key = _get_public_key, | |
761 | .equals = private_key_equals, | |
762 | .belongs_to = private_key_belongs_to, | |
763 | .get_fingerprint = _get_fingerprint, | |
764 | .has_fingerprint = private_key_has_fingerprint, | |
765 | .get_encoding = _get_encoding, | |
766 | .get_ref = _get_ref, | |
767 | .destroy = _destroy, | |
768 | }, | |
876b61e1 | 769 | }, |
48b23d06 | 770 | .threshold = 1, |
876b61e1 MW |
771 | .ref = 1, |
772 | ); | |
552cc11b MW |
773 | return this; |
774 | } | |
775 | ||
776 | /** | |
1086d00e | 777 | * See header. |
552cc11b | 778 | */ |
1086d00e | 779 | gmp_rsa_private_key_t *gmp_rsa_private_key_gen(key_type_t type, va_list args) |
552cc11b | 780 | { |
1086d00e | 781 | private_gmp_rsa_private_key_t *this; |
e36af6fc AS |
782 | drbg_type_t drbg_type = DRBG_HMAC_SHA512; |
783 | drbg_t* drbg; | |
784 | rng_t *rng; | |
785 | u_int strength = 256, key_size = 0, shares = 0, threshold = 1; | |
786 | bool safe_prime = FALSE, drbg_failed = FALSE, invert_failed = FALSE; | |
787 | mpz_t p, q, p1, q1; | |
788 | int i; | |
789 | ||
7daf5226 | 790 | |
1086d00e MW |
791 | while (TRUE) |
792 | { | |
793 | switch (va_arg(args, builder_part_t)) | |
794 | { | |
795 | case BUILD_KEY_SIZE: | |
796 | key_size = va_arg(args, u_int); | |
797 | continue; | |
168ee460 AS |
798 | case BUILD_SAFE_PRIMES: |
799 | safe_prime = TRUE; | |
800 | continue; | |
48b23d06 AS |
801 | case BUILD_SHARES: |
802 | shares = va_arg(args, u_int); | |
803 | continue; | |
804 | case BUILD_THRESHOLD: | |
805 | threshold = va_arg(args, u_int); | |
806 | continue; | |
1086d00e MW |
807 | case BUILD_END: |
808 | break; | |
809 | default: | |
810 | return NULL; | |
811 | } | |
812 | break; | |
813 | } | |
814 | if (!key_size) | |
815 | { | |
816 | return NULL; | |
817 | } | |
8b799d55 | 818 | key_size = key_size / BITS_PER_BYTE; |
7daf5226 | 819 | |
11e9d2b8 | 820 | /* Initiate a NIST SP 800-90A DRBG fed by a true rng owned by the drbg */ |
e36af6fc AS |
821 | rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE); |
822 | if (!rng) | |
823 | { | |
824 | DBG1(DBG_LIB, "no RNG of quality %N found", rng_quality_names, RNG_TRUE); | |
825 | return NULL; | |
826 | } | |
827 | drbg = lib->crypto->create_drbg(lib->crypto, drbg_type, strength, rng, | |
828 | chunk_empty); | |
829 | if (!drbg) | |
830 | { | |
831 | DBG1(DBG_LIB, "instantiation of %N failed", drbg_type_names, drbg_type); | |
832 | rng->destroy(rng); | |
833 | return NULL; | |
834 | } | |
835 | ||
552cc11b | 836 | /* Get values of primes p and q */ |
e36af6fc | 837 | if (compute_prime(drbg, key_size/2, safe_prime, &p, &p1) != SUCCESS) |
552cc11b | 838 | { |
e36af6fc | 839 | drbg->destroy(drbg); |
552cc11b | 840 | return NULL; |
7daf5226 | 841 | } |
e36af6fc | 842 | if (compute_prime(drbg, key_size/2, safe_prime, &q, &q1) != SUCCESS) |
552cc11b MW |
843 | { |
844 | mpz_clear(p); | |
48b23d06 | 845 | mpz_clear(p1); |
e36af6fc | 846 | drbg->destroy(drbg); |
552cc11b MW |
847 | return NULL; |
848 | } | |
7daf5226 | 849 | |
552cc11b MW |
850 | /* Swapping Primes so p is larger then q */ |
851 | if (mpz_cmp(p, q) < 0) | |
852 | { | |
853 | mpz_swap(p, q); | |
48b23d06 | 854 | mpz_swap(p1, q1); |
552cc11b | 855 | } |
7daf5226 | 856 | |
48b23d06 AS |
857 | /* Create and initialize RSA private key object */ |
858 | this = gmp_rsa_private_key_create_empty(); | |
e36af6fc AS |
859 | *this->p = *p; |
860 | *this->q = *q; | |
861 | ||
862 | /* allocate space for private exponent d with optional threshold scheme */ | |
48b23d06 AS |
863 | this->shares = shares; |
864 | this->threshold = threshold; | |
865 | this->d = malloc(threshold * sizeof(mpz_t)); | |
e36af6fc AS |
866 | for (i = 0; i < threshold; i++) |
867 | { | |
868 | mpz_init(this->d[i]); | |
869 | } | |
552cc11b | 870 | |
48b23d06 AS |
871 | mpz_init_set_ui(this->e, PUBLIC_EXPONENT); |
872 | mpz_init(this->n); | |
873 | mpz_init(this->m); | |
874 | mpz_init(this->exp1); | |
875 | mpz_init(this->exp2); | |
876 | mpz_init(this->coeff); | |
877 | mpz_init(this->v); | |
48b23d06 | 878 | |
e36af6fc AS |
879 | mpz_mul(this->n, p, q); /* n = p*q */ |
880 | mpz_lcm(this->m, p1, q1); /* m = lcm(p-1,q-1) */ | |
881 | mpz_invert(this->d[0], this->e, this->m); /* e has an inverse mod m */ | |
882 | mpz_mod(this->exp1, this->d[0], p1); /* exp1 = d mod p-1 */ | |
883 | mpz_mod(this->exp2, this->d[0], q1); /* exp2 = d mod q-1 */ | |
884 | mpz_invert(this->coeff, q, p); /* coeff = q^-1 mod p */ | |
48b23d06 AS |
885 | |
886 | invert_failed = mpz_cmp_ui(this->m, 0) == 0 || | |
887 | mpz_cmp_ui(this->coeff, 0) == 0; | |
7daf5226 | 888 | |
48b23d06 AS |
889 | /* generate and store random coefficients of secret sharing polynomial */ |
890 | if (threshold > 1) | |
552cc11b | 891 | { |
48b23d06 AS |
892 | chunk_t random_bytes; |
893 | mpz_t u; | |
48b23d06 | 894 | |
48b23d06 | 895 | mpz_init(u); |
e36af6fc | 896 | random_bytes = chunk_alloc(key_size); |
48b23d06 AS |
897 | |
898 | for (i = 1; i < threshold; i++) | |
899 | { | |
e36af6fc | 900 | if (!drbg->generate(drbg, random_bytes.len, random_bytes.ptr)) |
48b23d06 | 901 | { |
e36af6fc | 902 | drbg_failed = TRUE; |
48b23d06 AS |
903 | continue; |
904 | } | |
e36af6fc AS |
905 | mpz_import(this->d[i], random_bytes.len, 1, 1, 1, 0, random_bytes.ptr); |
906 | mpz_mod(this->d[i], this->d[i], this->m); | |
48b23d06 AS |
907 | } |
908 | ||
909 | /* generate verification key v as a square number */ | |
910 | do | |
911 | { | |
e36af6fc | 912 | if (!drbg->generate(drbg, random_bytes.len, random_bytes.ptr)) |
48b23d06 | 913 | { |
e36af6fc | 914 | drbg_failed = TRUE; |
48b23d06 AS |
915 | break; |
916 | } | |
917 | mpz_import(this->v, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr); | |
918 | mpz_mul(this->v, this->v, this->v); | |
919 | mpz_mod(this->v, this->v, this->n); | |
920 | mpz_gcd(u, this->v, this->n); | |
48b23d06 AS |
921 | } |
922 | while (mpz_cmp_ui(u, 1) != 0); | |
923 | ||
924 | mpz_clear(u); | |
e36af6fc | 925 | chunk_clear(&random_bytes); |
552cc11b MW |
926 | } |
927 | ||
48b23d06 | 928 | mpz_clear_sensitive(p1); |
741680d1 | 929 | mpz_clear_sensitive(q1); |
e36af6fc | 930 | drbg->destroy(drbg); |
552cc11b | 931 | |
e36af6fc | 932 | if (drbg_failed || invert_failed) |
48b23d06 AS |
933 | { |
934 | DBG1(DBG_LIB, "rsa key generation failed"); | |
935 | destroy(this); | |
936 | return NULL; | |
937 | } | |
7daf5226 | 938 | |
552cc11b MW |
939 | /* set key size in bytes */ |
940 | this->k = key_size; | |
7daf5226 | 941 | |
552cc11b MW |
942 | return &this->public; |
943 | } | |
944 | ||
bd4df68a TB |
945 | /** |
946 | * Recover the primes from n, e and d using the algorithm described in | |
947 | * Appendix C of NIST SP 800-56B. | |
948 | */ | |
949 | static bool calculate_pq(private_gmp_rsa_private_key_t *this) | |
950 | { | |
951 | gmp_randstate_t rstate; | |
952 | mpz_t k, r, g, y, n1, x; | |
953 | int i, t, j; | |
954 | bool success = FALSE; | |
955 | ||
956 | gmp_randinit_default(rstate); | |
4a84fb07 TB |
957 | mpz_init(k); |
958 | mpz_init(r); | |
959 | mpz_init(g); | |
960 | mpz_init(y); | |
961 | mpz_init(n1); | |
962 | mpz_init(x); | |
bd4df68a TB |
963 | /* k = (d * e) - 1 */ |
964 | mpz_mul(k, *this->d, this->e); | |
965 | mpz_sub_ui(k, k, 1); | |
966 | if (mpz_odd_p(k)) | |
967 | { | |
968 | goto error; | |
969 | } | |
970 | /* k = 2^t * r, where r is the largest odd integer dividing k, and t >= 1 */ | |
971 | mpz_set(r, k); | |
972 | for (t = 0; !mpz_odd_p(r); t++) | |
973 | { /* r = r/2 */ | |
974 | mpz_divexact_ui(r, r, 2); | |
975 | } | |
976 | /* we need n-1 below */ | |
977 | mpz_sub_ui(n1, this->n, 1); | |
978 | for (i = 0; i < 100; i++) | |
979 | { /* generate random integer g in [0, n-1] */ | |
980 | mpz_urandomm(g, rstate, this->n); | |
981 | /* y = g^r mod n */ | |
4a84fb07 | 982 | mpz_powm(y, g, r, this->n); |
bd4df68a TB |
983 | /* try again if y == 1 or y == n-1 */ |
984 | if (mpz_cmp_ui(y, 1) == 0 || mpz_cmp(y, n1) == 0) | |
985 | { | |
986 | continue; | |
987 | } | |
988 | for (j = 0; j < t; j++) | |
989 | { /* x = y^2 mod n */ | |
990 | mpz_powm_ui(x, y, 2, this->n); | |
991 | /* stop if x == 1 */ | |
992 | if (mpz_cmp_ui(x, 1) == 0) | |
993 | { | |
994 | goto done; | |
995 | } | |
996 | /* retry with new g if x = n-1 */ | |
997 | if (mpz_cmp(x, n1) == 0) | |
998 | { | |
999 | break; | |
1000 | } | |
1001 | /* y = x */ | |
1002 | mpz_set(y, x); | |
1003 | } | |
1004 | } | |
1005 | goto error; | |
1006 | ||
1007 | done: | |
1008 | /* p = gcd(y-1, n) */ | |
1009 | mpz_sub_ui(y, y, 1); | |
1010 | mpz_gcd(this->p, y, this->n); | |
1011 | /* q = n/p */ | |
1012 | mpz_divexact(this->q, this->n, this->p); | |
1013 | success = TRUE; | |
1014 | ||
1015 | error: | |
1016 | mpz_clear_sensitive(k); | |
1017 | mpz_clear_sensitive(r); | |
1018 | mpz_clear_sensitive(g); | |
1019 | mpz_clear_sensitive(y); | |
1020 | mpz_clear_sensitive(x); | |
1021 | mpz_clear(n1); | |
1022 | gmp_randclear(rstate); | |
1023 | return success; | |
1024 | } | |
1025 | ||
460025e2 | 1026 | /** |
1086d00e | 1027 | * See header. |
552cc11b | 1028 | */ |
1086d00e | 1029 | gmp_rsa_private_key_t *gmp_rsa_private_key_load(key_type_t type, va_list args) |
552cc11b | 1030 | { |
1086d00e | 1031 | private_gmp_rsa_private_key_t *this; |
48b23d06 | 1032 | chunk_t n, e, d, p, q, exp1, exp2, coeff; |
1086d00e MW |
1033 | |
1034 | n = e = d = p = q = exp1 = exp2 = coeff = chunk_empty; | |
1035 | while (TRUE) | |
1036 | { | |
1037 | switch (va_arg(args, builder_part_t)) | |
1038 | { | |
1039 | case BUILD_RSA_MODULUS: | |
1040 | n = va_arg(args, chunk_t); | |
1041 | continue; | |
1042 | case BUILD_RSA_PUB_EXP: | |
1043 | e = va_arg(args, chunk_t); | |
1044 | continue; | |
1045 | case BUILD_RSA_PRIV_EXP: | |
1046 | d = va_arg(args, chunk_t); | |
1047 | continue; | |
1048 | case BUILD_RSA_PRIME1: | |
1049 | p = va_arg(args, chunk_t); | |
1050 | continue; | |
1051 | case BUILD_RSA_PRIME2: | |
1052 | q = va_arg(args, chunk_t); | |
1053 | continue; | |
1054 | case BUILD_RSA_EXP1: | |
1055 | exp1 = va_arg(args, chunk_t); | |
1056 | continue; | |
1057 | case BUILD_RSA_EXP2: | |
1058 | exp2 = va_arg(args, chunk_t); | |
1059 | continue; | |
1060 | case BUILD_RSA_COEFF: | |
1061 | coeff = va_arg(args, chunk_t); | |
1062 | continue; | |
1063 | case BUILD_END: | |
1064 | break; | |
1065 | default: | |
1066 | return NULL; | |
1067 | } | |
1068 | break; | |
1069 | } | |
1070 | ||
1071 | this = gmp_rsa_private_key_create_empty(); | |
7daf5226 | 1072 | |
48b23d06 | 1073 | this->d = malloc(sizeof(mpz_t)); |
552cc11b MW |
1074 | mpz_init(this->n); |
1075 | mpz_init(this->e); | |
48b23d06 | 1076 | mpz_init(*this->d); |
552cc11b MW |
1077 | mpz_init(this->p); |
1078 | mpz_init(this->q); | |
48b23d06 | 1079 | mpz_init(this->m); |
552cc11b MW |
1080 | mpz_init(this->exp1); |
1081 | mpz_init(this->exp2); | |
1082 | mpz_init(this->coeff); | |
48b23d06 | 1083 | mpz_init(this->v); |
7daf5226 | 1084 | |
7033a70f MW |
1085 | mpz_import(this->n, n.len, 1, 1, 1, 0, n.ptr); |
1086 | mpz_import(this->e, e.len, 1, 1, 1, 0, e.ptr); | |
48b23d06 | 1087 | mpz_import(*this->d, d.len, 1, 1, 1, 0, d.ptr); |
bd4df68a TB |
1088 | if (p.len) |
1089 | { | |
1090 | mpz_import(this->p, p.len, 1, 1, 1, 0, p.ptr); | |
1091 | } | |
1092 | if (q.len) | |
1093 | { | |
1094 | mpz_import(this->q, q.len, 1, 1, 1, 0, q.ptr); | |
1095 | } | |
1096 | if (!p.len && !q.len) | |
1097 | { /* p and q missing in key, recalculate from n, e and d */ | |
1098 | if (!calculate_pq(this)) | |
1099 | { | |
1100 | destroy(this); | |
1101 | return NULL; | |
1102 | } | |
1103 | } | |
1104 | else if (!p.len) | |
1105 | { /* p missing in key, recalculate: p = n / q */ | |
1106 | mpz_divexact(this->p, this->n, this->q); | |
1107 | } | |
1108 | else if (!q.len) | |
1109 | { /* q missing in key, recalculate: q = n / p */ | |
1110 | mpz_divexact(this->q, this->n, this->p); | |
1111 | } | |
7033a70f MW |
1112 | if (!exp1.len) |
1113 | { /* exp1 missing in key, recalculate: exp1 = d mod (p-1) */ | |
1114 | mpz_sub_ui(this->exp1, this->p, 1); | |
48b23d06 | 1115 | mpz_mod(this->exp1, *this->d, this->exp1); |
552cc11b | 1116 | } |
7033a70f | 1117 | else |
d3d7e46b | 1118 | { |
7033a70f | 1119 | mpz_import(this->exp1, exp1.len, 1, 1, 1, 0, exp1.ptr); |
d3d7e46b | 1120 | } |
7033a70f MW |
1121 | if (!exp2.len) |
1122 | { /* exp2 missing in key, recalculate: exp2 = d mod (q-1) */ | |
1123 | mpz_sub_ui(this->exp2, this->q, 1); | |
48b23d06 | 1124 | mpz_mod(this->exp2, *this->d, this->exp2); |
8b799d55 | 1125 | } |
7033a70f | 1126 | else |
8b799d55 | 1127 | { |
7033a70f | 1128 | mpz_import(this->exp2, exp2.len, 1, 1, 1, 0, exp2.ptr); |
8b799d55 | 1129 | } |
bd4df68a TB |
1130 | if (!coeff.len) |
1131 | { /* coeff missing in key, recalculate: coeff = q^-1 mod p */ | |
1132 | mpz_invert(this->coeff, this->q, this->p); | |
1133 | } | |
1134 | else | |
1135 | { | |
1136 | mpz_import(this->coeff, coeff.len, 1, 1, 1, 0, coeff.ptr); | |
1137 | } | |
8b799d55 | 1138 | this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE; |
552cc11b MW |
1139 | if (check(this) != SUCCESS) |
1140 | { | |
1141 | destroy(this); | |
1142 | return NULL; | |
1143 | } | |
1144 | return &this->public; | |
1145 | } |