374330e2 |
1 | /* |
2 | * RSA implementation just sufficient for ssh client-side |
3 | * initialisation step |
4644b0ce |
4 | * |
5 | * Rewritten for more speed by Joris van Rantwijk, Jun 1999. |
374330e2 |
6 | */ |
7 | |
374330e2 |
8 | #include <stdio.h> |
9 | #include <stdlib.h> |
10 | #include <string.h> |
11 | |
e5574168 |
12 | #include "ssh.h" |
374330e2 |
13 | |
1c2a93c4 |
14 | |
374330e2 |
15 | int makekey(unsigned char *data, struct RSAKey *result, |
7cca0d81 |
16 | unsigned char **keystr, int order) { |
374330e2 |
17 | unsigned char *p = data; |
7cca0d81 |
18 | int i; |
374330e2 |
19 | |
a52f067e |
20 | if (result) { |
21 | result->bits = 0; |
22 | for (i=0; i<4; i++) |
23 | result->bits = (result->bits << 8) + *p++; |
24 | } else |
25 | p += 4; |
374330e2 |
26 | |
7cca0d81 |
27 | /* |
28 | * order=0 means exponent then modulus (the keys sent by the |
29 | * server). order=1 means modulus then exponent (the keys |
30 | * stored in a keyfile). |
31 | */ |
374330e2 |
32 | |
7cca0d81 |
33 | if (order == 0) |
a52f067e |
34 | p += ssh1_read_bignum(p, result ? &result->exponent : NULL); |
35 | if (result) |
36 | result->bytes = (((p[0] << 8) + p[1]) + 7) / 8; |
7cca0d81 |
37 | if (keystr) *keystr = p+2; |
a52f067e |
38 | p += ssh1_read_bignum(p, result ? &result->modulus : NULL); |
7cca0d81 |
39 | if (order == 1) |
a52f067e |
40 | p += ssh1_read_bignum(p, result ? &result->exponent : NULL); |
374330e2 |
41 | |
42 | return p - data; |
43 | } |
44 | |
7cca0d81 |
45 | int makeprivate(unsigned char *data, struct RSAKey *result) { |
46 | return ssh1_read_bignum(data, &result->private_exponent); |
47 | } |
48 | |
374330e2 |
49 | void rsaencrypt(unsigned char *data, int length, struct RSAKey *key) { |
50 | Bignum b1, b2; |
51 | int w, i; |
52 | unsigned char *p; |
53 | |
374330e2 |
54 | memmove(data+key->bytes-length, data, length); |
55 | data[0] = 0; |
56 | data[1] = 2; |
57 | |
58 | for (i = 2; i < key->bytes-length-1; i++) { |
59 | do { |
60 | data[i] = random_byte(); |
61 | } while (data[i] == 0); |
62 | } |
63 | data[key->bytes-length-1] = 0; |
64 | |
65 | w = (key->bytes+1)/2; |
66 | |
67 | b1 = newbn(w); |
68 | b2 = newbn(w); |
69 | |
70 | p = data; |
71 | for (i=1; i<=w; i++) |
72 | b1[i] = 0; |
d9373729 |
73 | for (i=key->bytes; i-- ;) { |
374330e2 |
74 | unsigned char byte = *p++; |
d9373729 |
75 | if (i & 1) |
76 | b1[1+i/2] |= byte<<8; |
374330e2 |
77 | else |
d9373729 |
78 | b1[1+i/2] |= byte; |
374330e2 |
79 | } |
80 | |
374330e2 |
81 | modpow(b1, key->exponent, key->modulus, b2); |
82 | |
374330e2 |
83 | p = data; |
d9373729 |
84 | for (i=key->bytes; i-- ;) { |
374330e2 |
85 | unsigned char b; |
86 | if (i & 1) |
d9373729 |
87 | b = b2[1+i/2] >> 8; |
374330e2 |
88 | else |
d9373729 |
89 | b = b2[1+i/2] & 0xFF; |
374330e2 |
90 | *p++ = b; |
91 | } |
92 | |
93 | freebn(b1); |
94 | freebn(b2); |
95 | } |
96 | |
7cca0d81 |
97 | Bignum rsadecrypt(Bignum input, struct RSAKey *key) { |
98 | Bignum ret; |
99 | ret = newbn(key->modulus[0]); |
100 | modpow(input, key->private_exponent, key->modulus, ret); |
101 | return ret; |
102 | } |
103 | |
374330e2 |
104 | int rsastr_len(struct RSAKey *key) { |
105 | Bignum md, ex; |
106 | |
107 | md = key->modulus; |
108 | ex = key->exponent; |
d5859615 |
109 | return 4 * (ex[0]+md[0]) + 20; |
374330e2 |
110 | } |
111 | |
112 | void rsastr_fmt(char *str, struct RSAKey *key) { |
113 | Bignum md, ex; |
d5859615 |
114 | int len = 0, i, nibbles; |
115 | static const char hex[] = "0123456789abcdef"; |
374330e2 |
116 | |
117 | md = key->modulus; |
118 | ex = key->exponent; |
119 | |
d5859615 |
120 | len += sprintf(str+len, "0x"); |
121 | |
122 | nibbles = (3 + ssh1_bignum_bitcount(ex))/4; if (nibbles<1) nibbles=1; |
123 | for (i=nibbles; i-- ;) |
124 | str[len++] = hex[(bignum_byte(ex, i/2) >> (4*(i%2))) & 0xF]; |
125 | |
126 | len += sprintf(str+len, ",0x"); |
127 | |
128 | nibbles = (3 + ssh1_bignum_bitcount(md))/4; if (nibbles<1) nibbles=1; |
129 | for (i=nibbles; i-- ;) |
130 | str[len++] = hex[(bignum_byte(md, i/2) >> (4*(i%2))) & 0xF]; |
131 | |
374330e2 |
132 | str[len] = '\0'; |
133 | } |
134 | |
1c2a93c4 |
135 | /* |
136 | * Generate a fingerprint string for the key. Compatible with the |
137 | * OpenSSH fingerprint code. |
138 | */ |
139 | void rsa_fingerprint(char *str, int len, struct RSAKey *key) { |
140 | struct MD5Context md5c; |
141 | unsigned char digest[16]; |
142 | char buffer[16*3+40]; |
143 | int numlen, slen, i; |
144 | |
145 | MD5Init(&md5c); |
146 | numlen = ssh1_bignum_length(key->modulus) - 2; |
147 | for (i = numlen; i-- ;) { |
148 | unsigned char c = bignum_byte(key->modulus, i); |
149 | MD5Update(&md5c, &c, 1); |
150 | } |
151 | numlen = ssh1_bignum_length(key->exponent) - 2; |
152 | for (i = numlen; i-- ;) { |
153 | unsigned char c = bignum_byte(key->exponent, i); |
154 | MD5Update(&md5c, &c, 1); |
155 | } |
156 | MD5Final(digest, &md5c); |
157 | |
158 | sprintf(buffer, "%d ", ssh1_bignum_bitcount(key->modulus)); |
159 | for (i = 0; i < 16; i++) |
160 | sprintf(buffer+strlen(buffer), "%s%02x", i?":":"", digest[i]); |
161 | strncpy(str, buffer, len); str[len-1] = '\0'; |
162 | slen = strlen(str); |
163 | if (key->comment && slen < len-1) { |
164 | str[slen] = ' '; |
165 | strncpy(str+slen+1, key->comment, len-slen-1); |
166 | str[len-1] = '\0'; |
167 | } |
168 | } |
169 | |
5c58ad2d |
170 | void freersakey(struct RSAKey *key) { |
171 | if (key->modulus) freebn(key->modulus); |
172 | if (key->exponent) freebn(key->exponent); |
173 | if (key->private_exponent) freebn(key->private_exponent); |
174 | if (key->comment) free(key->comment); |
175 | } |