6 #define GET_32BIT(cp) \
7 (((unsigned long)(unsigned char)(cp)[0] << 24) | \
8 ((unsigned long)(unsigned char)(cp)[1] << 16) | \
9 ((unsigned long)(unsigned char)(cp)[2] << 8) | \
10 ((unsigned long)(unsigned char)(cp)[3]))
12 #define PUT_32BIT(cp, value) { \
13 (cp)[0] = (unsigned char)((value) >> 24); \
14 (cp)[1] = (unsigned char)((value) >> 16); \
15 (cp)[2] = (unsigned char)((value) >> 8); \
16 (cp)[3] = (unsigned char)(value); }
20 * Condition this section in for debugging of DSS.
22 static void diagbn(char *prefix
, Bignum md
) {
23 int i
, nibbles
, morenibbles
;
24 static const char hex
[] = "0123456789ABCDEF";
26 printf("%s0x", prefix ? prefix
: "");
28 nibbles
= (3 + ssh1_bignum_bitcount(md
))/4; if (nibbles
<1) nibbles
=1;
29 morenibbles
= 4*md
[0] - nibbles
;
30 for (i
=0; i
<morenibbles
; i
++) putchar('-');
31 for (i
=nibbles
; i
-- ;)
32 putchar(hex
[(bignum_byte(md
, i
/2) >> (4*(i
%2))) & 0xF]);
34 if (prefix
) putchar('\n');
41 static void getstring(char **data
, int *datalen
, char **p
, int *length
) {
45 *length
= GET_32BIT(*data
);
46 *datalen
-= 4; *data
+= 4;
47 if (*datalen
< *length
)
50 *data
+= *length
; *datalen
-= *length
;
52 static Bignum
getmp(char **data
, int *datalen
) {
57 getstring(data
, datalen
, &p
, &length
);
61 return NULL
; /* negative mp */
62 b
= newbn((length
+1)/2);
63 for (i
= 0; i
< length
; i
++) {
66 b
[j
/2+1] |= ((unsigned char)p
[i
]) << 8;
68 b
[j
/2+1] |= ((unsigned char)p
[i
]);
70 while (b
[0] > 1 && b
[b
[0]] == 0) b
[0]--;
74 static Bignum
get160(char **data
, int *datalen
) {
80 *data
+= 20; *datalen
-= 20;
83 while (length
> 0 && !p
[0])
85 b
= newbn((length
+1)/2);
86 for (i
= 0; i
< length
; i
++) {
89 b
[j
/2+1] |= ((unsigned char)p
[i
]) << 8;
91 b
[j
/2+1] |= ((unsigned char)p
[i
]);
96 static Bignum dss_p
, dss_q
, dss_g
, dss_y
;
98 static void dss_setkey(char *data
, int len
) {
101 getstring(&data
, &len
, &p
, &slen
);
108 printf(" %02x", (unsigned char)(data
[i
]));
113 if (!p
|| memcmp(p
, "ssh-dss", 7)) {
117 dss_p
= getmp(&data
, &len
);
118 dss_q
= getmp(&data
, &len
);
119 dss_g
= getmp(&data
, &len
);
120 dss_y
= getmp(&data
, &len
);
123 static char *dss_fmtkey(void) {
125 int len
, i
, pos
, nibbles
;
126 static const char hex
[] = "0123456789abcdef";
129 len
= 8 + 4 + 1; /* 4 x "0x", punctuation, \0 */
130 len
+= 4 * (dss_p
[0] + dss_q
[0] + dss_g
[0] + dss_y
[0]); /* digits */
135 pos
+= sprintf(p
+pos
, "0x");
136 nibbles
= (3 + ssh1_bignum_bitcount(dss_p
))/4; if (nibbles
<1) nibbles
=1;
137 for (i
=nibbles
; i
-- ;)
138 p
[pos
++] = hex
[(bignum_byte(dss_p
, i
/2) >> (4*(i
%2))) & 0xF];
139 pos
+= sprintf(p
+pos
, ",0x");
140 nibbles
= (3 + ssh1_bignum_bitcount(dss_q
))/4; if (nibbles
<1) nibbles
=1;
141 for (i
=nibbles
; i
-- ;)
142 p
[pos
++] = hex
[(bignum_byte(dss_q
, i
/2) >> (4*(i
%2))) & 0xF];
143 pos
+= sprintf(p
+pos
, ",0x");
144 nibbles
= (3 + ssh1_bignum_bitcount(dss_g
))/4; if (nibbles
<1) nibbles
=1;
145 for (i
=nibbles
; i
-- ;)
146 p
[pos
++] = hex
[(bignum_byte(dss_g
, i
/2) >> (4*(i
%2))) & 0xF];
147 pos
+= sprintf(p
+pos
, ",0x");
148 nibbles
= (3 + ssh1_bignum_bitcount(dss_y
))/4; if (nibbles
<1) nibbles
=1;
149 for (i
=nibbles
; i
-- ;)
150 p
[pos
++] = hex
[(bignum_byte(dss_y
, i
/2) >> (4*(i
%2))) & 0xF];
155 static char *dss_fingerprint(void) {
156 struct MD5Context md5c
;
157 unsigned char digest
[16], lenbuf
[4];
158 char buffer
[16*3+40];
163 MD5Update(&md5c
, "\0\0\0\7ssh-dss", 11);
165 #define ADD_BIGNUM(bignum) \
166 numlen = (ssh1_bignum_bitcount(bignum)+8)/8; \
167 PUT_32BIT(lenbuf, numlen); MD5Update(&md5c, lenbuf, 4); \
168 for (i = numlen; i-- ;) { \
169 unsigned char c = bignum_byte(bignum, i); \
170 MD5Update(&md5c, &c, 1); \
178 MD5Final(digest
, &md5c
);
180 sprintf(buffer
, "%d ", ssh1_bignum_bitcount(dss_p
));
181 for (i
= 0; i
< 16; i
++)
182 sprintf(buffer
+strlen(buffer
), "%s%02x", i?
":":"", digest
[i
]);
183 ret
= malloc(strlen(buffer
)+1);
189 static int dss_verifysig(char *sig
, int siglen
, char *data
, int datalen
) {
193 Bignum r
, s
, w
, gu1p
, yu2p
, gu1yu2p
, u1
, u2
, sha
, v
;
203 for (i
=0;i
<siglen
;i
++)
204 printf(" %02xf", (unsigned char)(sig
[i
]));
209 * Commercial SSH (2.0.13) and OpenSSH disagree over the format
210 * of a DSA signature. OpenSSH is in line with the IETF drafts:
211 * it uses a string "ssh-dss", followed by a 40-byte string
212 * containing two 160-bit integers end-to-end. Commercial SSH
213 * can't be bothered with the header bit, and considers a DSA
214 * signature blob to be _just_ the 40-byte string containing
215 * the two 160-bit integers. We tell them apart by measuring
216 * the length: length 40 means the commercial-SSH bug, anything
217 * else is assumed to be IETF-compliant.
219 if (siglen
!= 40) { /* bug not present; read admin fields */
220 getstring(&sig
, &siglen
, &p
, &slen
);
221 if (!p
|| memcmp(p
, "ssh-dss", 7)) {
224 sig
+= 4, siglen
-= 4; /* skip yet another length field */
230 r
= get160(&sig
, &siglen
);
232 s
= get160(&sig
, &siglen
);
238 * Step 1. w <- s^-1 mod q.
240 w
= modinv(s
, dss_q
);
244 * Step 2. u1 <- SHA(message) * w mod q.
246 SHA_Simple(data
, datalen
, hash
);
247 p
= hash
; slen
= 20; sha
= get160(&p
, &slen
);
249 u1
= modmul(sha
, w
, dss_q
);
253 * Step 3. u2 <- r * w mod q.
255 u2
= modmul(r
, w
, dss_q
);
259 * Step 4. v <- (g^u1 * y^u2 mod p) mod q.
261 gu1p
= modpow(dss_g
, u1
, dss_p
);
262 diagbn("gu1p=", gu1p
);
263 yu2p
= modpow(dss_y
, u2
, dss_p
);
264 diagbn("yu2p=", yu2p
);
265 gu1yu2p
= modmul(gu1p
, yu2p
, dss_p
);
266 diagbn("gu1yu2p=", gu1yu2p
);
267 v
= modmul(gu1yu2p
, One
, dss_q
);
268 diagbn("gu1yu2q=v=", v
);
272 * Step 5. v should now be equal to r.
275 ret
= !bignum_cmp(v
, r
);
289 struct ssh_hostkey ssh_dss
= {