7 #define GET_32BIT(cp) \
8 (((unsigned long)(unsigned char)(cp)[0] << 24) | \
9 ((unsigned long)(unsigned char)(cp)[1] << 16) | \
10 ((unsigned long)(unsigned char)(cp)[2] << 8) | \
11 ((unsigned long)(unsigned char)(cp)[3]))
13 #define PUT_32BIT(cp, value) { \
14 (cp)[0] = (unsigned char)((value) >> 24); \
15 (cp)[1] = (unsigned char)((value) >> 16); \
16 (cp)[2] = (unsigned char)((value) >> 8); \
17 (cp)[3] = (unsigned char)(value); }
25 static void getstring(char **data
, int *datalen
, char **p
, int *length
) {
29 *length
= GET_32BIT(*data
);
30 *datalen
-= 4; *data
+= 4;
31 if (*datalen
< *length
)
34 *data
+= *length
; *datalen
-= *length
;
36 static Bignum
getmp(char **data
, int *datalen
) {
41 getstring(data
, datalen
, &p
, &length
);
45 return NULL
; /* negative mp */
46 b
= bignum_from_bytes(p
, length
);
50 static Bignum
get160(char **data
, int *datalen
) {
53 b
= bignum_from_bytes(*data
, 20);
54 *data
+= 20; *datalen
-= 20;
63 static void *dss_newkey(char *data
, int len
) {
68 dss
= smalloc(sizeof(struct dss_key
));
69 if (!dss
) return NULL
;
70 getstring(&data
, &len
, &p
, &slen
);
77 printf(" %02x", (unsigned char)(data
[i
]));
82 if (!p
|| memcmp(p
, "ssh-dss", 7)) {
86 dss
->p
= getmp(&data
, &len
);
87 dss
->q
= getmp(&data
, &len
);
88 dss
->g
= getmp(&data
, &len
);
89 dss
->y
= getmp(&data
, &len
);
94 static void dss_freekey(void *key
) {
95 struct dss_key
*dss
= (struct dss_key
*)key
;
103 static char *dss_fmtkey(void *key
) {
104 struct dss_key
*dss
= (struct dss_key
*)key
;
106 int len
, i
, pos
, nibbles
;
107 static const char hex
[] = "0123456789abcdef";
110 len
= 8 + 4 + 1; /* 4 x "0x", punctuation, \0 */
111 len
+= 4 * (ssh1_bignum_bitcount(dss
->p
)+15)/16;
112 len
+= 4 * (ssh1_bignum_bitcount(dss
->q
)+15)/16;
113 len
+= 4 * (ssh1_bignum_bitcount(dss
->g
)+15)/16;
114 len
+= 4 * (ssh1_bignum_bitcount(dss
->y
)+15)/16;
119 pos
+= sprintf(p
+pos
, "0x");
120 nibbles
= (3 + ssh1_bignum_bitcount(dss
->p
))/4; if (nibbles
<1) nibbles
=1;
121 for (i
=nibbles
; i
-- ;)
122 p
[pos
++] = hex
[(bignum_byte(dss
->p
, i
/2) >> (4*(i
%2))) & 0xF];
123 pos
+= sprintf(p
+pos
, ",0x");
124 nibbles
= (3 + ssh1_bignum_bitcount(dss
->q
))/4; if (nibbles
<1) nibbles
=1;
125 for (i
=nibbles
; i
-- ;)
126 p
[pos
++] = hex
[(bignum_byte(dss
->q
, i
/2) >> (4*(i
%2))) & 0xF];
127 pos
+= sprintf(p
+pos
, ",0x");
128 nibbles
= (3 + ssh1_bignum_bitcount(dss
->g
))/4; if (nibbles
<1) nibbles
=1;
129 for (i
=nibbles
; i
-- ;)
130 p
[pos
++] = hex
[(bignum_byte(dss
->g
, i
/2) >> (4*(i
%2))) & 0xF];
131 pos
+= sprintf(p
+pos
, ",0x");
132 nibbles
= (3 + ssh1_bignum_bitcount(dss
->y
))/4; if (nibbles
<1) nibbles
=1;
133 for (i
=nibbles
; i
-- ;)
134 p
[pos
++] = hex
[(bignum_byte(dss
->y
, i
/2) >> (4*(i
%2))) & 0xF];
139 static char *dss_fingerprint(void *key
) {
140 struct dss_key
*dss
= (struct dss_key
*)key
;
141 struct MD5Context md5c
;
142 unsigned char digest
[16], lenbuf
[4];
143 char buffer
[16*3+40];
148 MD5Update(&md5c
, "\0\0\0\7ssh-dss", 11);
150 #define ADD_BIGNUM(bignum) \
151 numlen = (ssh1_bignum_bitcount(bignum)+8)/8; \
152 PUT_32BIT(lenbuf, numlen); MD5Update(&md5c, lenbuf, 4); \
153 for (i = numlen; i-- ;) { \
154 unsigned char c = bignum_byte(bignum, i); \
155 MD5Update(&md5c, &c, 1); \
163 MD5Final(digest
, &md5c
);
165 sprintf(buffer
, "ssh-dss %d ", ssh1_bignum_bitcount(dss
->p
));
166 for (i
= 0; i
< 16; i
++)
167 sprintf(buffer
+strlen(buffer
), "%s%02x", i?
":":"", digest
[i
]);
168 ret
= smalloc(strlen(buffer
)+1);
174 static int dss_verifysig(void *key
, char *sig
, int siglen
,
175 char *data
, int datalen
) {
176 struct dss_key
*dss
= (struct dss_key
*)key
;
180 Bignum r
, s
, w
, gu1p
, yu2p
, gu1yu2p
, u1
, u2
, sha
, v
;
190 for (i
=0;i
<siglen
;i
++)
191 printf(" %02x", (unsigned char)(sig
[i
]));
196 * Commercial SSH (2.0.13) and OpenSSH disagree over the format
197 * of a DSA signature. OpenSSH is in line with the IETF drafts:
198 * it uses a string "ssh-dss", followed by a 40-byte string
199 * containing two 160-bit integers end-to-end. Commercial SSH
200 * can't be bothered with the header bit, and considers a DSA
201 * signature blob to be _just_ the 40-byte string containing
202 * the two 160-bit integers. We tell them apart by measuring
203 * the length: length 40 means the commercial-SSH bug, anything
204 * else is assumed to be IETF-compliant.
206 if (siglen
!= 40) { /* bug not present; read admin fields */
207 getstring(&sig
, &siglen
, &p
, &slen
);
208 if (!p
|| slen
!= 7 || memcmp(p
, "ssh-dss", 7)) {
211 sig
+= 4, siglen
-= 4; /* skip yet another length field */
213 diagbn("p=", dss
->p
);
214 diagbn("q=", dss
->q
);
215 diagbn("g=", dss
->g
);
216 diagbn("y=", dss
->y
);
217 r
= get160(&sig
, &siglen
);
219 s
= get160(&sig
, &siglen
);
225 * Step 1. w <- s^-1 mod q.
227 w
= modinv(s
, dss
->q
);
231 * Step 2. u1 <- SHA(message) * w mod q.
233 SHA_Simple(data
, datalen
, hash
);
234 p
= hash
; slen
= 20; sha
= get160(&p
, &slen
);
236 u1
= modmul(sha
, w
, dss
->q
);
240 * Step 3. u2 <- r * w mod q.
242 u2
= modmul(r
, w
, dss
->q
);
246 * Step 4. v <- (g^u1 * y^u2 mod p) mod q.
248 gu1p
= modpow(dss
->g
, u1
, dss
->p
);
249 diagbn("gu1p=", gu1p
);
250 yu2p
= modpow(dss
->y
, u2
, dss
->p
);
251 diagbn("yu2p=", yu2p
);
252 gu1yu2p
= modmul(gu1p
, yu2p
, dss
->p
);
253 diagbn("gu1yu2p=", gu1yu2p
);
254 v
= modmul(gu1yu2p
, One
, dss
->q
);
255 diagbn("gu1yu2q=v=", v
);
259 * Step 5. v should now be equal to r.
262 ret
= !bignum_cmp(v
, r
);
276 static unsigned char *dss_public_blob(void *key
, int *len
) {
277 struct dss_key
*dss
= (struct dss_key
*)key
;
278 int plen
, qlen
, glen
, ylen
, bloblen
;
280 unsigned char *blob
, *p
;
282 plen
= (ssh1_bignum_bitcount(dss
->p
)+8)/8;
283 qlen
= (ssh1_bignum_bitcount(dss
->q
)+8)/8;
284 glen
= (ssh1_bignum_bitcount(dss
->g
)+8)/8;
285 ylen
= (ssh1_bignum_bitcount(dss
->y
)+8)/8;
288 * string "ssh-dss", mpint p, mpint q, mpint g, mpint y. Total
289 * 27 + sum of lengths. (five length fields, 20+7=27).
291 bloblen
= 27+plen
+qlen
+glen
+ylen
;
292 blob
= smalloc(bloblen
);
294 PUT_32BIT(p
, 7); p
+= 4;
295 memcpy(p
, "ssh-dss", 7); p
+= 7;
296 PUT_32BIT(p
, plen
); p
+= 4;
297 for (i
= plen
; i
-- ;) *p
++ = bignum_byte(dss
->p
, i
);
298 PUT_32BIT(p
, qlen
); p
+= 4;
299 for (i
= qlen
; i
-- ;) *p
++ = bignum_byte(dss
->q
, i
);
300 PUT_32BIT(p
, glen
); p
+= 4;
301 for (i
= glen
; i
-- ;) *p
++ = bignum_byte(dss
->g
, i
);
302 PUT_32BIT(p
, ylen
); p
+= 4;
303 for (i
= ylen
; i
-- ;) *p
++ = bignum_byte(dss
->y
, i
);
304 assert(p
== blob
+ bloblen
);
309 static unsigned char *dss_private_blob(void *key
, int *len
) {
310 return NULL
; /* can't handle DSS private keys */
313 static void *dss_createkey(unsigned char *pub_blob
, int pub_len
,
314 unsigned char *priv_blob
, int priv_len
) {
315 return NULL
; /* can't handle DSS private keys */
318 static void *dss_openssh_createkey(unsigned char **blob
, int *len
) {
319 return NULL
; /* can't handle DSS private keys */
322 unsigned char *dss_sign(void *key
, char *data
, int datalen
, int *siglen
) {
323 return NULL
; /* can't handle DSS private keys */
326 const struct ssh_signkey ssh_dss
= {
333 dss_openssh_createkey
,