dropbear 2016.73
[tomato.git] / release / src / router / dropbear / dss.c
blobb771ec0439c4a110fc0bd7f5d1a32644aaca90f9
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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. */
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 "dbrandom.h"
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.
37 * See FIPS186 or the Handbook of Applied Cryptography for details of the
38 * algorithm */
40 #ifdef DROPBEAR_DSS
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, dropbear_dss_key *key) {
48 TRACE(("enter buf_get_dss_pub_key"))
49 dropbear_assert(key != NULL);
50 m_mp_alloc_init_multi(&key->p, &key->q, &key->g, &key->y, NULL);
51 key->x = NULL;
53 buf_incrpos(buf, 4+SSH_SIGNKEY_DSS_LEN); /* int + "ssh-dss" */
54 if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE
55 || buf_getmpint(buf, key->q) == DROPBEAR_FAILURE
56 || buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
57 || buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
58 TRACE(("leave buf_get_dss_pub_key: failed reading mpints"))
59 return DROPBEAR_FAILURE;
62 if (mp_count_bits(key->p) < MIN_DSS_KEYLEN) {
63 dropbear_log(LOG_WARNING, "DSS key too short");
64 TRACE(("leave buf_get_dss_pub_key: short key"))
65 return DROPBEAR_FAILURE;
68 TRACE(("leave buf_get_dss_pub_key: success"))
69 return DROPBEAR_SUCCESS;
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, dropbear_dss_key *key) {
77 int ret = DROPBEAR_FAILURE;
79 dropbear_assert(key != NULL);
81 ret = buf_get_dss_pub_key(buf, key);
82 if (ret == DROPBEAR_FAILURE) {
83 return DROPBEAR_FAILURE;
86 m_mp_alloc_init_multi(&key->x, NULL);
87 ret = buf_getmpint(buf, key->x);
88 if (ret == DROPBEAR_FAILURE) {
89 m_free(key->x);
92 return ret;
96 /* Clear and free the memory used by a public or private key */
97 void dss_key_free(dropbear_dss_key *key) {
99 TRACE2(("enter dsa_key_free"))
100 if (key == NULL) {
101 TRACE2(("enter dsa_key_free: key == NULL"))
102 return;
104 if (key->p) {
105 mp_clear(key->p);
106 m_free(key->p);
108 if (key->q) {
109 mp_clear(key->q);
110 m_free(key->q);
112 if (key->g) {
113 mp_clear(key->g);
114 m_free(key->g);
116 if (key->y) {
117 mp_clear(key->y);
118 m_free(key->y);
120 if (key->x) {
121 mp_clear(key->x);
122 m_free(key->x);
124 m_free(key);
125 TRACE2(("leave dsa_key_free"))
128 /* put the dss public key into the buffer in the required format:
130 * string "ssh-dss"
131 * mpint p
132 * mpint q
133 * mpint g
134 * mpint y
136 void buf_put_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
138 dropbear_assert(key != NULL);
139 buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
140 buf_putmpint(buf, key->p);
141 buf_putmpint(buf, key->q);
142 buf_putmpint(buf, key->g);
143 buf_putmpint(buf, key->y);
147 /* Same as buf_put_dss_pub_key, but with the private "x" key appended */
148 void buf_put_dss_priv_key(buffer* buf, dropbear_dss_key *key) {
150 dropbear_assert(key != NULL);
151 buf_put_dss_pub_key(buf, key);
152 buf_putmpint(buf, key->x);
156 #ifdef DROPBEAR_SIGNKEY_VERIFY
157 /* Verify a DSS signature (in buf) made on data by the key given.
158 * returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
159 int buf_dss_verify(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
160 unsigned char msghash[SHA1_HASH_SIZE];
161 hash_state hs;
162 int ret = DROPBEAR_FAILURE;
163 DEF_MP_INT(val1);
164 DEF_MP_INT(val2);
165 DEF_MP_INT(val3);
166 DEF_MP_INT(val4);
167 char * string = NULL;
168 unsigned int stringlen;
170 TRACE(("enter buf_dss_verify"))
171 dropbear_assert(key != NULL);
173 m_mp_init_multi(&val1, &val2, &val3, &val4, NULL);
175 /* get blob, check length */
176 string = buf_getstring(buf, &stringlen);
177 if (stringlen != 2*SHA1_HASH_SIZE) {
178 goto out;
181 /* hash the data */
182 sha1_init(&hs);
183 sha1_process(&hs, data_buf->data, data_buf->len);
184 sha1_done(&hs, msghash);
186 /* create the signature - s' and r' are the received signatures in buf */
187 /* w = (s')-1 mod q */
188 /* let val1 = s' */
189 bytes_to_mp(&val1, (const unsigned char*) &string[SHA1_HASH_SIZE], SHA1_HASH_SIZE);
191 if (mp_cmp(&val1, key->q) != MP_LT) {
192 TRACE(("verify failed, s' >= q"))
193 goto out;
195 /* let val2 = w = (s')^-1 mod q*/
196 if (mp_invmod(&val1, key->q, &val2) != MP_OKAY) {
197 goto out;
200 /* u1 = ((SHA(M')w) mod q */
201 /* let val1 = SHA(M') = msghash */
202 bytes_to_mp(&val1, msghash, SHA1_HASH_SIZE);
204 /* let val3 = u1 = ((SHA(M')w) mod q */
205 if (mp_mulmod(&val1, &val2, key->q, &val3) != MP_OKAY) {
206 goto out;
209 /* u2 = ((r')w) mod q */
210 /* let val1 = r' */
211 bytes_to_mp(&val1, (const unsigned char*) &string[0], SHA1_HASH_SIZE);
212 if (mp_cmp(&val1, key->q) != MP_LT) {
213 TRACE(("verify failed, r' >= q"))
214 goto out;
216 /* let val4 = u2 = ((r')w) mod q */
217 if (mp_mulmod(&val1, &val2, key->q, &val4) != MP_OKAY) {
218 goto out;
221 /* v = (((g)^u1 (y)^u2) mod p) mod q */
222 /* val2 = g^u1 mod p */
223 if (mp_exptmod(key->g, &val3, key->p, &val2) != MP_OKAY) {
224 goto out;
226 /* val3 = y^u2 mod p */
227 if (mp_exptmod(key->y, &val4, key->p, &val3) != MP_OKAY) {
228 goto out;
230 /* val4 = ((g)^u1 (y)^u2) mod p */
231 if (mp_mulmod(&val2, &val3, key->p, &val4) != MP_OKAY) {
232 goto out;
234 /* val2 = v = (((g)^u1 (y)^u2) mod p) mod q */
235 if (mp_mod(&val4, key->q, &val2) != MP_OKAY) {
236 goto out;
239 /* check whether signatures verify */
240 if (mp_cmp(&val2, &val1) == MP_EQ) {
241 /* good sig */
242 ret = DROPBEAR_SUCCESS;
245 out:
246 mp_clear_multi(&val1, &val2, &val3, &val4, NULL);
247 m_free(string);
249 return ret;
252 #endif /* DROPBEAR_SIGNKEY_VERIFY */
254 /* Sign the data presented with key, writing the signature contents
255 * to the buffer */
256 void buf_put_dss_sign(buffer* buf, dropbear_dss_key *key, buffer *data_buf) {
257 unsigned char msghash[SHA1_HASH_SIZE];
258 unsigned int writelen;
259 unsigned int i;
260 DEF_MP_INT(dss_k);
261 DEF_MP_INT(dss_m);
262 DEF_MP_INT(dss_temp1);
263 DEF_MP_INT(dss_temp2);
264 DEF_MP_INT(dss_r);
265 DEF_MP_INT(dss_s);
266 hash_state hs;
268 TRACE(("enter buf_put_dss_sign"))
269 dropbear_assert(key != NULL);
271 /* hash the data */
272 sha1_init(&hs);
273 sha1_process(&hs, data_buf->data, data_buf->len);
274 sha1_done(&hs, msghash);
276 m_mp_init_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
277 &dss_m, NULL);
278 /* the random number generator's input has included the private key which
279 * avoids DSS's problem of private key exposure due to low entropy */
280 gen_random_mpint(key->q, &dss_k);
282 /* now generate the actual signature */
283 bytes_to_mp(&dss_m, msghash, SHA1_HASH_SIZE);
285 /* g^k mod p */
286 if (mp_exptmod(key->g, &dss_k, key->p, &dss_temp1) != MP_OKAY) {
287 dropbear_exit("DSS error");
289 /* r = (g^k mod p) mod q */
290 if (mp_mod(&dss_temp1, key->q, &dss_r) != MP_OKAY) {
291 dropbear_exit("DSS error");
294 /* x*r mod q */
295 if (mp_mulmod(&dss_r, key->x, key->q, &dss_temp1) != MP_OKAY) {
296 dropbear_exit("DSS error");
298 /* (SHA1(M) + xr) mod q) */
299 if (mp_addmod(&dss_m, &dss_temp1, key->q, &dss_temp2) != MP_OKAY) {
300 dropbear_exit("DSS error");
303 /* (k^-1) mod q */
304 if (mp_invmod(&dss_k, key->q, &dss_temp1) != MP_OKAY) {
305 dropbear_exit("DSS error");
308 /* s = (k^-1(SHA1(M) + xr)) mod q */
309 if (mp_mulmod(&dss_temp1, &dss_temp2, key->q, &dss_s) != MP_OKAY) {
310 dropbear_exit("DSS error");
313 buf_putstring(buf, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN);
314 buf_putint(buf, 2*SHA1_HASH_SIZE);
316 writelen = mp_unsigned_bin_size(&dss_r);
317 dropbear_assert(writelen <= SHA1_HASH_SIZE);
318 /* need to pad to 160 bits with leading zeros */
319 for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
320 buf_putbyte(buf, 0);
322 if (mp_to_unsigned_bin(&dss_r, buf_getwriteptr(buf, writelen))
323 != MP_OKAY) {
324 dropbear_exit("DSS error");
326 mp_clear(&dss_r);
327 buf_incrwritepos(buf, writelen);
329 writelen = mp_unsigned_bin_size(&dss_s);
330 dropbear_assert(writelen <= SHA1_HASH_SIZE);
331 /* need to pad to 160 bits with leading zeros */
332 for (i = 0; i < SHA1_HASH_SIZE - writelen; i++) {
333 buf_putbyte(buf, 0);
335 if (mp_to_unsigned_bin(&dss_s, buf_getwriteptr(buf, writelen))
336 != MP_OKAY) {
337 dropbear_exit("DSS error");
339 mp_clear(&dss_s);
340 buf_incrwritepos(buf, writelen);
342 mp_clear_multi(&dss_k, &dss_temp1, &dss_temp2, &dss_r, &dss_s,
343 &dss_m, NULL);
345 /* create the signature to return */
347 TRACE(("leave buf_put_dss_sign"))
350 #endif /* DROPBEAR_DSS */