comparison ecc_sys.c @ 3:7faae8f46238 libtomcrypt-orig

Branch renaming
author Matt Johnston <matt@ucc.asn.au>
date Mon, 31 May 2004 18:25:41 +0000
parents
children 5d99163f7e32
comparison
equal deleted inserted replaced
-1:000000000000 3:7faae8f46238
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