📄 sshrsa.c
字号:
/* * RSA implementation for PuTTY. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include "ssh.h"#include "misc.h"#define GET_32BIT(cp) \ (((unsigned long)(unsigned char)(cp)[0] << 24) | \ ((unsigned long)(unsigned char)(cp)[1] << 16) | \ ((unsigned long)(unsigned char)(cp)[2] << 8) | \ ((unsigned long)(unsigned char)(cp)[3]))#define PUT_32BIT(cp, value) { \ (cp)[0] = (unsigned char)((value) >> 24); \ (cp)[1] = (unsigned char)((value) >> 16); \ (cp)[2] = (unsigned char)((value) >> 8); \ (cp)[3] = (unsigned char)(value); }int makekey(unsigned char *data, int len, struct RSAKey *result, unsigned char **keystr, int order){ unsigned char *p = data; int i, n; if (len < 4) return -1; if (result) { result->bits = 0; for (i = 0; i < 4; i++) result->bits = (result->bits << 8) + *p++; } else p += 4; len -= 4; /* * order=0 means exponent then modulus (the keys sent by the * server). order=1 means modulus then exponent (the keys * stored in a keyfile). */ if (order == 0) { n = ssh1_read_bignum(p, len, result ? &result->exponent : NULL); if (n < 0) return -1; p += n; len -= n; } n = ssh1_read_bignum(p, len, result ? &result->modulus : NULL); if (n < 0 || (result && bignum_bitcount(result->modulus) == 0)) return -1; if (result) result->bytes = n - 2; if (keystr) *keystr = p + 2; p += n; len -= n; if (order == 1) { n = ssh1_read_bignum(p, len, result ? &result->exponent : NULL); if (n < 0) return -1; p += n; len -= n; } return p - data;}int makeprivate(unsigned char *data, int len, struct RSAKey *result){ return ssh1_read_bignum(data, len, &result->private_exponent);}int rsaencrypt(unsigned char *data, int length, struct RSAKey *key){ Bignum b1, b2; int i; unsigned char *p; if (key->bytes < length + 4) return 0; /* RSA key too short! */ memmove(data + key->bytes - length, data, length); data[0] = 0; data[1] = 2; for (i = 2; i < key->bytes - length - 1; i++) { do { data[i] = random_byte(); } while (data[i] == 0); } data[key->bytes - length - 1] = 0; b1 = bignum_from_bytes(data, key->bytes); b2 = modpow(b1, key->exponent, key->modulus); p = data; for (i = key->bytes; i--;) { *p++ = bignum_byte(b2, i); } freebn(b1); freebn(b2); return 1;}static void sha512_mpint(SHA512_State * s, Bignum b){ unsigned char lenbuf[4]; int len; len = (bignum_bitcount(b) + 8) / 8; PUT_32BIT(lenbuf, len); SHA512_Bytes(s, lenbuf, 4); while (len-- > 0) { lenbuf[0] = bignum_byte(b, len); SHA512_Bytes(s, lenbuf, 1); } memset(lenbuf, 0, sizeof(lenbuf));}/* * This function is a wrapper on modpow(). It has the same effect * as modpow(), but employs RSA blinding to protect against timing * attacks. */static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key){ Bignum random, random_encrypted, random_inverse; Bignum input_blinded, ret_blinded; Bignum ret; SHA512_State ss; unsigned char digest512[64]; int digestused = lenof(digest512); int hashseq = 0; /* * Start by inventing a random number chosen uniformly from the * range 2..modulus-1. (We do this by preparing a random number * of the right length and retrying if it's greater than the * modulus, to prevent any potential Bleichenbacher-like * attacks making use of the uneven distribution within the * range that would arise from just reducing our number mod n. * There are timing implications to the potential retries, of * course, but all they tell you is the modulus, which you * already knew.) * * To preserve determinism and avoid Pageant needing to share * the random number pool, we actually generate this `random' * number by hashing stuff with the private key. */ while (1) { int bits, byte, bitsleft, v; random = copybn(key->modulus); /* * Find the topmost set bit. (This function will return its * index plus one.) Then we'll set all bits from that one * downwards randomly. */ bits = bignum_bitcount(random); byte = 0; bitsleft = 0; while (bits--) { if (bitsleft <= 0) { bitsleft = 8; /* * Conceptually the following few lines are equivalent to * byte = random_byte(); */ if (digestused >= lenof(digest512)) { unsigned char seqbuf[4]; PUT_32BIT(seqbuf, hashseq); SHA512_Init(&ss); SHA512_Bytes(&ss, "RSA deterministic blinding", 26); SHA512_Bytes(&ss, seqbuf, sizeof(seqbuf)); sha512_mpint(&ss, key->private_exponent); SHA512_Final(&ss, digest512); hashseq++; /* * Now hash that digest plus the signature * input. */ SHA512_Init(&ss); SHA512_Bytes(&ss, digest512, sizeof(digest512)); sha512_mpint(&ss, input); SHA512_Final(&ss, digest512); digestused = 0; } byte = digest512[digestused++]; } v = byte & 1; byte >>= 1; bitsleft--; bignum_set_bit(random, bits, v); } /* * Now check that this number is strictly greater than * zero, and strictly less than modulus. */ if (bignum_cmp(random, Zero) <= 0 || bignum_cmp(random, key->modulus) >= 0) { freebn(random); continue; } else { break; } } /* * RSA blinding relies on the fact that (xy)^d mod n is equal * to (x^d mod n) * (y^d mod n) mod n. We invent a random pair * y and y^d; then we multiply x by y, raise to the power d mod * n as usual, and divide by y^d to recover x^d. Thus an * attacker can't correlate the timing of the modpow with the * input, because they don't know anything about the number * that was input to the actual modpow. * * The clever bit is that we don't have to do a huge modpow to * get y and y^d; we will use the number we just invented as * _y^d_, and use the _public_ exponent to compute (y^d)^e = y * from it, which is much faster to do. */ random_encrypted = modpow(random, key->exponent, key->modulus); random_inverse = modinv(random, key->modulus); input_blinded = modmul(input, random_encrypted, key->modulus); ret_blinded = modpow(input_blinded, key->private_exponent, key->modulus); ret = modmul(ret_blinded, random_inverse, key->modulus); freebn(ret_blinded); freebn(input_blinded); freebn(random_inverse); freebn(random_encrypted); freebn(random); return ret;}Bignum rsadecrypt(Bignum input, struct RSAKey *key){ return rsa_privkey_op(input, key);}int rsastr_len(struct RSAKey *key){ Bignum md, ex; int mdlen, exlen; md = key->modulus; ex = key->exponent; mdlen = (bignum_bitcount(md) + 15) / 16; exlen = (bignum_bitcount(ex) + 15) / 16; return 4 * (mdlen + exlen) + 20;}void rsastr_fmt(char *str, struct RSAKey *key){ Bignum md, ex; int len = 0, i, nibbles; static const char hex[] = "0123456789abcdef"; md = key->modulus; ex = key->exponent; len += sprintf(str + len, "0x"); nibbles = (3 + bignum_bitcount(ex)) / 4; if (nibbles < 1) nibbles = 1; for (i = nibbles; i--;) str[len++] = hex[(bignum_byte(ex, i / 2) >> (4 * (i % 2))) & 0xF]; len += sprintf(str + len, ",0x"); nibbles = (3 + bignum_bitcount(md)) / 4; if (nibbles < 1) nibbles = 1; for (i = nibbles; i--;) str[len++] = hex[(bignum_byte(md, i / 2) >> (4 * (i % 2))) & 0xF]; str[len] = '\0';}/* * Generate a fingerprint string for the key. Compatible with the * OpenSSH fingerprint code. */void rsa_fingerprint(char *str, int len, struct RSAKey *key){ struct MD5Context md5c; unsigned char digest[16]; char buffer[16 * 3 + 40]; int numlen, slen, i; MD5Init(&md5c); numlen = ssh1_bignum_length(key->modulus) - 2; for (i = numlen; i--;) { unsigned char c = bignum_byte(key->modulus, i); MD5Update(&md5c, &c, 1); } numlen = ssh1_bignum_length(key->exponent) - 2; for (i = numlen; i--;) { unsigned char c = bignum_byte(key->exponent, i); MD5Update(&md5c, &c, 1); } MD5Final(digest, &md5c); sprintf(buffer, "%d ", bignum_bitcount(key->modulus)); for (i = 0; i < 16; i++) sprintf(buffer + strlen(buffer), "%s%02x", i ? ":" : "", digest[i]); strncpy(str, buffer, len); str[len - 1] = '\0'; slen = strlen(str); if (key->comment && slen < len - 1) { str[slen] = ' '; strncpy(str + slen + 1, key->comment, len - slen - 1); str[len - 1] = '\0'; }}/* * Verify that the public data in an RSA key matches the private * data. We also check the private data itself: we ensure that p > * q and that iqmp really is the inverse of q mod p. */int rsa_verify(struct RSAKey *key){ Bignum n, ed, pm1, qm1; int cmp; /* n must equal pq. */ n = bigmul(key->p, key->q); cmp = bignum_cmp(n, key->modulus); freebn(n); if (cmp != 0) return 0; /* e * d must be congruent to 1, modulo (p-1) and modulo (q-1). */ pm1 = copybn(key->p); decbn(pm1); ed = modmul(key->exponent, key->private_exponent, pm1); cmp = bignum_cmp(ed, One); sfree(ed); if (cmp != 0) return 0; qm1 = copybn(key->q); decbn(qm1); ed = modmul(key->exponent, key->private_exponent, qm1); cmp = bignum_cmp(ed, One); sfree(ed); if (cmp != 0) return 0; /* * Ensure p > q. */ if (bignum_cmp(key->p, key->q) <= 0) return 0; /* * Ensure iqmp * q is congruent to 1, modulo p. */ n = modmul(key->iqmp, key->q, key->p); cmp = bignum_cmp(n, One); sfree(n); if (cmp != 0) return 0; return 1;}/* Public key blob as used by Pageant: exponent before modulus. */unsigned char *rsa_public_blob(struct RSAKey *key, int *len){ int length, pos; unsigned char *ret; length = (ssh1_bignum_length(key->modulus) + ssh1_bignum_length(key->exponent) + 4); ret = snewn(length, unsigned char); PUT_32BIT(ret, bignum_bitcount(key->modulus)); pos = 4; pos += ssh1_write_bignum(ret + pos, key->exponent); pos += ssh1_write_bignum(ret + pos, key->modulus); *len = length; return ret;}/* Given a public blob, determine its length. */int rsa_public_blob_len(void *data, int maxlen){ unsigned char *p = (unsigned char *)data; int n; if (maxlen < 4) return -1; p += 4; /* length word */ maxlen -= 4; n = ssh1_read_bignum(p, maxlen, NULL); /* exponent */ if (n < 0) return -1; p += n; n = ssh1_read_bignum(p, maxlen, NULL); /* modulus */ if (n < 0) return -1; p += n; return p - (unsigned char *)data;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -