📄 sshrsa.c
字号:
void freersakey(struct RSAKey *key){ if (key->modulus) freebn(key->modulus); if (key->exponent) freebn(key->exponent); if (key->private_exponent) freebn(key->private_exponent); if (key->comment) sfree(key->comment);}/* ---------------------------------------------------------------------- * Implementation of the ssh-rsa signing key type. */static void getstring(char **data, int *datalen, char **p, int *length){ *p = NULL; if (*datalen < 4) return; *length = GET_32BIT(*data); *datalen -= 4; *data += 4; if (*datalen < *length) return; *p = *data; *data += *length; *datalen -= *length;}static Bignum getmp(char **data, int *datalen){ char *p; int length; Bignum b; getstring(data, datalen, &p, &length); if (!p) return NULL; b = bignum_from_bytes((unsigned char *)p, length); return b;}static void *rsa2_newkey(char *data, int len){ char *p; int slen; struct RSAKey *rsa; rsa = snew(struct RSAKey); if (!rsa) return NULL; getstring(&data, &len, &p, &slen); if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) { sfree(rsa); return NULL; } rsa->exponent = getmp(&data, &len); rsa->modulus = getmp(&data, &len); rsa->private_exponent = NULL; rsa->comment = NULL; return rsa;}static void rsa2_freekey(void *key){ struct RSAKey *rsa = (struct RSAKey *) key; freersakey(rsa); sfree(rsa);}static char *rsa2_fmtkey(void *key){ struct RSAKey *rsa = (struct RSAKey *) key; char *p; int len; len = rsastr_len(rsa); p = snewn(len, char); rsastr_fmt(p, rsa); return p;}static unsigned char *rsa2_public_blob(void *key, int *len){ struct RSAKey *rsa = (struct RSAKey *) key; int elen, mlen, bloblen; int i; unsigned char *blob, *p; elen = (bignum_bitcount(rsa->exponent) + 8) / 8; mlen = (bignum_bitcount(rsa->modulus) + 8) / 8; /* * string "ssh-rsa", mpint exp, mpint mod. Total 19+elen+mlen. * (three length fields, 12+7=19). */ bloblen = 19 + elen + mlen; blob = snewn(bloblen, unsigned char); p = blob; PUT_32BIT(p, 7); p += 4; memcpy(p, "ssh-rsa", 7); p += 7; PUT_32BIT(p, elen); p += 4; for (i = elen; i--;) *p++ = bignum_byte(rsa->exponent, i); PUT_32BIT(p, mlen); p += 4; for (i = mlen; i--;) *p++ = bignum_byte(rsa->modulus, i); assert(p == blob + bloblen); *len = bloblen; return blob;}static unsigned char *rsa2_private_blob(void *key, int *len){ struct RSAKey *rsa = (struct RSAKey *) key; int dlen, plen, qlen, ulen, bloblen; int i; unsigned char *blob, *p; dlen = (bignum_bitcount(rsa->private_exponent) + 8) / 8; plen = (bignum_bitcount(rsa->p) + 8) / 8; qlen = (bignum_bitcount(rsa->q) + 8) / 8; ulen = (bignum_bitcount(rsa->iqmp) + 8) / 8; /* * mpint private_exp, mpint p, mpint q, mpint iqmp. Total 16 + * sum of lengths. */ bloblen = 16 + dlen + plen + qlen + ulen; blob = snewn(bloblen, unsigned char); p = blob; PUT_32BIT(p, dlen); p += 4; for (i = dlen; i--;) *p++ = bignum_byte(rsa->private_exponent, i); PUT_32BIT(p, plen); p += 4; for (i = plen; i--;) *p++ = bignum_byte(rsa->p, i); PUT_32BIT(p, qlen); p += 4; for (i = qlen; i--;) *p++ = bignum_byte(rsa->q, i); PUT_32BIT(p, ulen); p += 4; for (i = ulen; i--;) *p++ = bignum_byte(rsa->iqmp, i); assert(p == blob + bloblen); *len = bloblen; return blob;}static void *rsa2_createkey(unsigned char *pub_blob, int pub_len, unsigned char *priv_blob, int priv_len){ struct RSAKey *rsa; char *pb = (char *) priv_blob; rsa = rsa2_newkey((char *) pub_blob, pub_len); rsa->private_exponent = getmp(&pb, &priv_len); rsa->p = getmp(&pb, &priv_len); rsa->q = getmp(&pb, &priv_len); rsa->iqmp = getmp(&pb, &priv_len); if (!rsa_verify(rsa)) { rsa2_freekey(rsa); return NULL; } return rsa;}static void *rsa2_openssh_createkey(unsigned char **blob, int *len){ char **b = (char **) blob; struct RSAKey *rsa; rsa = snew(struct RSAKey); if (!rsa) return NULL; rsa->comment = NULL; rsa->modulus = getmp(b, len); rsa->exponent = getmp(b, len); rsa->private_exponent = getmp(b, len); rsa->iqmp = getmp(b, len); rsa->p = getmp(b, len); rsa->q = getmp(b, len); if (!rsa->modulus || !rsa->exponent || !rsa->private_exponent || !rsa->iqmp || !rsa->p || !rsa->q) { sfree(rsa->modulus); sfree(rsa->exponent); sfree(rsa->private_exponent); sfree(rsa->iqmp); sfree(rsa->p); sfree(rsa->q); sfree(rsa); return NULL; } return rsa;}static int rsa2_openssh_fmtkey(void *key, unsigned char *blob, int len){ struct RSAKey *rsa = (struct RSAKey *) key; int bloblen, i; bloblen = ssh2_bignum_length(rsa->modulus) + ssh2_bignum_length(rsa->exponent) + ssh2_bignum_length(rsa->private_exponent) + ssh2_bignum_length(rsa->iqmp) + ssh2_bignum_length(rsa->p) + ssh2_bignum_length(rsa->q); if (bloblen > len) return bloblen; bloblen = 0;#define ENC(x) \ PUT_32BIT(blob+bloblen, ssh2_bignum_length((x))-4); bloblen += 4; \ for (i = ssh2_bignum_length((x))-4; i-- ;) blob[bloblen++]=bignum_byte((x),i); ENC(rsa->modulus); ENC(rsa->exponent); ENC(rsa->private_exponent); ENC(rsa->iqmp); ENC(rsa->p); ENC(rsa->q); return bloblen;}static int rsa2_pubkey_bits(void *blob, int len){ struct RSAKey *rsa; int ret; rsa = rsa2_newkey((char *) blob, len); ret = bignum_bitcount(rsa->modulus); rsa2_freekey(rsa); return ret;}static char *rsa2_fingerprint(void *key){ struct RSAKey *rsa = (struct RSAKey *) key; struct MD5Context md5c; unsigned char digest[16], lenbuf[4]; char buffer[16 * 3 + 40]; char *ret; int numlen, i; MD5Init(&md5c); MD5Update(&md5c, (unsigned char *)"\0\0\0\7ssh-rsa", 11);#define ADD_BIGNUM(bignum) \ numlen = (bignum_bitcount(bignum)+8)/8; \ PUT_32BIT(lenbuf, numlen); MD5Update(&md5c, lenbuf, 4); \ for (i = numlen; i-- ;) { \ unsigned char c = bignum_byte(bignum, i); \ MD5Update(&md5c, &c, 1); \ } ADD_BIGNUM(rsa->exponent); ADD_BIGNUM(rsa->modulus);#undef ADD_BIGNUM MD5Final(digest, &md5c); sprintf(buffer, "ssh-rsa %d ", bignum_bitcount(rsa->modulus)); for (i = 0; i < 16; i++) sprintf(buffer + strlen(buffer), "%s%02x", i ? ":" : "", digest[i]); ret = snewn(strlen(buffer) + 1, char); if (ret) strcpy(ret, buffer); return ret;}/* * This is the magic ASN.1/DER prefix that goes in the decoded * signature, between the string of FFs and the actual SHA hash * value. The meaning of it is: * * 00 -- this marks the end of the FFs; not part of the ASN.1 bit itself * * 30 21 -- a constructed SEQUENCE of length 0x21 * 30 09 -- a constructed sub-SEQUENCE of length 9 * 06 05 -- an object identifier, length 5 * 2B 0E 03 02 1A -- object id { 1 3 14 3 2 26 } * (the 1,3 comes from 0x2B = 43 = 40*1+3) * 05 00 -- NULL * 04 14 -- a primitive OCTET STRING of length 0x14 * [0x14 bytes of hash data follows] * * The object id in the middle there is listed as `id-sha1' in * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1d2.asn (the * ASN module for PKCS #1) and its expanded form is as follows: * * id-sha1 OBJECT IDENTIFIER ::= { * iso(1) identified-organization(3) oiw(14) secsig(3) * algorithms(2) 26 } */static const unsigned char asn1_weird_stuff[] = { 0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14,};#define ASN1_LEN ( (int) sizeof(asn1_weird_stuff) )static int rsa2_verifysig(void *key, char *sig, int siglen, char *data, int datalen){ struct RSAKey *rsa = (struct RSAKey *) key; Bignum in, out; char *p; int slen; int bytes, i, j, ret; unsigned char hash[20]; getstring(&sig, &siglen, &p, &slen); if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) { return 0; } in = getmp(&sig, &siglen); out = modpow(in, rsa->exponent, rsa->modulus); freebn(in); ret = 1; bytes = (bignum_bitcount(rsa->modulus)+7) / 8; /* Top (partial) byte should be zero. */ if (bignum_byte(out, bytes - 1) != 0) ret = 0; /* First whole byte should be 1. */ if (bignum_byte(out, bytes - 2) != 1) ret = 0; /* Most of the rest should be FF. */ for (i = bytes - 3; i >= 20 + ASN1_LEN; i--) { if (bignum_byte(out, i) != 0xFF) ret = 0; } /* Then we expect to see the asn1_weird_stuff. */ for (i = 20 + ASN1_LEN - 1, j = 0; i >= 20; i--, j++) { if (bignum_byte(out, i) != asn1_weird_stuff[j]) ret = 0; } /* Finally, we expect to see the SHA-1 hash of the signed data. */ SHA_Simple(data, datalen, hash); for (i = 19, j = 0; i >= 0; i--, j++) { if (bignum_byte(out, i) != hash[j]) ret = 0; } freebn(out); return ret;}static unsigned char *rsa2_sign(void *key, char *data, int datalen, int *siglen){ struct RSAKey *rsa = (struct RSAKey *) key; unsigned char *bytes; int nbytes; unsigned char hash[20]; Bignum in, out; int i, j; SHA_Simple(data, datalen, hash); nbytes = (bignum_bitcount(rsa->modulus) - 1) / 8; bytes = snewn(nbytes, unsigned char); bytes[0] = 1; for (i = 1; i < nbytes - 20 - ASN1_LEN; i++) bytes[i] = 0xFF; for (i = nbytes - 20 - ASN1_LEN, j = 0; i < nbytes - 20; i++, j++) bytes[i] = asn1_weird_stuff[j]; for (i = nbytes - 20, j = 0; i < nbytes; i++, j++) bytes[i] = hash[j]; in = bignum_from_bytes(bytes, nbytes); sfree(bytes); out = rsa_privkey_op(in, rsa); freebn(in); nbytes = (bignum_bitcount(out) + 7) / 8; bytes = snewn(4 + 7 + 4 + nbytes, unsigned char); PUT_32BIT(bytes, 7); memcpy(bytes + 4, "ssh-rsa", 7); PUT_32BIT(bytes + 4 + 7, nbytes); for (i = 0; i < nbytes; i++) bytes[4 + 7 + 4 + i] = bignum_byte(out, nbytes - 1 - i); freebn(out); *siglen = 4 + 7 + 4 + nbytes; return bytes;}const struct ssh_signkey ssh_rsa = { rsa2_newkey, rsa2_freekey, rsa2_fmtkey, rsa2_public_blob, rsa2_private_blob, rsa2_createkey, rsa2_openssh_createkey, rsa2_openssh_fmtkey, rsa2_pubkey_bits, rsa2_fingerprint, rsa2_verifysig, rsa2_sign, "ssh-rsa", "rsa2"};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -