comparison dss.c @ 4:fe6bca95afa7

Makefile.in contains updated files required
author Matt Johnston <matt@ucc.asn.au>
date Tue, 01 Jun 2004 02:46:09 +0000
parents
children e2a1eaa19f22
comparison
equal deleted inserted replaced
-1:000000000000 4:fe6bca95afa7
1 /*
2 * Dropbear - a SSH2 server
3 *
4 * Copyright (c) 2002,2003 Matt Johnston
5 * All rights reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE. */
24
25 #include "includes.h"
26 #include "dbutil.h"
27 #include "bignum.h"
28 #include "dss.h"
29 #include "buffer.h"
30 #include "ssh.h"
31 #include "random.h"
32
33 /* Handle DSS (Digital Signature Standard), aka DSA (D.S. Algorithm),
34 * operations, such as key reading, signing, verification. Key generation
35 * is in gendss.c, since it isn't required in the server itself.
36 *
37 * See FIPS186 or the Handbook of Applied Cryptography for details of the
38 * algorithm */
39
40 #ifdef DROPBEAR_DSS
41
42 /* Load a dss key from a buffer, initialising the values.
43 * The key will have the same format as buf_put_dss_key.
44 * These should be freed with dss_key_free.
45 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
46 int buf_get_dss_pub_key(buffer* buf, dss_key *key) {
47
48 assert(key != NULL);
49 key->p = m_malloc(sizeof(mp_int));
50 key->q = m_malloc(sizeof(mp_int));
51 key->g = m_malloc(sizeof(mp_int));
52 key->y = m_malloc(sizeof(mp_int));
53 m_mp_init_multi(key->p, key->q, key->g, key->y, NULL);
54 key->x = NULL;
55
56 buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
57 if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE
58 || buf_getmpint(buf, key->q) == DROPBEAR_FAILURE
59 || buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
60 || buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
61 return DROPBEAR_FAILURE;
62 }
63
64 if (mp_count_bits(key->p) < MIN_DSS_KEYLEN) {
65 dropbear_log(LOG_WARNING, "DSS key too short");
66 return DROPBEAR_FAILURE;
67 }
68
69 return DROPBEAR_SUCCESS;
70 }
71
72 /* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
73 * Loads a private dss key from a buffer
74 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
75 int buf_get_dss_priv_key(buffer* buf, dss_key *key) {
76
77 int ret = DROPBEAR_FAILURE;
78
79 assert(key != NULL);
80
81 ret = buf_get_dss_pub_key(buf, key);
82 if (ret == DROPBEAR_FAILURE) {
83 return DROPBEAR_FAILURE;
84 }
85
86 key->x = m_malloc(sizeof(mp_int));
87 m_mp_init(key->x);
88 ret = buf_getmpint(buf, key->x);
89
90 return ret;
91 }
92
93
94 /* Clear and free the memory used by a public or private key */
95 void dss_key_free(dss_key *key) {
96
97 TRACE(("enter dsa_key_free"));
98 if (key == NULL) {
99 TRACE(("enter dsa_key_free: key == NULL"));
100 return;
101 }
102 if (key->p) {
103 mp_clear(key->p);
104 m_free(key->p);
105 }
106 if (key->q) {
107 mp_clear(key->q);
108 m_free(key->q);
109 }
110 if (key->g) {
111 mp_clear(key->g);
112 m_free(key->g);
113 }
114 if (key->y) {
115 mp_clear(key->y);
116 m_free(key->y);
117 }
118 if (key->x) {
119 mp_clear(key->x);
120 m_free(key->x);
121 }
122 m_free(key);
123 TRACE(("leave dsa_key_free"));
124 }
125
126 /* put the dss public key into the buffer in the required format:
127 *
128 * string "ssh-dss"
129 * mpint p
130 * mpint q
131 * mpint g
132 * mpint y
133 */
134 void buf_put_dss_pub_key(buffer* buf, dss_key *key) {
135
136 assert(key != NULL);
137 buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
138 buf_putmpint(buf, key->p);
139 buf_putmpint(buf, key->q);
140 buf_putmpint(buf, key->g);
141 buf_putmpint(buf, key->y);
142
143 }
144
145 /* Same as buf_put_dss_pub_key, but with the private "x" key appended */
146 void buf_put_dss_priv_key(buffer* buf, dss_key *key) {
147
148 assert(key != NULL);
149 buf_put_dss_pub_key(buf, key);
150 buf_putmpint(buf, key->x);
151
152 }
153
154 #ifdef DROPBEAR_SIGNKEY_VERIFY
155 /* Verify a DSS signature (in buf) made on data by the key given.
156 * returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
157 int buf_dss_verify(buffer* buf, dss_key *key, const unsigned char* data,
158 unsigned int len) {
159
160 unsigned char msghash[SHA1_HASH_SIZE];
161 hash_state hs;
162 int ret = DROPBEAR_FAILURE;
163 mp_int val1, val2, val3, val4;
164 char * string = NULL;
165 int stringlen;
166
167 TRACE(("enter buf_dss_verify"));
168 assert(key != NULL);
169
170 /* get blob, check length */
171 string = buf_getstring(buf, &stringlen);
172 if (stringlen != 2*SHA1_HASH_SIZE) {
173 goto out;
174 }
175
176 /* hash the data */
177 sha1_init(&hs);
178 sha1_process(&hs, data, len);
179 sha1_done(&hs, msghash);
180
181 m_mp_init_multi(&val1, &val2, &val3, &val4, NULL);
182
183 /* create the signature - s' and r' are the received signatures in buf */
184 /* w = (s')-1 mod q */
185 /* let val1 = s' */
186 if (mp_read_unsigned_bin(&val1, &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE)
187 != MP_OKAY) {
188 goto out;
189 }
190 if (mp_cmp(&val1, key->q) != MP_LT) {
191 TRACE(("verify failed, s' >= q"));
192 goto out;
193 }
194 /* let val2 = w = (s')^-1 mod q*/
195 if (mp_invmod(&val1, key->q, &val2) != MP_OKAY) {
196 goto out;
197 }
198
199 /* u1 = ((SHA(M')w) mod q */
200 /* let val1 = SHA(M') = msghash */
201 if (mp_read_unsigned_bin(&val1, msghash, SHA1_HASH_SIZE) != MP_OKAY) {
202 goto out;
203 }
204 /* let val3 = u1 = ((SHA(M')w) mod q */
205 if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
206 goto out;
207 }
208
209 /* u2 = ((r')w) mod q */
210 /* let val1 = r' */
211 if (mp_read_unsigned_bin(&val1, &string[0], SHA1_HASH_SIZE)
212 != MP_OKAY) {
213 goto out;
214 }
215 if (mp_cmp(&val1, key->q) != MP_LT) {
216 TRACE(("verify failed, r' >= q"));
217 goto out;
218 }
219 /* let val4 = u2 = ((r')w) mod q */
220 if (mp_mulmod(&val1, &val2, key->q, &val4) != MP_OKAY) {
221 goto out;
222 }
223
224 /* v = (((g)^u1 (y)^u2) mod p) mod q */
225 /* val2 = g^u1 mod p */
226 if (mp_exptmod(key->g, &val3, key->p, &val2) != MP_OKAY) {
227 goto out;
228 }
229 /* val3 = y^u2 mod p */
230 if (mp_exptmod(key->y, &val4, key->p, &val3) != MP_OKAY) {
231 goto out;
232 }
233 /* val4 = ((g)^u1 (y)^u2) mod p */
234 if (mp_mulmod(&val2, &val3, key->p, &val4) != MP_OKAY) {
235 goto out;
236 }
237 /* val2 = v = (((g)^u1 (y)^u2) mod p) mod q */
238 if (mp_mod(&val4, key->q, &val2) != MP_OKAY) {
239 goto out;
240 }
241
242 /* check whether signatures verify */
243 if (mp_cmp(&val2, &val1) == MP_EQ) {
244 /* good sig */
245 ret = DROPBEAR_SUCCESS;
246 }
247
248 out:
249 mp_clear_multi(&val1, &val2, &val3, &val4, NULL);
250 m_free(string);
251
252 return ret;
253
254 }
255 #endif /* DROPBEAR_SIGNKEY_VERIFY */
256
257 /* Sign the data presented with key, writing the signature contents
258 * to the buffer
259 *
260 * When DSS_PROTOK is #defined:
261 * The alternate k generation method is based on the method used in PuTTY.
262 * In particular to avoid being vulnerable to attacks using flaws in random
263 * generation of k, we use the following:
264 *
265 * proto_k = SHA512 ( SHA512(x) || SHA160(message) )
266 * k = proto_k mod q
267 *
268 * Now we aren't relying on the random number generation to protect the private
269 * key x, which is a long term secret */
270 void buf_put_dss_sign(buffer* buf, dss_key *key, const unsigned char* data,
271 unsigned int len) {
272
273 unsigned char msghash[SHA1_HASH_SIZE];
274 unsigned int writelen;
275 unsigned int i;
276 #ifdef DSS_PROTOK
277 unsigned char privkeyhash[SHA512_HASH_SIZE];
278 unsigned char *privkeytmp;
279 unsigned char proto_k[SHA512_HASH_SIZE];
280 mp_int dss_protok;
281 #else
282 unsigned char kbuf[SHA1_HASH_SIZE];
283 #endif
284 mp_int dss_k, dss_m;
285 mp_int dss_temp1, dss_temp2;
286 mp_int dss_r, dss_s;
287 hash_state hs;
288
289 TRACE(("enter buf_put_dss_sign"));
290 assert(key != NULL);
291
292 /* hash the data */
293 sha1_init(&hs);
294 sha1_process(&hs, data, len);
295 sha1_done(&hs, msghash);
296
297 m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
298 &dss_m, NULL);
299 #ifdef DSS_PROTOK
300 /* hash the privkey */
301 privkeytmp = mptobytes(key->x, &i);
302 sha512_init(&hs);
303 sha512_process(&hs, "the quick brown fox jumped over the lazy dog", 44);
304 sha512_process(&hs, privkeytmp, i);
305 sha512_done(&hs, privkeyhash);
306 m_burn(privkeytmp, i);
307 m_free(privkeytmp);
308
309 /* calculate proto_k */
310 sha512_init(&hs);
311 sha512_process(&hs, privkeyhash, SHA512_HASH_SIZE);
312 sha512_process(&hs, msghash, SHA1_HASH_SIZE);
313 sha512_done(&hs, proto_k);
314
315 /* generate k */
316 m_mp_init(&dss_protok);
317 bytestomp(&dss_protok, proto_k, SHA512_HASH_SIZE);
318 mp_mod(&dss_protok, key->q, &dss_k);
319 mp_clear(&dss_protok);
320 m_burn(proto_k, SHA512_HASH_SIZE);
321 #else /* DSS_PROTOK not defined*/
322 do {
323 genrandom(kbuf, SHA1_HASH_SIZE);
324 if (mp_read_unsigned_bin(&dss_k, kbuf, SHA1_HASH_SIZE) != MP_OKAY) {
325 dropbear_exit("dss error");
326 }
327 } while (mp_cmp(&dss_k, key->q) == MP_GT || mp_cmp_d(&dss_k, 0) != MP_GT);
328 m_burn(kbuf, SHA1_HASH_SIZE);
329 #endif
330
331 /* now generate the actual signature */
332 bytestomp(&dss_m, msghash, SHA1_HASH_SIZE);
333
334 /* g^k mod p */
335 if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) != MP_OKAY) {
336 dropbear_exit("dss error");
337 }
338 /* r = (g^k mod p) mod q */
339 if (mp_mod(&dss_temp1, key->q, &dss_r) != MP_OKAY) {
340 dropbear_exit("dss error");
341 }
342
343 /* x*r mod q */
344 if (mp_mulmod(&dss_r, key->x, key->q, &dss_temp1) != MP_OKAY) {
345 dropbear_exit("dss error");
346 }
347 /* (SHA1(M) + xr) mod q) */
348 if (mp_addmod(&dss_m, &dss_temp1, key->q, &dss_temp2) != MP_OKAY) {
349 dropbear_exit("dss error");
350 }
351
352 /* (k^-1) mod q */
353 if (mp_invmod(&dss_k, key->q, &dss_temp1) != MP_OKAY) {
354 dropbear_exit("dss error");
355 }
356
357 /* s = (k^-1(SHA1(M) + xr)) mod q */
358 if (mp_mulmod(&dss_temp1, &dss_temp2, key->q, &dss_s) != MP_OKAY) {
359 dropbear_exit("dss error");
360 }
361
362 buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
363 buf_putint(buf, 2*SHA1_HASH_SIZE);
364
365 writelen = mp_unsigned_bin_size(&dss_r);
366 assert(writelen <= SHA1_HASH_SIZE);
367 /* need to pad to 160 bits with leading zeros */
368 for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
369 buf_putbyte(buf, 0);
370 }
371 if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
372 != MP_OKAY) {
373 dropbear_exit("dss error");
374 }
375 mp_clear(&dss_r);
376 buf_incrwritepos(buf, writelen);
377
378 writelen = mp_unsigned_bin_size(&dss_s);
379 assert(writelen <= SHA1_HASH_SIZE);
380 /* need to pad to 160 bits with leading zeros */
381 for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
382 buf_putbyte(buf, 0);
383 }
384 if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
385 != MP_OKAY) {
386 dropbear_exit("dss error");
387 }
388 mp_clear(&dss_s);
389 buf_incrwritepos(buf, writelen);
390
391 mp_clear_multi(&dss_k, &dss_temp1, &dss_temp1, &dss_r, &dss_s,
392 &dss_m, NULL);
393
394 /* create the signature to return */
395
396 TRACE(("leave buf_put_dss_sign"));
397 }
398
399 #endif /* DROPBEAR_DSS */