Mercurial > dropbear
comparison ecdsa.c @ 844:68facbc41273
merge again
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 01 Nov 2013 00:19:25 +0800 |
parents | 7dcb46da72d9 |
children | b298bb438625 |
comparison
equal
deleted
inserted
replaced
834:e378da7eae5d | 844:68facbc41273 |
---|---|
1 #include "options.h" | |
2 #include "includes.h" | |
3 #include "dbutil.h" | |
4 #include "crypto_desc.h" | |
5 #include "ecc.h" | |
6 #include "ecdsa.h" | |
7 #include "signkey.h" | |
8 | |
9 #ifdef DROPBEAR_ECDSA | |
10 | |
11 enum signkey_type ecdsa_signkey_type(ecc_key * key) { | |
12 #ifdef DROPBEAR_ECC_256 | |
13 if (key->dp == ecc_curve_nistp256.dp) { | |
14 return DROPBEAR_SIGNKEY_ECDSA_NISTP256; | |
15 } | |
16 #endif | |
17 #ifdef DROPBEAR_ECC_384 | |
18 if (key->dp == ecc_curve_nistp384.dp) { | |
19 return DROPBEAR_SIGNKEY_ECDSA_NISTP384; | |
20 } | |
21 #endif | |
22 #ifdef DROPBEAR_ECC_521 | |
23 if (key->dp == ecc_curve_nistp521.dp) { | |
24 return DROPBEAR_SIGNKEY_ECDSA_NISTP521; | |
25 } | |
26 #endif | |
27 return DROPBEAR_SIGNKEY_NONE; | |
28 } | |
29 | |
30 ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) { | |
31 const ltc_ecc_set_type *dp = NULL; // curve domain parameters | |
32 switch (bit_size) { | |
33 #ifdef DROPBEAR_ECC_256 | |
34 case 256: | |
35 dp = ecc_curve_nistp256.dp; | |
36 break; | |
37 #endif | |
38 #ifdef DROPBEAR_ECC_384 | |
39 case 384: | |
40 dp = ecc_curve_nistp384.dp; | |
41 break; | |
42 #endif | |
43 #ifdef DROPBEAR_ECC_521 | |
44 case 521: | |
45 dp = ecc_curve_nistp521.dp; | |
46 break; | |
47 #endif | |
48 } | |
49 if (!dp) { | |
50 dropbear_exit("Key size %d isn't valid. Try " | |
51 #ifdef DROPBEAR_ECC_256 | |
52 "256 " | |
53 #endif | |
54 #ifdef DROPBEAR_ECC_384 | |
55 "384 " | |
56 #endif | |
57 #ifdef DROPBEAR_ECC_521 | |
58 "521 " | |
59 #endif | |
60 , bit_size); | |
61 } | |
62 | |
63 ecc_key *new_key = m_malloc(sizeof(*new_key)); | |
64 if (ecc_make_key_ex(NULL, dropbear_ltc_prng, new_key, dp) != CRYPT_OK) { | |
65 dropbear_exit("ECC error"); | |
66 } | |
67 return new_key; | |
68 } | |
69 | |
70 ecc_key *buf_get_ecdsa_pub_key(buffer* buf) { | |
71 unsigned char *key_ident = NULL, *identifier = NULL; | |
72 unsigned int key_ident_len, identifier_len; | |
73 buffer *q_buf = NULL; | |
74 struct dropbear_ecc_curve **curve; | |
75 ecc_key *new_key = NULL; | |
76 | |
77 // string "ecdsa-sha2-[identifier]" | |
78 key_ident = buf_getstring(buf, &key_ident_len); | |
79 // string "[identifier]" | |
80 identifier = buf_getstring(buf, &identifier_len); | |
81 | |
82 if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) { | |
83 TRACE(("Bad identifier lengths")) | |
84 goto out; | |
85 } | |
86 if (memcmp(&key_ident[strlen("ecdsa-sha2-")], identifier, identifier_len) != 0) { | |
87 TRACE(("mismatching identifiers")) | |
88 goto out; | |
89 } | |
90 | |
91 for (curve = dropbear_ecc_curves; *curve; curve++) { | |
92 if (memcmp(identifier, (char*)(*curve)->name, strlen((char*)(*curve)->name)) == 0) { | |
93 break; | |
94 } | |
95 } | |
96 if (!*curve) { | |
97 TRACE(("couldn't match ecc curve")) | |
98 goto out; | |
99 } | |
100 | |
101 // string Q | |
102 q_buf = buf_getstringbuf(buf); | |
103 new_key = buf_get_ecc_raw_pubkey(q_buf, *curve); | |
104 | |
105 out: | |
106 m_free(key_ident); | |
107 m_free(identifier); | |
108 if (q_buf) { | |
109 buf_free(q_buf); | |
110 q_buf = NULL; | |
111 } | |
112 TRACE(("leave buf_get_ecdsa_pub_key")) | |
113 return new_key; | |
114 } | |
115 | |
116 ecc_key *buf_get_ecdsa_priv_key(buffer *buf) { | |
117 ecc_key *new_key = NULL; | |
118 TRACE(("enter buf_get_ecdsa_priv_key")) | |
119 new_key = buf_get_ecdsa_pub_key(buf); | |
120 if (!new_key) { | |
121 return NULL; | |
122 } | |
123 | |
124 if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) { | |
125 ecc_free(new_key); | |
126 return NULL; | |
127 } | |
128 | |
129 return new_key; | |
130 } | |
131 | |
132 void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) { | |
133 struct dropbear_ecc_curve *curve = NULL; | |
134 unsigned char key_ident[30]; | |
135 | |
136 curve = curve_for_dp(key->dp); | |
137 snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name); | |
138 buf_putstring(buf, key_ident, strlen(key_ident)); | |
139 buf_putstring(buf, curve->name, strlen(curve->name)); | |
140 buf_put_ecc_raw_pubkey_string(buf, key); | |
141 } | |
142 | |
143 void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key) { | |
144 buf_put_ecdsa_pub_key(buf, key); | |
145 buf_putmpint(buf, key->k); | |
146 } | |
147 | |
148 void buf_put_ecdsa_sign(buffer *buf, ecc_key *key, buffer *data_buf) { | |
149 /* Based on libtomcrypt's ecc_sign_hash but without the asn1 */ | |
150 int err = DROPBEAR_FAILURE; | |
151 struct dropbear_ecc_curve *curve = NULL; | |
152 hash_state hs; | |
153 unsigned char hash[64]; | |
154 void *e = NULL, *p = NULL, *s = NULL, *r; | |
155 unsigned char key_ident[30]; | |
156 buffer *sigbuf = NULL; | |
157 | |
158 TRACE(("buf_put_ecdsa_sign")) | |
159 curve = curve_for_dp(key->dp); | |
160 | |
161 if (ltc_init_multi(&r, &s, &p, &e, NULL) != CRYPT_OK) { | |
162 goto out; | |
163 } | |
164 | |
165 curve->hash_desc->init(&hs); | |
166 curve->hash_desc->process(&hs, data_buf->data, data_buf->len); | |
167 curve->hash_desc->done(&hs, hash); | |
168 | |
169 if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) { | |
170 goto out; | |
171 } | |
172 | |
173 if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) { | |
174 goto out; | |
175 } | |
176 | |
177 for (;;) { | |
178 ecc_key R_key; // ephemeral key | |
179 if (ecc_make_key_ex(NULL, dropbear_ltc_prng, &R_key, key->dp) != CRYPT_OK) { | |
180 goto out; | |
181 } | |
182 if (ltc_mp.mpdiv(R_key.pubkey.x, p, NULL, r) != CRYPT_OK) { | |
183 goto out; | |
184 } | |
185 if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ) { | |
186 // try again | |
187 ecc_free(&R_key); | |
188 continue; | |
189 } | |
190 /* k = 1/k */ | |
191 if (ltc_mp.invmod(R_key.k, p, R_key.k) != CRYPT_OK) { | |
192 goto out; | |
193 } | |
194 /* s = xr */ | |
195 if (ltc_mp.mulmod(key->k, r, p, s) != CRYPT_OK) { | |
196 goto out; | |
197 } | |
198 /* s = e + xr */ | |
199 if (ltc_mp.add(e, s, s) != CRYPT_OK) { | |
200 goto out; | |
201 } | |
202 if (ltc_mp.mpdiv(s, p, NULL, s) != CRYPT_OK) { | |
203 goto out; | |
204 } | |
205 /* s = (e + xr)/k */ | |
206 if (ltc_mp.mulmod(s, R_key.k, p, s) != CRYPT_OK) { | |
207 goto out; | |
208 } | |
209 ecc_free(&R_key); | |
210 | |
211 if (ltc_mp.compare_d(s, 0) != LTC_MP_EQ) { | |
212 break; | |
213 } | |
214 } | |
215 | |
216 snprintf((char*)key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name); | |
217 buf_putstring(buf, key_ident, strlen(key_ident)); | |
218 // enough for nistp521 | |
219 sigbuf = buf_new(200); | |
220 buf_putmpint(sigbuf, (mp_int*)r); | |
221 buf_putmpint(sigbuf, (mp_int*)s); | |
222 buf_putbufstring(buf, sigbuf); | |
223 | |
224 err = DROPBEAR_SUCCESS; | |
225 | |
226 out: | |
227 if (r && s && p && e) { | |
228 ltc_deinit_multi(r, s, p, e, NULL); | |
229 } | |
230 | |
231 if (sigbuf) { | |
232 buf_free(sigbuf); | |
233 } | |
234 | |
235 if (err == DROPBEAR_FAILURE) { | |
236 dropbear_exit("ECC error"); | |
237 } | |
238 } | |
239 | |
240 // returns values in s and r | |
241 // returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE | |
242 static int buf_get_ecdsa_verify_params(buffer *buf, struct dropbear_ecc_curve *curve, | |
243 void *r, void* s) { | |
244 int ret = DROPBEAR_FAILURE; | |
245 unsigned int sig_len; | |
246 unsigned int sig_pos; | |
247 | |
248 sig_len = buf_getint(buf); | |
249 sig_pos = buf->pos; | |
250 if (buf_getmpint(buf, r) != DROPBEAR_SUCCESS) { | |
251 goto out; | |
252 } | |
253 if (buf_getmpint(buf, s) != DROPBEAR_SUCCESS) { | |
254 goto out; | |
255 } | |
256 if (buf->pos - sig_pos != sig_len) { | |
257 goto out; | |
258 } | |
259 ret = DROPBEAR_SUCCESS; | |
260 | |
261 out: | |
262 return ret; | |
263 } | |
264 | |
265 | |
266 int buf_ecdsa_verify(buffer *buf, ecc_key *key, buffer *data_buf) { | |
267 /* Based on libtomcrypt's ecc_verify_hash but without the asn1 */ | |
268 int ret = DROPBEAR_FAILURE; | |
269 hash_state hs; | |
270 struct dropbear_ecc_curve *curve = NULL; | |
271 unsigned char hash[64]; | |
272 ecc_point *mG = NULL, *mQ = NULL; | |
273 void *r = NULL, *s = NULL, *v = NULL, *w = NULL, *u1 = NULL, *u2 = NULL, | |
274 *e = NULL, *p = NULL, *m = NULL; | |
275 void *mp = NULL; | |
276 | |
277 /* verify | |
278 * | |
279 * w = s^-1 mod n | |
280 * u1 = xw | |
281 * u2 = rw | |
282 * X = u1*G + u2*Q | |
283 * v = X_x1 mod n | |
284 * accept if v == r | |
285 */ | |
286 | |
287 TRACE(("buf_ecdsa_verify")) | |
288 curve = curve_for_dp(key->dp); | |
289 | |
290 mG = ltc_ecc_new_point(); | |
291 mQ = ltc_ecc_new_point(); | |
292 if (ltc_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL) != CRYPT_OK | |
293 || !mG | |
294 || !mQ) { | |
295 dropbear_exit("ECC error"); | |
296 } | |
297 | |
298 if (buf_get_ecdsa_verify_params(buf, curve, r, s) != DROPBEAR_SUCCESS) { | |
299 goto out; | |
300 } | |
301 | |
302 curve->hash_desc->init(&hs); | |
303 curve->hash_desc->process(&hs, data_buf->data, data_buf->len); | |
304 curve->hash_desc->done(&hs, hash); | |
305 | |
306 if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) { | |
307 goto out; | |
308 } | |
309 | |
310 /* get the order */ | |
311 if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) { | |
312 goto out; | |
313 } | |
314 | |
315 /* get the modulus */ | |
316 if (ltc_mp.read_radix(m, (char *)key->dp->prime, 16) != CRYPT_OK) { | |
317 goto out; | |
318 } | |
319 | |
320 /* check for zero */ | |
321 if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ | |
322 || ltc_mp.compare_d(s, 0) == LTC_MP_EQ | |
323 || ltc_mp.compare(r, p) != LTC_MP_LT | |
324 || ltc_mp.compare(s, p) != LTC_MP_LT) { | |
325 goto out; | |
326 } | |
327 | |
328 /* w = s^-1 mod n */ | |
329 if (ltc_mp.invmod(s, p, w) != CRYPT_OK) { | |
330 goto out; | |
331 } | |
332 | |
333 /* u1 = ew */ | |
334 if (ltc_mp.mulmod(e, w, p, u1) != CRYPT_OK) { | |
335 goto out; | |
336 } | |
337 | |
338 /* u2 = rw */ | |
339 if (ltc_mp.mulmod(r, w, p, u2) != CRYPT_OK) { | |
340 goto out; | |
341 } | |
342 | |
343 /* find mG and mQ */ | |
344 if (ltc_mp.read_radix(mG->x, (char *)key->dp->Gx, 16) != CRYPT_OK) { | |
345 goto out; | |
346 } | |
347 if (ltc_mp.read_radix(mG->y, (char *)key->dp->Gy, 16) != CRYPT_OK) { | |
348 goto out; | |
349 } | |
350 if (ltc_mp.set_int(mG->z, 1) != CRYPT_OK) { | |
351 goto out; | |
352 } | |
353 | |
354 if (ltc_mp.copy(key->pubkey.x, mQ->x) != CRYPT_OK | |
355 || ltc_mp.copy(key->pubkey.y, mQ->y) != CRYPT_OK | |
356 || ltc_mp.copy(key->pubkey.z, mQ->z) != CRYPT_OK) { | |
357 goto out; | |
358 } | |
359 | |
360 /* compute u1*mG + u2*mQ = mG */ | |
361 if (ltc_mp.ecc_mul2add == NULL) { | |
362 if (ltc_mp.ecc_ptmul(u1, mG, mG, m, 0) != CRYPT_OK) { | |
363 goto out; | |
364 } | |
365 if (ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0) != CRYPT_OK) { | |
366 goto out; | |
367 } | |
368 | |
369 /* find the montgomery mp */ | |
370 if (ltc_mp.montgomery_setup(m, &mp) != CRYPT_OK) { | |
371 goto out; | |
372 } | |
373 | |
374 /* add them */ | |
375 if (ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp) != CRYPT_OK) { | |
376 goto out; | |
377 } | |
378 | |
379 /* reduce */ | |
380 if (ltc_mp.ecc_map(mG, m, mp) != CRYPT_OK) { | |
381 goto out; | |
382 } | |
383 } else { | |
384 /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */ | |
385 if (ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m) != CRYPT_OK) { | |
386 goto out; | |
387 } | |
388 } | |
389 | |
390 /* v = X_x1 mod n */ | |
391 if (ltc_mp.mpdiv(mG->x, p, NULL, v) != CRYPT_OK) { | |
392 goto out; | |
393 } | |
394 | |
395 /* does v == r */ | |
396 if (ltc_mp.compare(v, r) == LTC_MP_EQ) { | |
397 ret = DROPBEAR_SUCCESS; | |
398 } | |
399 | |
400 out: | |
401 ltc_ecc_del_point(mG); | |
402 ltc_ecc_del_point(mQ); | |
403 mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL); | |
404 if (mp != NULL) { | |
405 ltc_mp.montgomery_deinit(mp); | |
406 } | |
407 return ret; | |
408 } | |
409 | |
410 | |
411 | |
412 #endif // DROPBEAR_ECDSA |