1 | /*
|
---|
2 | * dlls/rsaenh/rsa.c
|
---|
3 | * RSA public key cryptographic functions
|
---|
4 | *
|
---|
5 | * Copyright 2004 Michael Jung
|
---|
6 | * Based on public domain code by Tom St Denis (tomstdenis@iahu.ca)
|
---|
7 | *
|
---|
8 | * This library is free software; you can redistribute it and/or
|
---|
9 | * modify it under the terms of the GNU Lesser General Public
|
---|
10 | * License as published by the Free Software Foundation; either
|
---|
11 | * version 2.1 of the License, or (at your option) any later version.
|
---|
12 | *
|
---|
13 | * This library is distributed in the hope that it will be useful,
|
---|
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
16 | * Lesser General Public License for more details.
|
---|
17 | *
|
---|
18 | * You should have received a copy of the GNU Lesser General Public
|
---|
19 | * License along with this library; if not, write to the Free Software
|
---|
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
---|
21 | */
|
---|
22 |
|
---|
23 | /*
|
---|
24 | * This file contains code from the LibTomCrypt cryptographic
|
---|
25 | * library written by Tom St Denis (tomstdenis@iahu.ca). LibTomCrypt
|
---|
26 | * is in the public domain. The code in this file is tailored to
|
---|
27 | * special requirements. Take a look at http://libtomcrypt.org for the
|
---|
28 | * original version.
|
---|
29 | */
|
---|
30 |
|
---|
31 | #include "tomcrypt.h"
|
---|
32 |
|
---|
33 | static const struct {
|
---|
34 | int mpi_code, ltc_code;
|
---|
35 | } mpi_to_ltc_codes[] = {
|
---|
36 | { MP_OKAY , CRYPT_OK},
|
---|
37 | { MP_MEM , CRYPT_MEM},
|
---|
38 | { MP_VAL , CRYPT_INVALID_ARG},
|
---|
39 | };
|
---|
40 |
|
---|
41 | /* convert a MPI error to a LTC error (Possibly the most powerful function ever! Oh wait... no) */
|
---|
42 | static int mpi_to_ltc_error(int err)
|
---|
43 | {
|
---|
44 | int x;
|
---|
45 |
|
---|
46 | for (x = 0; x < (int)(sizeof(mpi_to_ltc_codes)/sizeof(mpi_to_ltc_codes[0])); x++) {
|
---|
47 | if (err == mpi_to_ltc_codes[x].mpi_code) {
|
---|
48 | return mpi_to_ltc_codes[x].ltc_code;
|
---|
49 | }
|
---|
50 | }
|
---|
51 | return CRYPT_ERROR;
|
---|
52 | }
|
---|
53 |
|
---|
54 | extern int gen_rand_impl(unsigned char *dst, unsigned int len);
|
---|
55 |
|
---|
56 | static int rand_prime_helper(unsigned char *dst, int len, void *dat)
|
---|
57 | {
|
---|
58 | return gen_rand_impl(dst, len) ? len : 0;
|
---|
59 | }
|
---|
60 |
|
---|
61 | static int rand_prime(mp_int *N, long len)
|
---|
62 | {
|
---|
63 | int type;
|
---|
64 |
|
---|
65 | /* get type */
|
---|
66 | if (len < 0) {
|
---|
67 | type = LTM_PRIME_BBS;
|
---|
68 | len = -len;
|
---|
69 | } else {
|
---|
70 | /* This seems to be what MS CSP's do: */
|
---|
71 | type = LTM_PRIME_2MSB_ON;
|
---|
72 | /* Original LibTomCrypt: type = 0; */
|
---|
73 | }
|
---|
74 |
|
---|
75 | /* allow sizes between 2 and 256 bytes for a prime size */
|
---|
76 | if (len < 16 || len > 8192) {
|
---|
77 | //printf("Invalid prime size!\n");
|
---|
78 | return CRYPT_INVALID_PRIME_SIZE;
|
---|
79 | }
|
---|
80 |
|
---|
81 | /* New prime generation makes the code even more cryptoish-insane. Do you know what this means!!!
|
---|
82 | -- Gir: Yeah, oh wait, er, no.
|
---|
83 | */
|
---|
84 | return mpi_to_ltc_error(mp_prime_random_ex(N, mp_prime_rabin_miller_trials(len), len, type, rand_prime_helper, NULL));
|
---|
85 | }
|
---|
86 |
|
---|
87 | int rsa_make_key(int size, long e, rsa_key *key)
|
---|
88 | {
|
---|
89 | mp_int p, q, tmp1, tmp2, tmp3;
|
---|
90 | int err;
|
---|
91 |
|
---|
92 | if ((size < (MIN_RSA_SIZE/8)) || (size > (MAX_RSA_SIZE/8))) {
|
---|
93 | return CRYPT_INVALID_KEYSIZE;
|
---|
94 | }
|
---|
95 |
|
---|
96 | if ((e < 3) || ((e & 1) == 0)) {
|
---|
97 | return CRYPT_INVALID_ARG;
|
---|
98 | }
|
---|
99 |
|
---|
100 | if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != MP_OKAY) {
|
---|
101 | return mpi_to_ltc_error(err);
|
---|
102 | }
|
---|
103 |
|
---|
104 | /* make primes p and q (optimization provided by Wayne Scott) */
|
---|
105 | if ((err = mp_set_int(&tmp3, e)) != MP_OKAY) { goto error; } /* tmp3 = e */
|
---|
106 |
|
---|
107 | /* make prime "p" */
|
---|
108 | do {
|
---|
109 | if ((err = rand_prime(&p, size*4)) != CRYPT_OK) { goto done; }
|
---|
110 | if ((err = mp_sub_d(&p, 1, &tmp1)) != MP_OKAY) { goto error; } /* tmp1 = p-1 */
|
---|
111 | if ((err = mp_gcd(&tmp1, &tmp3, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = gcd(p-1, e) */
|
---|
112 | } while (mp_cmp_d(&tmp2, 1) != 0); /* while e divides p-1 */
|
---|
113 |
|
---|
114 | /* make prime "q" */
|
---|
115 | do {
|
---|
116 | if ((err = rand_prime(&q, size*4)) != CRYPT_OK) { goto done; }
|
---|
117 | if ((err = mp_sub_d(&q, 1, &tmp1)) != MP_OKAY) { goto error; } /* tmp1 = q-1 */
|
---|
118 | if ((err = mp_gcd(&tmp1, &tmp3, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = gcd(q-1, e) */
|
---|
119 | } while (mp_cmp_d(&tmp2, 1) != 0); /* while e divides q-1 */
|
---|
120 |
|
---|
121 | /* tmp1 = lcm(p-1, q-1) */
|
---|
122 | if ((err = mp_sub_d(&p, 1, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = p-1 */
|
---|
123 | /* tmp1 = q-1 (previous do/while loop) */
|
---|
124 | if ((err = mp_lcm(&tmp1, &tmp2, &tmp1)) != MP_OKAY) { goto error; } /* tmp1 = lcm(p-1, q-1) */
|
---|
125 |
|
---|
126 | /* make key */
|
---|
127 | if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP,
|
---|
128 | &key->qP, &key->p, &key->q, NULL)) != MP_OKAY) {
|
---|
129 | goto error;
|
---|
130 | }
|
---|
131 |
|
---|
132 | if ((err = mp_set_int(&key->e, e)) != MP_OKAY) { goto error2; } /* key->e = e */
|
---|
133 | if ((err = mp_invmod(&key->e, &tmp1, &key->d)) != MP_OKAY) { goto error2; } /* key->d = 1/e mod lcm(p-1,q-1) */
|
---|
134 | if ((err = mp_mul(&p, &q, &key->N)) != MP_OKAY) { goto error2; } /* key->N = pq */
|
---|
135 |
|
---|
136 | /* optimize for CRT now */
|
---|
137 | /* find d mod q-1 and d mod p-1 */
|
---|
138 | if ((err = mp_sub_d(&p, 1, &tmp1)) != MP_OKAY) { goto error2; } /* tmp1 = q-1 */
|
---|
139 | if ((err = mp_sub_d(&q, 1, &tmp2)) != MP_OKAY) { goto error2; } /* tmp2 = p-1 */
|
---|
140 | if ((err = mp_mod(&key->d, &tmp1, &key->dP)) != MP_OKAY) { goto error2; } /* dP = d mod p-1 */
|
---|
141 | if ((err = mp_mod(&key->d, &tmp2, &key->dQ)) != MP_OKAY) { goto error2; } /* dQ = d mod q-1 */
|
---|
142 | if ((err = mp_invmod(&q, &p, &key->qP)) != MP_OKAY) { goto error2; } /* qP = 1/q mod p */
|
---|
143 |
|
---|
144 | if ((err = mp_copy(&p, &key->p)) != MP_OKAY) { goto error2; }
|
---|
145 | if ((err = mp_copy(&q, &key->q)) != MP_OKAY) { goto error2; }
|
---|
146 |
|
---|
147 | /* shrink ram required */
|
---|
148 | if ((err = mp_shrink(&key->e)) != MP_OKAY) { goto error2; }
|
---|
149 | if ((err = mp_shrink(&key->d)) != MP_OKAY) { goto error2; }
|
---|
150 | if ((err = mp_shrink(&key->N)) != MP_OKAY) { goto error2; }
|
---|
151 | if ((err = mp_shrink(&key->dQ)) != MP_OKAY) { goto error2; }
|
---|
152 | if ((err = mp_shrink(&key->dP)) != MP_OKAY) { goto error2; }
|
---|
153 | if ((err = mp_shrink(&key->qP)) != MP_OKAY) { goto error2; }
|
---|
154 | if ((err = mp_shrink(&key->p)) != MP_OKAY) { goto error2; }
|
---|
155 | if ((err = mp_shrink(&key->q)) != MP_OKAY) { goto error2; }
|
---|
156 |
|
---|
157 | /* set key type (in this case it's CRT optimized) */
|
---|
158 | key->type = PK_PRIVATE;
|
---|
159 |
|
---|
160 | /* return ok and free temps */
|
---|
161 | err = CRYPT_OK;
|
---|
162 | goto done;
|
---|
163 | error2:
|
---|
164 | mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP,
|
---|
165 | &key->qP, &key->p, &key->q, NULL);
|
---|
166 | error:
|
---|
167 | err = mpi_to_ltc_error(err);
|
---|
168 | done:
|
---|
169 | mp_clear_multi(&tmp3, &tmp2, &tmp1, &p, &q, NULL);
|
---|
170 | return err;
|
---|
171 | }
|
---|
172 |
|
---|
173 | void rsa_free(rsa_key *key)
|
---|
174 | {
|
---|
175 | mp_clear_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP,
|
---|
176 | &key->qP, &key->p, &key->q, NULL);
|
---|
177 | }
|
---|
178 |
|
---|
179 | /* compute an RSA modular exponentiation */
|
---|
180 | int rsa_exptmod(const unsigned char *in, unsigned long inlen,
|
---|
181 | unsigned char *out, unsigned long *outlen, int which,
|
---|
182 | rsa_key *key)
|
---|
183 | {
|
---|
184 | mp_int tmp, tmpa, tmpb;
|
---|
185 | unsigned long x;
|
---|
186 | int err;
|
---|
187 |
|
---|
188 | /* is the key of the right type for the operation? */
|
---|
189 | if (which == PK_PRIVATE && (key->type != PK_PRIVATE)) {
|
---|
190 | return CRYPT_PK_NOT_PRIVATE;
|
---|
191 | }
|
---|
192 |
|
---|
193 | /* must be a private or public operation */
|
---|
194 | if (which != PK_PRIVATE && which != PK_PUBLIC) {
|
---|
195 | return CRYPT_PK_INVALID_TYPE;
|
---|
196 | }
|
---|
197 |
|
---|
198 | /* init and copy into tmp */
|
---|
199 | if ((err = mp_init_multi(&tmp, &tmpa, &tmpb, NULL)) != MP_OKAY) { return mpi_to_ltc_error(err); }
|
---|
200 | if ((err = mp_read_unsigned_bin(&tmp, in, (int)inlen)) != MP_OKAY) { goto error; }
|
---|
201 |
|
---|
202 | /* sanity check on the input */
|
---|
203 | if (mp_cmp(&key->N, &tmp) == MP_LT) {
|
---|
204 | err = CRYPT_PK_INVALID_SIZE;
|
---|
205 | goto done;
|
---|
206 | }
|
---|
207 |
|
---|
208 | /* are we using the private exponent and is the key optimized? */
|
---|
209 | if (which == PK_PRIVATE) {
|
---|
210 | /* tmpa = tmp^dP mod p */
|
---|
211 | if ((err = mpi_to_ltc_error(mp_exptmod(&tmp, &key->dP, &key->p, &tmpa))) != MP_OKAY) { goto error; }
|
---|
212 |
|
---|
213 | /* tmpb = tmp^dQ mod q */
|
---|
214 | if ((err = mpi_to_ltc_error(mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb))) != MP_OKAY) { goto error; }
|
---|
215 |
|
---|
216 | /* tmp = (tmpa - tmpb) * qInv (mod p) */
|
---|
217 | if ((err = mp_sub(&tmpa, &tmpb, &tmp)) != MP_OKAY) { goto error; }
|
---|
218 | if ((err = mp_mulmod(&tmp, &key->qP, &key->p, &tmp)) != MP_OKAY) { goto error; }
|
---|
219 |
|
---|
220 | /* tmp = tmpb + q * tmp */
|
---|
221 | if ((err = mp_mul(&tmp, &key->q, &tmp)) != MP_OKAY) { goto error; }
|
---|
222 | if ((err = mp_add(&tmp, &tmpb, &tmp)) != MP_OKAY) { goto error; }
|
---|
223 | } else {
|
---|
224 | /* exptmod it */
|
---|
225 | if ((err = mp_exptmod(&tmp, &key->e, &key->N, &tmp)) != MP_OKAY) { goto error; }
|
---|
226 | }
|
---|
227 |
|
---|
228 | /* read it back */
|
---|
229 | x = (unsigned long)mp_unsigned_bin_size(&key->N);
|
---|
230 | if (x > *outlen) {
|
---|
231 | err = CRYPT_BUFFER_OVERFLOW;
|
---|
232 | goto done;
|
---|
233 | }
|
---|
234 | *outlen = x;
|
---|
235 |
|
---|
236 | /* convert it */
|
---|
237 | memset(out, 0, x);
|
---|
238 | if ((err = mp_to_unsigned_bin(&tmp, out+(x-mp_unsigned_bin_size(&tmp)))) != MP_OKAY) { goto error; }
|
---|
239 |
|
---|
240 | /* clean up and return */
|
---|
241 | err = CRYPT_OK;
|
---|
242 | goto done;
|
---|
243 | error:
|
---|
244 | err = mpi_to_ltc_error(err);
|
---|
245 | done:
|
---|
246 | mp_clear_multi(&tmp, &tmpa, &tmpb, NULL);
|
---|
247 | return err;
|
---|
248 | }
|
---|