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