Mercurial > dropbear
comparison ecc_sys.c @ 0:d7da3b1e1540 libtomcrypt
put back the 0.95 makefile which was inadvertently merged over
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Mon, 31 May 2004 18:21:40 +0000 |
parents | |
children | 5d99163f7e32 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d7da3b1e1540 |
---|---|
1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis | |
2 * | |
3 * LibTomCrypt is a library that provides various cryptographic | |
4 * algorithms in a highly modular and flexible manner. | |
5 * | |
6 * The library is free for all purposes without any express | |
7 * guarantee it works. | |
8 * | |
9 * Tom St Denis, [email protected], http://libtomcrypt.org | |
10 */ | |
11 int ecc_encrypt_key(const unsigned char *inkey, unsigned long keylen, | |
12 unsigned char *out, unsigned long *len, | |
13 prng_state *prng, int wprng, int hash, | |
14 ecc_key *key) | |
15 { | |
16 unsigned char pub_expt[256], ecc_shared[256], skey[MAXBLOCKSIZE]; | |
17 ecc_key pubkey; | |
18 unsigned long x, y, z, hashsize, pubkeysize; | |
19 int err; | |
20 | |
21 _ARGCHK(inkey != NULL); | |
22 _ARGCHK(out != NULL); | |
23 _ARGCHK(len != NULL); | |
24 _ARGCHK(key != NULL); | |
25 | |
26 /* check that wprng/cipher/hash are not invalid */ | |
27 if ((err = prng_is_valid(wprng)) != CRYPT_OK) { | |
28 return err; | |
29 } | |
30 | |
31 if ((err = hash_is_valid(hash)) != CRYPT_OK) { | |
32 return err; | |
33 } | |
34 | |
35 if (keylen > hash_descriptor[hash].hashsize) { | |
36 return CRYPT_INVALID_HASH; | |
37 } | |
38 | |
39 /* make a random key and export the public copy */ | |
40 if ((err = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { | |
41 return err; | |
42 } | |
43 | |
44 pubkeysize = (unsigned long)sizeof(pub_expt); | |
45 if ((err = ecc_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { | |
46 ecc_free(&pubkey); | |
47 return err; | |
48 } | |
49 | |
50 /* now check if the out buffer is big enough */ | |
51 if (*len < (9 + PACKET_SIZE + pubkeysize + hash_descriptor[hash].hashsize)) { | |
52 ecc_free(&pubkey); | |
53 return CRYPT_BUFFER_OVERFLOW; | |
54 } | |
55 | |
56 /* make random key */ | |
57 hashsize = hash_descriptor[hash].hashsize; | |
58 x = (unsigned long)sizeof(ecc_shared); | |
59 if ((err = ecc_shared_secret(&pubkey, key, ecc_shared, &x)) != CRYPT_OK) { | |
60 ecc_free(&pubkey); | |
61 return err; | |
62 } | |
63 ecc_free(&pubkey); | |
64 z = (unsigned long)sizeof(skey); | |
65 if ((err = hash_memory(hash, ecc_shared, x, skey, &z)) != CRYPT_OK) { | |
66 return err; | |
67 } | |
68 | |
69 /* store header */ | |
70 packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_ENC_KEY); | |
71 | |
72 /* output header */ | |
73 y = PACKET_SIZE; | |
74 | |
75 /* size of hash name and the name itself */ | |
76 out[y++] = hash_descriptor[hash].ID; | |
77 | |
78 /* length of ECC pubkey and the key itself */ | |
79 STORE32L(pubkeysize, out+y); | |
80 y += 4; | |
81 | |
82 for (x = 0; x < pubkeysize; x++, y++) { | |
83 out[y] = pub_expt[x]; | |
84 } | |
85 | |
86 STORE32L(keylen, out+y); | |
87 y += 4; | |
88 | |
89 /* Encrypt/Store the encrypted key */ | |
90 for (x = 0; x < keylen; x++, y++) { | |
91 out[y] = skey[x] ^ inkey[x]; | |
92 } | |
93 *len = y; | |
94 | |
95 #ifdef CLEAN_STACK | |
96 /* clean up */ | |
97 zeromem(pub_expt, sizeof(pub_expt)); | |
98 zeromem(ecc_shared, sizeof(ecc_shared)); | |
99 zeromem(skey, sizeof(skey)); | |
100 #endif | |
101 return CRYPT_OK; | |
102 } | |
103 | |
104 int ecc_decrypt_key(const unsigned char *in, unsigned long inlen, | |
105 unsigned char *outkey, unsigned long *keylen, | |
106 ecc_key *key) | |
107 { | |
108 unsigned char shared_secret[256], skey[MAXBLOCKSIZE]; | |
109 unsigned long x, y, z, hashsize, keysize; | |
110 int hash, err; | |
111 ecc_key pubkey; | |
112 | |
113 _ARGCHK(in != NULL); | |
114 _ARGCHK(outkey != NULL); | |
115 _ARGCHK(keylen != NULL); | |
116 _ARGCHK(key != NULL); | |
117 | |
118 /* right key type? */ | |
119 if (key->type != PK_PRIVATE) { | |
120 return CRYPT_PK_NOT_PRIVATE; | |
121 } | |
122 | |
123 /* correct length ? */ | |
124 if (inlen < PACKET_SIZE+1+4+4) { | |
125 return CRYPT_INVALID_PACKET; | |
126 } else { | |
127 inlen -= PACKET_SIZE+1+4+4; | |
128 } | |
129 | |
130 /* is header correct? */ | |
131 if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_ENC_KEY)) != CRYPT_OK) { | |
132 return err; | |
133 } | |
134 | |
135 /* now lets get the hash name */ | |
136 y = PACKET_SIZE; | |
137 hash = find_hash_id(in[y++]); | |
138 if (hash == -1) { | |
139 return CRYPT_INVALID_HASH; | |
140 } | |
141 | |
142 /* common values */ | |
143 hashsize = hash_descriptor[hash].hashsize; | |
144 | |
145 /* get public key */ | |
146 LOAD32L(x, in+y); | |
147 if (inlen < x) { | |
148 return CRYPT_INVALID_PACKET; | |
149 } else { | |
150 inlen -= x; | |
151 } | |
152 y += 4; | |
153 if ((err = ecc_import(in+y, x, &pubkey)) != CRYPT_OK) { | |
154 return err; | |
155 } | |
156 y += x; | |
157 | |
158 /* make shared key */ | |
159 x = (unsigned long)sizeof(shared_secret); | |
160 if ((err = ecc_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) { | |
161 ecc_free(&pubkey); | |
162 return err; | |
163 } | |
164 ecc_free(&pubkey); | |
165 | |
166 z = (unsigned long)sizeof(skey); | |
167 if ((err = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) { | |
168 return err; | |
169 } | |
170 | |
171 LOAD32L(keysize, in+y); | |
172 if (inlen < keysize) { | |
173 return CRYPT_INVALID_PACKET; | |
174 } else { | |
175 inlen -= keysize; | |
176 } | |
177 y += 4; | |
178 | |
179 if (*keylen < keysize) { | |
180 err = CRYPT_BUFFER_OVERFLOW; | |
181 goto done; | |
182 } | |
183 | |
184 /* Decrypt the key */ | |
185 for (x = 0; x < keysize; x++, y++) { | |
186 outkey[x] = skey[x] ^ in[y]; | |
187 } | |
188 | |
189 *keylen = keysize; | |
190 | |
191 err = CRYPT_OK; | |
192 done: | |
193 #ifdef CLEAN_STACK | |
194 zeromem(shared_secret, sizeof(shared_secret)); | |
195 zeromem(skey, sizeof(skey)); | |
196 #endif | |
197 return err; | |
198 } | |
199 | |
200 int ecc_sign_hash(const unsigned char *in, unsigned long inlen, | |
201 unsigned char *out, unsigned long *outlen, | |
202 prng_state *prng, int wprng, ecc_key *key) | |
203 { | |
204 ecc_key pubkey; | |
205 mp_int b, p; | |
206 unsigned char epubkey[256], er[256]; | |
207 unsigned long x, y, pubkeysize, rsize; | |
208 int err; | |
209 | |
210 _ARGCHK(in != NULL); | |
211 _ARGCHK(out != NULL); | |
212 _ARGCHK(outlen != NULL); | |
213 _ARGCHK(key != NULL); | |
214 | |
215 /* is this a private key? */ | |
216 if (key->type != PK_PRIVATE) { | |
217 return CRYPT_PK_NOT_PRIVATE; | |
218 } | |
219 | |
220 /* is the IDX valid ? */ | |
221 if (is_valid_idx(key->idx) != 1) { | |
222 return CRYPT_PK_INVALID_TYPE; | |
223 } | |
224 | |
225 if ((err = prng_is_valid(wprng)) != CRYPT_OK) { | |
226 return err; | |
227 } | |
228 | |
229 /* make up a key and export the public copy */ | |
230 if ((err = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { | |
231 return err; | |
232 } | |
233 | |
234 pubkeysize = (unsigned long)sizeof(epubkey); | |
235 if ((err = ecc_export(epubkey, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { | |
236 ecc_free(&pubkey); | |
237 return err; | |
238 } | |
239 | |
240 /* get the hash and load it as a bignum into 'b' */ | |
241 /* init the bignums */ | |
242 if ((err = mp_init_multi(&b, &p, NULL)) != MP_OKAY) { | |
243 ecc_free(&pubkey); | |
244 return mpi_to_ltc_error(err); | |
245 } | |
246 if ((err = mp_read_radix(&p, (char *)sets[key->idx].order, 64)) != MP_OKAY) { goto error; } | |
247 if ((err = mp_read_unsigned_bin(&b, (unsigned char *)in, (int)inlen)) != MP_OKAY) { goto error; } | |
248 | |
249 /* find b = (m - x)/k */ | |
250 if ((err = mp_invmod(&pubkey.k, &p, &pubkey.k)) != MP_OKAY) { goto error; } /* k = 1/k */ | |
251 if ((err = mp_submod(&b, &key->k, &p, &b)) != MP_OKAY) { goto error; } /* b = m - x */ | |
252 if ((err = mp_mulmod(&b, &pubkey.k, &p, &b)) != MP_OKAY) { goto error; } /* b = (m - x)/k */ | |
253 | |
254 /* export it */ | |
255 rsize = (unsigned long)mp_unsigned_bin_size(&b); | |
256 if (rsize > (unsigned long)sizeof(er)) { | |
257 err = CRYPT_BUFFER_OVERFLOW; | |
258 goto error; | |
259 } | |
260 if ((err = mp_to_unsigned_bin(&b, er)) != MP_OKAY) { goto error; } | |
261 | |
262 /* now lets check the outlen before we write */ | |
263 if (*outlen < (12 + rsize + pubkeysize)) { | |
264 err = CRYPT_BUFFER_OVERFLOW; | |
265 goto done; | |
266 } | |
267 | |
268 /* lets output */ | |
269 y = PACKET_SIZE; | |
270 | |
271 /* size of public key */ | |
272 STORE32L(pubkeysize, out+y); | |
273 y += 4; | |
274 | |
275 /* copy the public key */ | |
276 for (x = 0; x < pubkeysize; x++, y++) { | |
277 out[y] = epubkey[x]; | |
278 } | |
279 | |
280 /* size of 'r' */ | |
281 STORE32L(rsize, out+y); | |
282 y += 4; | |
283 | |
284 /* copy r */ | |
285 for (x = 0; x < rsize; x++, y++) { | |
286 out[y] = er[x]; | |
287 } | |
288 | |
289 /* store header */ | |
290 packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_SIGNED); | |
291 | |
292 /* clear memory */ | |
293 *outlen = y; | |
294 err = CRYPT_OK; | |
295 goto done; | |
296 error: | |
297 err = mpi_to_ltc_error(err); | |
298 done: | |
299 mp_clear_multi(&b, &p, NULL); | |
300 ecc_free(&pubkey); | |
301 #ifdef CLEAN_STACK | |
302 zeromem(er, sizeof(er)); | |
303 zeromem(epubkey, sizeof(epubkey)); | |
304 #endif | |
305 return err; | |
306 } | |
307 | |
308 /* verify that mG = (bA + Y) | |
309 * | |
310 * The signatures work by making up a fresh key "a" with a public key "A". Now we want to sign so the | |
311 * public key Y = xG can verify it. | |
312 * | |
313 * b = (m - x)/k, A is the public key embedded and Y is the users public key [who signed it] | |
314 * A = kG therefore bA == ((m-x)/k)kG == (m-x)G | |
315 * | |
316 * Adding Y = xG to the bA gives us (m-x)G + xG == mG | |
317 * | |
318 * The user given only xG, kG and b cannot determine k or x which means they can't find the private key. | |
319 * | |
320 */ | |
321 int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, | |
322 const unsigned char *hash, unsigned long inlen, | |
323 int *stat, ecc_key *key) | |
324 { | |
325 ecc_point *mG; | |
326 ecc_key pubkey; | |
327 mp_int b, p, m, mu; | |
328 unsigned long x, y; | |
329 int err; | |
330 | |
331 _ARGCHK(sig != NULL); | |
332 _ARGCHK(hash != NULL); | |
333 _ARGCHK(stat != NULL); | |
334 _ARGCHK(key != NULL); | |
335 | |
336 /* default to invalid signature */ | |
337 *stat = 0; | |
338 | |
339 if (siglen < PACKET_SIZE+4+4) { | |
340 return CRYPT_INVALID_PACKET; | |
341 } else { | |
342 siglen -= PACKET_SIZE+4+4; | |
343 } | |
344 | |
345 /* is the message format correct? */ | |
346 if ((err = packet_valid_header((unsigned char *)sig, PACKET_SECT_ECC, PACKET_SUB_SIGNED)) != CRYPT_OK) { | |
347 return err; | |
348 } | |
349 | |
350 /* get hash name */ | |
351 y = PACKET_SIZE; | |
352 | |
353 /* get size of public key */ | |
354 LOAD32L(x, sig+y); | |
355 if (siglen < x) { | |
356 return CRYPT_INVALID_PACKET; | |
357 } else { | |
358 siglen -= x; | |
359 } | |
360 y += 4; | |
361 | |
362 /* load the public key */ | |
363 if ((err = ecc_import((unsigned char*)sig+y, x, &pubkey)) != CRYPT_OK) { | |
364 return err; | |
365 } | |
366 y += x; | |
367 | |
368 /* load size of 'b' */ | |
369 LOAD32L(x, sig+y); | |
370 if (siglen < x) { | |
371 return CRYPT_INVALID_PACKET; | |
372 } else { | |
373 siglen -= x; | |
374 } | |
375 y += 4; | |
376 | |
377 /* init values */ | |
378 if ((err = mp_init_multi(&b, &m, &p, &mu, NULL)) != MP_OKAY) { | |
379 ecc_free(&pubkey); | |
380 return mpi_to_ltc_error(err); | |
381 } | |
382 | |
383 mG = new_point(); | |
384 if (mG == NULL) { | |
385 mp_clear_multi(&b, &m, &p, &mu, NULL); | |
386 ecc_free(&pubkey); | |
387 return CRYPT_MEM; | |
388 } | |
389 | |
390 /* load b */ | |
391 if ((err = mp_read_unsigned_bin(&b, (unsigned char *)sig+y, (int)x)) != MP_OKAY) { goto error; } | |
392 y += x; | |
393 | |
394 /* get m in binary a bignum */ | |
395 if ((err = mp_read_unsigned_bin(&m, (unsigned char *)hash, (int)inlen)) != MP_OKAY) { goto error; } | |
396 | |
397 /* load prime */ | |
398 if ((err = mp_read_radix(&p, (char *)sets[key->idx].prime, 64)) != MP_OKAY) { goto error; } | |
399 | |
400 /* calculate barrett stuff */ | |
401 mp_set(&mu, 1); | |
402 mp_lshd(&mu, 2 * USED(&p)); | |
403 if ((err = mp_div(&mu, &p, &mu, NULL)) != MP_OKAY) { goto error; } | |
404 | |
405 /* get bA */ | |
406 if ((err = ecc_mulmod(&b, &pubkey.pubkey, &pubkey.pubkey, &p)) != CRYPT_OK) { goto done; } | |
407 | |
408 /* get bA + Y */ | |
409 if ((err = add_point(&pubkey.pubkey, &key->pubkey, &pubkey.pubkey, &p, &mu)) != CRYPT_OK) { goto done; } | |
410 | |
411 /* get mG */ | |
412 if ((err = mp_read_radix(&mG->x, (char *)sets[key->idx].Gx, 64)) != MP_OKAY) { goto error; } | |
413 if ((err = mp_read_radix(&mG->y, (char *)sets[key->idx].Gy, 64)) != MP_OKAY) { goto error; } | |
414 if ((err = ecc_mulmod(&m, mG, mG, &p)) != CRYPT_OK) { goto done; } | |
415 | |
416 /* compare mG to bA + Y */ | |
417 if (mp_cmp(&mG->x, &pubkey.pubkey.x) == MP_EQ && mp_cmp(&mG->y, &pubkey.pubkey.y) == MP_EQ) { | |
418 *stat = 1; | |
419 } | |
420 | |
421 /* clear up and return */ | |
422 err = CRYPT_OK; | |
423 goto done; | |
424 error: | |
425 err = mpi_to_ltc_error(err); | |
426 done: | |
427 del_point(mG); | |
428 ecc_free(&pubkey); | |
429 mp_clear_multi(&p, &m, &b, &mu, NULL); | |
430 return err; | |
431 } | |
432 |