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
]);
100 static void *dss_newkey(char *data
, int len
) {
105 dss
= smalloc(sizeof(struct dss_key
));
106 if (!dss
) return NULL
;
107 getstring(&data
, &len
, &p
, &slen
);
114 printf(" %02x", (unsigned char)(data
[i
]));
119 if (!p
|| memcmp(p
, "ssh-dss", 7)) {
123 dss
->p
= getmp(&data
, &len
);
124 dss
->q
= getmp(&data
, &len
);
125 dss
->g
= getmp(&data
, &len
);
126 dss
->y
= getmp(&data
, &len
);
131 static void dss_freekey(void *key
) {
132 struct dss_key
*dss
= (struct dss_key
*)key
;
140 static char *dss_fmtkey(void *key
) {
141 struct dss_key
*dss
= (struct dss_key
*)key
;
143 int len
, i
, pos
, nibbles
;
144 static const char hex
[] = "0123456789abcdef";
147 len
= 8 + 4 + 1; /* 4 x "0x", punctuation, \0 */
148 len
+= 4 * (dss
->p
[0] + dss
->q
[0] + dss
->g
[0] + dss
->y
[0]); /* digits */
153 pos
+= sprintf(p
+pos
, "0x");
154 nibbles
= (3 + ssh1_bignum_bitcount(dss
->p
))/4; if (nibbles
<1) nibbles
=1;
155 for (i
=nibbles
; i
-- ;)
156 p
[pos
++] = hex
[(bignum_byte(dss
->p
, i
/2) >> (4*(i
%2))) & 0xF];
157 pos
+= sprintf(p
+pos
, ",0x");
158 nibbles
= (3 + ssh1_bignum_bitcount(dss
->q
))/4; if (nibbles
<1) nibbles
=1;
159 for (i
=nibbles
; i
-- ;)
160 p
[pos
++] = hex
[(bignum_byte(dss
->q
, i
/2) >> (4*(i
%2))) & 0xF];
161 pos
+= sprintf(p
+pos
, ",0x");
162 nibbles
= (3 + ssh1_bignum_bitcount(dss
->g
))/4; if (nibbles
<1) nibbles
=1;
163 for (i
=nibbles
; i
-- ;)
164 p
[pos
++] = hex
[(bignum_byte(dss
->g
, i
/2) >> (4*(i
%2))) & 0xF];
165 pos
+= sprintf(p
+pos
, ",0x");
166 nibbles
= (3 + ssh1_bignum_bitcount(dss
->y
))/4; if (nibbles
<1) nibbles
=1;
167 for (i
=nibbles
; i
-- ;)
168 p
[pos
++] = hex
[(bignum_byte(dss
->y
, i
/2) >> (4*(i
%2))) & 0xF];
173 static char *dss_fingerprint(void *key
) {
174 struct dss_key
*dss
= (struct dss_key
*)key
;
175 struct MD5Context md5c
;
176 unsigned char digest
[16], lenbuf
[4];
177 char buffer
[16*3+40];
182 MD5Update(&md5c
, "\0\0\0\7ssh-dss", 11);
184 #define ADD_BIGNUM(bignum) \
185 numlen = (ssh1_bignum_bitcount(bignum)+8)/8; \
186 PUT_32BIT(lenbuf, numlen); MD5Update(&md5c, lenbuf, 4); \
187 for (i = numlen; i-- ;) { \
188 unsigned char c = bignum_byte(bignum, i); \
189 MD5Update(&md5c, &c, 1); \
197 MD5Final(digest
, &md5c
);
199 sprintf(buffer
, "%d ", ssh1_bignum_bitcount(dss
->p
));
200 for (i
= 0; i
< 16; i
++)
201 sprintf(buffer
+strlen(buffer
), "%s%02x", i?
":":"", digest
[i
]);
202 ret
= smalloc(strlen(buffer
)+1);
208 static int dss_verifysig(void *key
, char *sig
, int siglen
,
209 char *data
, int datalen
) {
210 struct dss_key
*dss
= (struct dss_key
*)key
;
214 Bignum r
, s
, w
, gu1p
, yu2p
, gu1yu2p
, u1
, u2
, sha
, v
;
224 for (i
=0;i
<siglen
;i
++)
225 printf(" %02xf", (unsigned char)(sig
[i
]));
230 * Commercial SSH (2.0.13) and OpenSSH disagree over the format
231 * of a DSA signature. OpenSSH is in line with the IETF drafts:
232 * it uses a string "ssh-dss", followed by a 40-byte string
233 * containing two 160-bit integers end-to-end. Commercial SSH
234 * can't be bothered with the header bit, and considers a DSA
235 * signature blob to be _just_ the 40-byte string containing
236 * the two 160-bit integers. We tell them apart by measuring
237 * the length: length 40 means the commercial-SSH bug, anything
238 * else is assumed to be IETF-compliant.
240 if (siglen
!= 40) { /* bug not present; read admin fields */
241 getstring(&sig
, &siglen
, &p
, &slen
);
242 if (!p
|| memcmp(p
, "ssh-dss", 7)) {
245 sig
+= 4, siglen
-= 4; /* skip yet another length field */
247 diagbn("p=", dss
->p
);
248 diagbn("q=", dss
->q
);
249 diagbn("g=", dss
->g
);
250 diagbn("y=", dss
->y
);
251 r
= get160(&sig
, &siglen
);
253 s
= get160(&sig
, &siglen
);
259 * Step 1. w <- s^-1 mod q.
261 w
= modinv(s
, dss
->q
);
265 * Step 2. u1 <- SHA(message) * w mod q.
267 SHA_Simple(data
, datalen
, hash
);
268 p
= hash
; slen
= 20; sha
= get160(&p
, &slen
);
270 u1
= modmul(sha
, w
, dss
->q
);
274 * Step 3. u2 <- r * w mod q.
276 u2
= modmul(r
, w
, dss
->q
);
280 * Step 4. v <- (g^u1 * y^u2 mod p) mod q.
282 gu1p
= modpow(dss
->g
, u1
, dss
->p
);
283 diagbn("gu1p=", gu1p
);
284 yu2p
= modpow(dss
->y
, u2
, dss
->p
);
285 diagbn("yu2p=", yu2p
);
286 gu1yu2p
= modmul(gu1p
, yu2p
, dss
->p
);
287 diagbn("gu1yu2p=", gu1yu2p
);
288 v
= modmul(gu1yu2p
, One
, dss
->q
);
289 diagbn("gu1yu2q=v=", v
);
293 * Step 5. v should now be equal to r.
296 ret
= !bignum_cmp(v
, r
);
310 int dss_sign(void *key
, char *sig
, int siglen
,
311 char *data
, int datalen
) {
312 return 0; /* do nothing */
315 struct ssh_signkey ssh_dss
= {