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