(cp)[2] = (unsigned char)((value) >> 8); \
(cp)[3] = (unsigned char)(value); }
-int makekey(unsigned char *data, struct RSAKey *result,
+int makekey(unsigned char *data, int len, struct RSAKey *result,
unsigned char **keystr, int order)
{
unsigned char *p = data;
- int i;
+ int i, n;
+
+ if (len < 4)
+ return -1;
if (result) {
result->bits = 0;
} 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)
- p += ssh1_read_bignum(p, result ? &result->exponent : NULL);
+ 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 = (((p[0] << 8) + p[1]) + 7) / 8;
+ result->bytes = n - 2;
if (keystr)
*keystr = p + 2;
- p += ssh1_read_bignum(p, result ? &result->modulus : NULL);
- if (order == 1)
- p += ssh1_read_bignum(p, result ? &result->exponent : NULL);
-
+ 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, struct RSAKey *result)
+int makeprivate(unsigned char *data, int len, struct RSAKey *result)
{
- return ssh1_read_bignum(data, &result->private_exponent);
+ return ssh1_read_bignum(data, len, &result->private_exponent);
}
-void rsaencrypt(unsigned char *data, int length, struct RSAKey *key)
+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;
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));
}
/*
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
* 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;
byte = 0;
bitsleft = 0;
while (bits--) {
- if (bitsleft <= 0)
- bitsleft = 8, byte = random_byte();
+ 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--;
}
/* Given a public blob, determine its length. */
-int rsa_public_blob_len(void *data)
+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 */
- p += ssh1_read_bignum(p, NULL); /* exponent */
- p += ssh1_read_bignum(p, NULL); /* modulus */
+ 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;
}
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;
ret = 1;
- bytes = bignum_bitcount(rsa->modulus) / 8;
+ bytes = (bignum_bitcount(rsa->modulus)+7) / 8;
/* Top (partial) byte should be zero. */
if (bignum_byte(out, bytes - 1) != 0)
ret = 0;
if (bignum_byte(out, i) != hash[j])
ret = 0;
}
+ freebn(out);
return ret;
}
rsa2_createkey,
rsa2_openssh_createkey,
rsa2_openssh_fmtkey,
+ rsa2_pubkey_bits,
rsa2_fingerprint,
rsa2_verifysig,
rsa2_sign,