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); |
374330e2 |
68 | |
69 | p = data; |
70 | for (i=1; i<=w; i++) |
71 | b1[i] = 0; |
d9373729 |
72 | for (i=key->bytes; i-- ;) { |
374330e2 |
73 | unsigned char byte = *p++; |
d9373729 |
74 | if (i & 1) |
75 | b1[1+i/2] |= byte<<8; |
374330e2 |
76 | else |
d9373729 |
77 | b1[1+i/2] |= byte; |
374330e2 |
78 | } |
79 | |
59600f67 |
80 | b2 = modpow(b1, key->exponent, key->modulus); |
374330e2 |
81 | |
374330e2 |
82 | p = data; |
d9373729 |
83 | for (i=key->bytes; i-- ;) { |
374330e2 |
84 | unsigned char b; |
85 | if (i & 1) |
d9373729 |
86 | b = b2[1+i/2] >> 8; |
374330e2 |
87 | else |
d9373729 |
88 | b = b2[1+i/2] & 0xFF; |
374330e2 |
89 | *p++ = b; |
90 | } |
91 | |
92 | freebn(b1); |
93 | freebn(b2); |
94 | } |
95 | |
7cca0d81 |
96 | Bignum rsadecrypt(Bignum input, struct RSAKey *key) { |
97 | Bignum ret; |
59600f67 |
98 | ret = modpow(input, key->private_exponent, key->modulus); |
7cca0d81 |
99 | return ret; |
100 | } |
101 | |
374330e2 |
102 | int rsastr_len(struct RSAKey *key) { |
103 | Bignum md, ex; |
104 | |
105 | md = key->modulus; |
106 | ex = key->exponent; |
d5859615 |
107 | return 4 * (ex[0]+md[0]) + 20; |
374330e2 |
108 | } |
109 | |
110 | void rsastr_fmt(char *str, struct RSAKey *key) { |
111 | Bignum md, ex; |
d5859615 |
112 | int len = 0, i, nibbles; |
113 | static const char hex[] = "0123456789abcdef"; |
374330e2 |
114 | |
115 | md = key->modulus; |
116 | ex = key->exponent; |
117 | |
d5859615 |
118 | len += sprintf(str+len, "0x"); |
119 | |
120 | nibbles = (3 + ssh1_bignum_bitcount(ex))/4; if (nibbles<1) nibbles=1; |
121 | for (i=nibbles; i-- ;) |
122 | str[len++] = hex[(bignum_byte(ex, i/2) >> (4*(i%2))) & 0xF]; |
123 | |
124 | len += sprintf(str+len, ",0x"); |
125 | |
126 | nibbles = (3 + ssh1_bignum_bitcount(md))/4; if (nibbles<1) nibbles=1; |
127 | for (i=nibbles; i-- ;) |
128 | str[len++] = hex[(bignum_byte(md, i/2) >> (4*(i%2))) & 0xF]; |
129 | |
374330e2 |
130 | str[len] = '\0'; |
131 | } |
132 | |
1c2a93c4 |
133 | /* |
134 | * Generate a fingerprint string for the key. Compatible with the |
135 | * OpenSSH fingerprint code. |
136 | */ |
137 | void rsa_fingerprint(char *str, int len, struct RSAKey *key) { |
138 | struct MD5Context md5c; |
139 | unsigned char digest[16]; |
140 | char buffer[16*3+40]; |
141 | int numlen, slen, i; |
142 | |
143 | MD5Init(&md5c); |
144 | numlen = ssh1_bignum_length(key->modulus) - 2; |
145 | for (i = numlen; i-- ;) { |
146 | unsigned char c = bignum_byte(key->modulus, i); |
147 | MD5Update(&md5c, &c, 1); |
148 | } |
149 | numlen = ssh1_bignum_length(key->exponent) - 2; |
150 | for (i = numlen; i-- ;) { |
151 | unsigned char c = bignum_byte(key->exponent, i); |
152 | MD5Update(&md5c, &c, 1); |
153 | } |
154 | MD5Final(digest, &md5c); |
155 | |
156 | sprintf(buffer, "%d ", ssh1_bignum_bitcount(key->modulus)); |
157 | for (i = 0; i < 16; i++) |
158 | sprintf(buffer+strlen(buffer), "%s%02x", i?":":"", digest[i]); |
159 | strncpy(str, buffer, len); str[len-1] = '\0'; |
160 | slen = strlen(str); |
161 | if (key->comment && slen < len-1) { |
162 | str[slen] = ' '; |
163 | strncpy(str+slen+1, key->comment, len-slen-1); |
164 | str[len-1] = '\0'; |
165 | } |
166 | } |
167 | |
5c58ad2d |
168 | void freersakey(struct RSAKey *key) { |
169 | if (key->modulus) freebn(key->modulus); |
170 | if (key->exponent) freebn(key->exponent); |
171 | if (key->private_exponent) freebn(key->private_exponent); |
dcbde236 |
172 | if (key->comment) sfree(key->comment); |
5c58ad2d |
173 | } |