/src/samba/third_party/heimdal/lib/hcrypto/rsa-ltm.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2006 - 2007, 2010 Kungliga Tekniska Högskolan |
3 | | * (Royal Institute of Technology, Stockholm, Sweden). |
4 | | * All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * |
10 | | * 1. Redistributions of source code must retain the above copyright |
11 | | * notice, this list of conditions and the following disclaimer. |
12 | | * |
13 | | * 2. Redistributions in binary form must reproduce the above copyright |
14 | | * notice, this list of conditions and the following disclaimer in the |
15 | | * documentation and/or other materials provided with the distribution. |
16 | | * |
17 | | * 3. Neither the name of the Institute nor the names of its contributors |
18 | | * may be used to endorse or promote products derived from this software |
19 | | * without specific prior written permission. |
20 | | * |
21 | | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND |
22 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE |
25 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
27 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
28 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
29 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
30 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
31 | | * SUCH DAMAGE. |
32 | | */ |
33 | | |
34 | | #include <config.h> |
35 | | #include <roken.h> |
36 | | #include <krb5-types.h> |
37 | | #include <assert.h> |
38 | | |
39 | | #include <rsa.h> |
40 | | |
41 | | #include "tommath.h" |
42 | | |
43 | | #define CHECK(f) \ |
44 | | do { where = __LINE__ + 1; if (ret == MP_OKAY && ((ret = f)) != MP_OKAY) { goto out; } } while (0) |
45 | 0 | #define FIRST(e) do { ret = (e); } while (0) |
46 | | #define FIRST_ALLOC(e) \ |
47 | | do { where = __LINE__; ret = ((e)) ? MP_OKAY : MP_MEM; } while (0) |
48 | | #define THEN_MP(e) \ |
49 | 0 | do { where = __LINE__ + 1; if (ret == MP_OKAY) ret = (e); } while (0) |
50 | | #define THEN_IF_MP(cond, e) \ |
51 | 0 | do { where = __LINE__ + 1; if (ret == MP_OKAY && (cond)) ret = (e); } while (0) |
52 | | #define THEN_IF_VOID(cond, e) \ |
53 | | do { where = __LINE__ + 1; if (ret == MP_OKAY && (cond)) e; } while (0) |
54 | | #define THEN_VOID(e) \ |
55 | 0 | do { where = __LINE__ + 1; if (ret == MP_OKAY) e; } while (0) |
56 | | #define THEN_ALLOC(e) \ |
57 | 0 | do { where = __LINE__ + 1; if (ret == MP_OKAY) ret = ((e)) ? MP_OKAY : MP_MEM; } while (0) |
58 | | |
59 | | static mp_err |
60 | | random_num(mp_int *num, size_t len) |
61 | 0 | { |
62 | 0 | unsigned char *p; |
63 | 0 | mp_err ret = MP_MEM; |
64 | |
|
65 | 0 | len = (len + 7) / 8; /* bits to bytes */ |
66 | 0 | if ((p = malloc(len)) && RAND_bytes(p, len) != 1) |
67 | 0 | ret = MP_ERR; |
68 | 0 | if (p) |
69 | 0 | ret = mp_from_ubin(num, p, len); |
70 | 0 | free(p); |
71 | 0 | return ret; |
72 | 0 | } |
73 | | |
74 | | static mp_err |
75 | | BN2mpz(mp_int *s, const BIGNUM *bn) |
76 | 0 | { |
77 | 0 | size_t len; |
78 | 0 | mp_err ret = MP_MEM; |
79 | 0 | void *p; |
80 | |
|
81 | 0 | len = BN_num_bytes(bn); |
82 | 0 | p = malloc(len); |
83 | 0 | if (p) { |
84 | 0 | BN_bn2bin(bn, p); |
85 | 0 | ret = mp_from_ubin(s, p, len); |
86 | 0 | } |
87 | 0 | free(p); |
88 | 0 | return ret; |
89 | 0 | } |
90 | | |
91 | | static mp_err |
92 | | setup_blind(mp_int *n, mp_int *b, mp_int *bi) |
93 | 0 | { |
94 | 0 | mp_err ret; |
95 | |
|
96 | 0 | ret = random_num(b, mp_count_bits(n)); |
97 | 0 | if (ret == MP_OKAY) ret = mp_mod(b, n, b); |
98 | 0 | if (ret == MP_OKAY) ret = mp_invmod(b, n, bi); |
99 | 0 | return ret; |
100 | 0 | } |
101 | | |
102 | | static mp_err |
103 | | blind(mp_int *in, mp_int *b, mp_int *e, mp_int *n) |
104 | 0 | { |
105 | 0 | mp_err ret; |
106 | 0 | mp_int t1; |
107 | |
|
108 | 0 | ret = mp_init(&t1); |
109 | | /* in' = (in * b^e) mod n */ |
110 | 0 | if (ret == MP_OKAY) ret = mp_exptmod(b, e, n, &t1); |
111 | 0 | if (ret == MP_OKAY) ret = mp_mul(&t1, in, in); |
112 | 0 | if (ret == MP_OKAY) ret = mp_mod(in, n, in); |
113 | 0 | mp_clear(&t1); |
114 | 0 | return ret; |
115 | 0 | } |
116 | | |
117 | | static mp_err |
118 | | unblind(mp_int *out, mp_int *bi, mp_int *n) |
119 | 0 | { |
120 | 0 | mp_err ret; |
121 | | |
122 | | /* out' = (out * 1/b) mod n */ |
123 | 0 | ret = mp_mul(out, bi, out); |
124 | 0 | if (ret == MP_OKAY) ret = mp_mod(out, n, out); |
125 | 0 | return ret; |
126 | 0 | } |
127 | | |
128 | | static mp_err |
129 | | ltm_rsa_private_calculate(mp_int * in, mp_int * p, mp_int * q, |
130 | | mp_int * dmp1, mp_int * dmq1, mp_int * iqmp, |
131 | | mp_int * out) |
132 | 0 | { |
133 | 0 | mp_err ret; |
134 | 0 | mp_int vp, vq, u; |
135 | 0 | int where HEIMDAL_UNUSED_ATTRIBUTE = 0; |
136 | |
|
137 | 0 | FIRST(mp_init_multi(&vp, &vq, &u, NULL)); |
138 | | |
139 | | /* vq = c ^ (d mod (q - 1)) mod q */ |
140 | | /* vp = c ^ (d mod (p - 1)) mod p */ |
141 | 0 | THEN_MP(mp_mod(in, p, &u)); |
142 | 0 | THEN_MP(mp_exptmod(&u, dmp1, p, &vp)); |
143 | 0 | THEN_MP(mp_mod(in, q, &u)); |
144 | 0 | THEN_MP(mp_exptmod(&u, dmq1, q, &vq)); |
145 | | |
146 | | /* C2 = 1/q mod p (iqmp) */ |
147 | | /* u = (vp - vq)C2 mod p. */ |
148 | 0 | THEN_MP(mp_sub(&vp, &vq, &u)); |
149 | 0 | THEN_IF_MP(mp_isneg(&u), mp_add(&u, p, &u)); |
150 | 0 | THEN_MP(mp_mul(&u, iqmp, &u)); |
151 | 0 | THEN_MP(mp_mod(&u, p, &u)); |
152 | | |
153 | | /* c ^ d mod n = vq + u q */ |
154 | 0 | THEN_MP(mp_mul(&u, q, &u)); |
155 | 0 | THEN_MP(mp_add(&u, &vq, out)); |
156 | |
|
157 | 0 | mp_clear_multi(&vp, &vq, &u, NULL); |
158 | 0 | return ret; |
159 | 0 | } |
160 | | |
161 | | /* |
162 | | * |
163 | | */ |
164 | | |
165 | | static int |
166 | | ltm_rsa_public_encrypt(int flen, const unsigned char* from, |
167 | | unsigned char* to, RSA* rsa, int padding) |
168 | 0 | { |
169 | 0 | unsigned char *p = NULL, *p0 = NULL; |
170 | 0 | size_t size, ssize = 0, padlen; |
171 | 0 | mp_int enc, dec, n, e; |
172 | 0 | mp_err ret; |
173 | 0 | int where = __LINE__; |
174 | |
|
175 | 0 | if (padding != RSA_PKCS1_PADDING) |
176 | 0 | return -1; |
177 | | |
178 | 0 | FIRST(mp_init_multi(&n, &e, &enc, &dec, NULL)); |
179 | |
|
180 | 0 | size = RSA_size(rsa); |
181 | 0 | THEN_IF_MP((size < RSA_PKCS1_PADDING_SIZE || |
182 | 0 | size - RSA_PKCS1_PADDING_SIZE < flen), |
183 | 0 | MP_ERR); |
184 | 0 | THEN_MP(BN2mpz(&n, rsa->n)); |
185 | 0 | THEN_MP(BN2mpz(&e, rsa->e)); |
186 | 0 | THEN_IF_MP((mp_cmp_d(&e, 3) == MP_LT), MP_ERR); |
187 | 0 | THEN_ALLOC((p = p0 = malloc(size - 1))); |
188 | |
|
189 | 0 | if (ret == MP_OKAY) { |
190 | 0 | padlen = size - flen - 3; |
191 | 0 | *p++ = 2; |
192 | 0 | } |
193 | 0 | THEN_IF_MP((RAND_bytes(p, padlen) != 1), MP_ERR); |
194 | |
|
195 | 0 | if (ret == MP_OKAY) { |
196 | 0 | while (padlen) { |
197 | 0 | if (*p == 0) |
198 | 0 | *p = 1; |
199 | 0 | padlen--; |
200 | 0 | p++; |
201 | 0 | } |
202 | 0 | *p++ = 0; |
203 | 0 | memcpy(p, from, flen); |
204 | 0 | p += flen; |
205 | 0 | assert((p - p0) == size - 1); |
206 | 0 | } |
207 | |
|
208 | 0 | THEN_MP(mp_from_ubin(&dec, p0, size - 1)); |
209 | 0 | THEN_MP(mp_exptmod(&dec, &e, &n, &enc)); |
210 | 0 | THEN_VOID(ssize = mp_ubin_size(&enc)); |
211 | 0 | THEN_VOID(assert(size >= ssize)); |
212 | 0 | THEN_MP(mp_to_ubin(&enc, to, SIZE_MAX, NULL)); |
213 | 0 | THEN_VOID(size = ssize); |
214 | |
|
215 | 0 | mp_clear_multi(&dec, &e, &n, NULL); |
216 | 0 | mp_clear(&enc); |
217 | 0 | free(p0); |
218 | 0 | return ret == MP_OKAY ? size : -where; |
219 | 0 | } |
220 | | |
221 | | static int |
222 | | ltm_rsa_public_decrypt(int flen, const unsigned char* from, |
223 | | unsigned char* to, RSA* rsa, int padding) |
224 | 0 | { |
225 | 0 | unsigned char *p = NULL; |
226 | 0 | mp_err ret; |
227 | 0 | size_t size = 0; |
228 | 0 | mp_int s, us, n, e; |
229 | 0 | int where = __LINE__; |
230 | |
|
231 | 0 | if (padding != RSA_PKCS1_PADDING) |
232 | 0 | return -1; |
233 | | |
234 | 0 | if (flen > RSA_size(rsa)) |
235 | 0 | return -2; |
236 | | |
237 | 0 | FIRST(mp_init_multi(&e, &n, &s, &us, NULL)); |
238 | 0 | THEN_MP(BN2mpz(&n, rsa->n)); |
239 | 0 | THEN_MP(BN2mpz(&e, rsa->e)); |
240 | 0 | THEN_MP((mp_cmp_d(&e, 3) == MP_LT) ? MP_ERR : MP_OKAY); |
241 | 0 | THEN_MP(mp_from_ubin(&s, rk_UNCONST(from), (size_t)flen)); |
242 | 0 | THEN_MP((mp_cmp(&s, &n) >= 0) ? MP_ERR : MP_OKAY); |
243 | 0 | THEN_MP(mp_exptmod(&s, &e, &n, &us)); |
244 | |
|
245 | 0 | THEN_VOID(p = to); |
246 | 0 | THEN_VOID(size = mp_ubin_size(&us)); |
247 | 0 | THEN_VOID(assert(size <= RSA_size(rsa))); |
248 | 0 | THEN_MP(mp_to_ubin(&us, p, SIZE_MAX, NULL)); |
249 | |
|
250 | 0 | mp_clear_multi(&e, &n, &s, NULL); |
251 | 0 | mp_clear(&us); |
252 | |
|
253 | 0 | if (ret != MP_OKAY || size == 0) |
254 | 0 | return -where; |
255 | | |
256 | | /* head zero was skipped by mp_to_unsigned_bin */ |
257 | 0 | if (*p == 0) |
258 | 0 | return -where; |
259 | 0 | if (*p != 1) |
260 | 0 | return -(where + 1); |
261 | 0 | size--; p++; |
262 | 0 | while (size && *p == 0xff) { |
263 | 0 | size--; p++; |
264 | 0 | } |
265 | 0 | if (size == 0 || *p != 0) |
266 | 0 | return -(where + 2); |
267 | 0 | size--; p++; |
268 | 0 | memmove(to, p, size); |
269 | 0 | return size; |
270 | 0 | } |
271 | | |
272 | | static int |
273 | | ltm_rsa_private_encrypt(int flen, const unsigned char* from, |
274 | | unsigned char* to, RSA* rsa, int padding) |
275 | 0 | { |
276 | 0 | unsigned char *ptr = NULL, *ptr0 = NULL; |
277 | 0 | mp_err ret; |
278 | 0 | mp_int in, out, n, e; |
279 | 0 | mp_int bi, b; |
280 | 0 | size_t size; |
281 | 0 | int blinding = (rsa->flags & RSA_FLAG_NO_BLINDING) == 0; |
282 | 0 | int do_unblind = 0; |
283 | 0 | int where = __LINE__; |
284 | |
|
285 | 0 | if (padding != RSA_PKCS1_PADDING) |
286 | 0 | return -1; |
287 | | |
288 | 0 | FIRST(mp_init_multi(&e, &n, &in, &out, &b, &bi, NULL)); |
289 | |
|
290 | 0 | size = RSA_size(rsa); |
291 | 0 | if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen) |
292 | 0 | return -2; |
293 | | |
294 | 0 | THEN_ALLOC((ptr0 = ptr = malloc(size))); |
295 | 0 | if (ret == MP_OKAY) { |
296 | 0 | *ptr++ = 0; |
297 | 0 | *ptr++ = 1; |
298 | 0 | memset(ptr, 0xff, size - flen - 3); |
299 | 0 | ptr += size - flen - 3; |
300 | 0 | *ptr++ = 0; |
301 | 0 | memcpy(ptr, from, flen); |
302 | 0 | ptr += flen; |
303 | 0 | assert((ptr - ptr0) == size); |
304 | 0 | } |
305 | |
|
306 | 0 | THEN_MP(BN2mpz(&n, rsa->n)); |
307 | 0 | THEN_MP(BN2mpz(&e, rsa->e)); |
308 | 0 | THEN_IF_MP((mp_cmp_d(&e, 3) == MP_LT), MP_ERR); |
309 | 0 | THEN_MP(mp_from_ubin(&in, ptr0, size)); |
310 | 0 | free(ptr0); |
311 | |
|
312 | 0 | THEN_IF_MP((mp_isneg(&in) || mp_cmp(&in, &n) >= 0), MP_ERR); |
313 | |
|
314 | 0 | if (blinding) { |
315 | 0 | THEN_MP(setup_blind(&n, &b, &bi)); |
316 | 0 | THEN_MP(blind(&in, &b, &e, &n)); |
317 | 0 | do_unblind = 1; |
318 | 0 | } |
319 | |
|
320 | 0 | if (ret == MP_OKAY && rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && |
321 | 0 | rsa->iqmp) { |
322 | 0 | mp_int p, q, dmp1, dmq1, iqmp; |
323 | |
|
324 | 0 | FIRST(mp_init_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL)); |
325 | 0 | THEN_MP(BN2mpz(&p, rsa->p)); |
326 | 0 | THEN_MP(BN2mpz(&q, rsa->q)); |
327 | 0 | THEN_MP(BN2mpz(&dmp1, rsa->dmp1)); |
328 | 0 | THEN_MP(BN2mpz(&dmq1, rsa->dmq1)); |
329 | 0 | THEN_MP(BN2mpz(&iqmp, rsa->iqmp)); |
330 | 0 | THEN_MP(ltm_rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, |
331 | 0 | &out)); |
332 | 0 | mp_clear_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); |
333 | 0 | if (ret != MP_OKAY) goto out; |
334 | 0 | } else if (ret == MP_OKAY) { |
335 | 0 | mp_int d; |
336 | |
|
337 | 0 | THEN_MP(BN2mpz(&d, rsa->d)); |
338 | 0 | THEN_MP(mp_exptmod(&in, &d, &n, &out)); |
339 | 0 | mp_clear(&d); |
340 | 0 | if (ret != MP_OKAY) goto out; |
341 | 0 | } |
342 | | |
343 | 0 | if (do_unblind) |
344 | 0 | THEN_MP(unblind(&out, &bi, &n)); |
345 | |
|
346 | 0 | if (ret == MP_OKAY && size > 0) { |
347 | 0 | size_t ssize; |
348 | |
|
349 | 0 | ssize = mp_ubin_size(&out); |
350 | 0 | assert(size >= ssize); |
351 | 0 | THEN_MP(mp_to_ubin(&out, to, SIZE_MAX, NULL)); |
352 | 0 | size = ssize; |
353 | 0 | } |
354 | |
|
355 | 0 | out: |
356 | 0 | mp_clear_multi(&e, &n, &in, &out, &b, &bi, NULL); |
357 | 0 | return ret == MP_OKAY ? size : -where; |
358 | 0 | } |
359 | | |
360 | | static int |
361 | | ltm_rsa_private_decrypt(int flen, const unsigned char* from, |
362 | | unsigned char* to, RSA* rsa, int padding) |
363 | 0 | { |
364 | 0 | unsigned char *ptr; |
365 | 0 | size_t size; |
366 | 0 | mp_err ret; |
367 | 0 | mp_int in, out, n, e, b, bi; |
368 | 0 | int blinding = (rsa->flags & RSA_FLAG_NO_BLINDING) == 0; |
369 | 0 | int do_unblind = 0; |
370 | 0 | int where = __LINE__; |
371 | |
|
372 | 0 | if (padding != RSA_PKCS1_PADDING) |
373 | 0 | return -1; |
374 | | |
375 | 0 | size = RSA_size(rsa); |
376 | 0 | if (flen > size) |
377 | 0 | return -2; |
378 | | |
379 | 0 | FIRST(mp_init_multi(&in, &n, &e, &out, &b, &bi, NULL)); |
380 | 0 | THEN_MP(BN2mpz(&n, rsa->n)); |
381 | 0 | THEN_MP(BN2mpz(&e, rsa->e)); |
382 | 0 | THEN_IF_MP((mp_cmp_d(&e, 3) == MP_LT), MP_ERR); |
383 | 0 | THEN_MP(mp_from_ubin(&in, rk_UNCONST(from), flen)); |
384 | 0 | THEN_IF_MP((mp_isneg(&in) || mp_cmp(&in, &n) >= 0), MP_ERR); |
385 | |
|
386 | 0 | if (blinding) { |
387 | 0 | THEN_MP(setup_blind(&n, &b, &bi)); |
388 | 0 | THEN_MP(blind(&in, &b, &e, &n)); |
389 | 0 | do_unblind = 1; |
390 | 0 | } |
391 | |
|
392 | 0 | if (ret == MP_OKAY && rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && |
393 | 0 | rsa->iqmp) { |
394 | 0 | mp_int p, q, dmp1, dmq1, iqmp; |
395 | |
|
396 | 0 | THEN_MP(mp_init_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL)); |
397 | 0 | THEN_MP(BN2mpz(&p, rsa->p)); |
398 | 0 | THEN_MP(BN2mpz(&q, rsa->q)); |
399 | 0 | THEN_MP(BN2mpz(&dmp1, rsa->dmp1)); |
400 | 0 | THEN_MP(BN2mpz(&dmq1, rsa->dmq1)); |
401 | 0 | THEN_MP(BN2mpz(&iqmp, rsa->iqmp)); |
402 | 0 | THEN_MP(ltm_rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out)); |
403 | 0 | mp_clear_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); |
404 | 0 | if (ret != MP_OKAY) goto out; |
405 | 0 | } else if (ret == MP_OKAY) { |
406 | 0 | mp_int d; |
407 | |
|
408 | 0 | THEN_IF_MP((mp_isneg(&in) || mp_cmp(&in, &n) >= 0), MP_ERR); |
409 | 0 | THEN_MP(BN2mpz(&d, rsa->d)); |
410 | 0 | THEN_MP(mp_exptmod(&in, &d, &n, &out)); |
411 | 0 | mp_clear(&d); |
412 | 0 | if (ret != MP_OKAY) goto out; |
413 | 0 | } |
414 | | |
415 | 0 | if (do_unblind) |
416 | 0 | THEN_MP(unblind(&out, &bi, &n)); |
417 | |
|
418 | 0 | if (ret == MP_OKAY) { |
419 | 0 | size_t ssize; |
420 | |
|
421 | 0 | ptr = to; |
422 | 0 | ssize = mp_ubin_size(&out); |
423 | 0 | assert(size >= ssize); |
424 | 0 | ret = mp_to_ubin(&out, ptr, SIZE_MAX, NULL); |
425 | 0 | if (ret != MP_OKAY) goto out; |
426 | 0 | size = ssize; |
427 | | |
428 | | /* head zero was skipped by mp_int_to_unsigned */ |
429 | 0 | if (*ptr != 2) { |
430 | 0 | where = __LINE__; |
431 | 0 | goto out; |
432 | 0 | } |
433 | 0 | size--; ptr++; |
434 | 0 | while (size && *ptr != 0) { |
435 | 0 | size--; ptr++; |
436 | 0 | } |
437 | 0 | if (size == 0) { |
438 | 0 | where = __LINE__; |
439 | 0 | goto out; |
440 | 0 | } |
441 | 0 | size--; ptr++; |
442 | 0 | memmove(to, ptr, size); |
443 | 0 | } |
444 | | |
445 | 0 | out: |
446 | 0 | mp_clear_multi(&e, &n, &in, &out, &b, &bi, NULL); |
447 | 0 | return (ret == MP_OKAY) ? size : -where; |
448 | 0 | } |
449 | | |
450 | | static BIGNUM * |
451 | | mpz2BN(mp_int *s) |
452 | 0 | { |
453 | 0 | size_t size; |
454 | 0 | BIGNUM *bn; |
455 | 0 | mp_err ret; |
456 | 0 | void *p; |
457 | |
|
458 | 0 | size = mp_ubin_size(s); |
459 | 0 | if (size == 0) |
460 | 0 | return NULL; |
461 | | |
462 | 0 | p = malloc(size); |
463 | 0 | if (p == NULL) |
464 | 0 | return NULL; |
465 | | |
466 | 0 | ret = mp_to_ubin(s, p, SIZE_MAX, NULL); |
467 | 0 | if (ret == MP_OKAY) |
468 | 0 | bn = BN_bin2bn(p, size, NULL); |
469 | 0 | free(p); |
470 | 0 | return (ret == MP_OKAY) ? bn : NULL; |
471 | 0 | } |
472 | | |
473 | | enum gen_pq_type { GEN_P, GEN_Q }; |
474 | | |
475 | | static int |
476 | | gen_p(int bits, enum gen_pq_type pq_type, uint8_t nibble_pair, mp_int *p, mp_int *e, BN_GENCB *cb) |
477 | 0 | { |
478 | 0 | unsigned char *buf = NULL; |
479 | 0 | mp_bool res; |
480 | 0 | mp_err ret = MP_MEM; |
481 | 0 | mp_int t1, t2; |
482 | 0 | size_t len = (bits + 7) / 8; |
483 | 0 | int trials = mp_prime_rabin_miller_trials(bits); |
484 | 0 | int counter = 0; |
485 | 0 | int where HEIMDAL_UNUSED_ATTRIBUTE = 0; |
486 | | |
487 | |
|
488 | 0 | FIRST(mp_init_multi(&t1, &t2, NULL)); |
489 | 0 | if (ret == MP_OKAY && (buf = malloc(len))) do { |
490 | 0 | BN_GENCB_call(cb, 2, counter++); |
491 | | /* random bytes */ |
492 | 0 | ret = (RAND_bytes(buf, len) == 1) ? MP_OKAY : MP_ERR; |
493 | | |
494 | | /* make it odd */ |
495 | 0 | buf[len - 1] |= 1; |
496 | | |
497 | | /* ensure the high nibble of the product is at least 128 */ |
498 | 0 | if (pq_type == GEN_P) |
499 | 0 | buf[0] = (nibble_pair & 0xf0) | (buf[0] & 0x0f); |
500 | 0 | else |
501 | 0 | buf[0] = ((nibble_pair & 0x0f) << 4) | (buf[0] & 0x0f); |
502 | | |
503 | | /* load number */ |
504 | 0 | THEN_MP(mp_from_ubin(p, buf, len)); |
505 | | |
506 | | /* test primality; repeat if not */ |
507 | 0 | THEN_MP(mp_prime_is_prime(p, trials, &res)); |
508 | 0 | if (ret == MP_OKAY && res == MP_NO) continue; |
509 | | |
510 | | /* check gcd(p - 1, e) == 1 */ |
511 | 0 | THEN_MP(mp_sub_d(p, 1, &t1)); |
512 | 0 | THEN_MP(mp_gcd(&t1, e, &t2)); |
513 | 0 | } while (ret == MP_OKAY && mp_cmp_d(&t2, 1) != MP_EQ); |
514 | |
|
515 | 0 | mp_clear_multi(&t1, &t2, NULL); |
516 | 0 | free(buf); |
517 | 0 | return ret; |
518 | 0 | } |
519 | | |
520 | | static uint8_t pq_high_nibble_pairs[] = { |
521 | | 0x9f, 0xad, 0xae, 0xaf, 0xbc, 0xbd, 0xbe, 0xbf, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, |
522 | | 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf9, |
523 | | 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff |
524 | | }; |
525 | | |
526 | | static int |
527 | | ltm_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) |
528 | 0 | { |
529 | 0 | mp_int el, p, q, n, d, dmp1, dmq1, iqmp, t1, t2, t3; |
530 | 0 | mp_err ret; |
531 | 0 | uint8_t high_nibbles = 0; |
532 | 0 | int bitsp; |
533 | 0 | int where = __LINE__; |
534 | |
|
535 | 0 | if (bits < 789) |
536 | 0 | return -1; |
537 | | |
538 | 0 | bitsp = (bits + 1) / 2; |
539 | |
|
540 | 0 | FIRST(mp_init_multi(&el, &p, &q, &n, &d, |
541 | 0 | &dmp1, &dmq1, &iqmp, |
542 | 0 | &t1, &t2, &t3, NULL)); |
543 | 0 | THEN_MP(BN2mpz(&el, e)); |
544 | | |
545 | | /* |
546 | | * randomly pick a pair of high nibbles for p and q to ensure the product's |
547 | | * high nibble is at least 128 |
548 | | */ |
549 | 0 | if (ret == MP_OKAY) |
550 | 0 | ret = (RAND_bytes(&high_nibbles, 1) == 1) ? MP_OKAY : MP_ERR; |
551 | 0 | high_nibbles %= sizeof(pq_high_nibble_pairs); |
552 | 0 | high_nibbles = pq_high_nibble_pairs[high_nibbles]; |
553 | | |
554 | | /* generate p and q so that p != q and bits(pq) ~ bits */ |
555 | 0 | THEN_MP(gen_p(bitsp, GEN_P, high_nibbles, &p, &el, cb)); |
556 | 0 | BN_GENCB_call(cb, 3, 0); |
557 | 0 | THEN_MP(gen_p(bitsp, GEN_Q, high_nibbles, &q, &el, cb)); |
558 | | |
559 | | /* make p > q */ |
560 | 0 | if (mp_cmp(&p, &q) < 0) { |
561 | 0 | mp_int c; |
562 | 0 | c = p; |
563 | 0 | p = q; |
564 | 0 | q = c; |
565 | 0 | } |
566 | |
|
567 | 0 | BN_GENCB_call(cb, 3, 1); |
568 | | |
569 | | /* calculate n, n = p * q */ |
570 | 0 | THEN_MP(mp_mul(&p, &q, &n)); |
571 | | |
572 | | /* calculate d, d = 1/e mod (p - 1)(q - 1) */ |
573 | 0 | THEN_MP(mp_sub_d(&p, 1, &t1)); |
574 | 0 | THEN_MP(mp_sub_d(&q, 1, &t2)); |
575 | 0 | THEN_MP(mp_mul(&t1, &t2, &t3)); |
576 | 0 | THEN_MP(mp_invmod(&el, &t3, &d)); |
577 | | |
578 | | /* calculate dmp1 dmp1 = d mod (p-1) */ |
579 | 0 | THEN_MP(mp_mod(&d, &t1, &dmp1)); |
580 | | /* calculate dmq1 dmq1 = d mod (q-1) */ |
581 | 0 | THEN_MP(mp_mod(&d, &t2, &dmq1)); |
582 | | /* calculate iqmp iqmp = 1/q mod p */ |
583 | 0 | THEN_MP(mp_invmod(&q, &p, &iqmp)); |
584 | | |
585 | | /* fill in RSA key */ |
586 | |
|
587 | 0 | if (ret == MP_OKAY) { |
588 | 0 | rsa->e = mpz2BN(&el); |
589 | 0 | rsa->p = mpz2BN(&p); |
590 | 0 | rsa->q = mpz2BN(&q); |
591 | 0 | rsa->n = mpz2BN(&n); |
592 | 0 | rsa->d = mpz2BN(&d); |
593 | 0 | rsa->dmp1 = mpz2BN(&dmp1); |
594 | 0 | rsa->dmq1 = mpz2BN(&dmq1); |
595 | 0 | rsa->iqmp = mpz2BN(&iqmp); |
596 | 0 | } |
597 | |
|
598 | 0 | mp_clear_multi(&el, &p, &q, &n, &d, |
599 | 0 | &dmp1, &dmq1, &iqmp, |
600 | 0 | &t1, &t2, &t3, NULL); |
601 | 0 | return (ret == MP_OKAY) ? 1 : -where; |
602 | 0 | } |
603 | | |
604 | | static int |
605 | | ltm_rsa_init(RSA *rsa) |
606 | 0 | { |
607 | 0 | return 1; |
608 | 0 | } |
609 | | |
610 | | static int |
611 | | ltm_rsa_finish(RSA *rsa) |
612 | 0 | { |
613 | 0 | return 1; |
614 | 0 | } |
615 | | |
616 | | const RSA_METHOD hc_rsa_ltm_method = { |
617 | | "hcrypto ltm RSA", |
618 | | ltm_rsa_public_encrypt, |
619 | | ltm_rsa_public_decrypt, |
620 | | ltm_rsa_private_encrypt, |
621 | | ltm_rsa_private_decrypt, |
622 | | NULL, |
623 | | NULL, |
624 | | ltm_rsa_init, |
625 | | ltm_rsa_finish, |
626 | | 0, |
627 | | NULL, |
628 | | NULL, |
629 | | NULL, |
630 | | ltm_rsa_generate_key |
631 | | }; |
632 | | |
633 | | const RSA_METHOD * |
634 | | RSA_ltm_method(void) |
635 | 0 | { |
636 | 0 | return &hc_rsa_ltm_method; |
637 | 0 | } |