diff options
Diffstat (limited to 'main/openssl/crypto/bn/bn_rand.c')
-rw-r--r-- | main/openssl/crypto/bn/bn_rand.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/main/openssl/crypto/bn/bn_rand.c b/main/openssl/crypto/bn/bn_rand.c index b376c28f..55676f07 100644 --- a/main/openssl/crypto/bn/bn_rand.c +++ b/main/openssl/crypto/bn/bn_rand.c @@ -114,6 +114,7 @@ #include "cryptlib.h" #include "bn_lcl.h" #include <openssl/rand.h> +#include <openssl/sha.h> static int bnrand(int pseudorand, BIGNUM *rnd, int bits, int top, int bottom) { @@ -303,3 +304,72 @@ int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) { return bn_rand_range(1, r, range); } + +#ifndef OPENSSL_NO_SHA512 +/* BN_generate_dsa_nonce generates a random number 0 <= out < range. Unlike + * BN_rand_range, it also includes the contents of |priv| and |message| in the + * generation so that an RNG failure isn't fatal as long as |priv| remains + * secret. This is intended for use in DSA and ECDSA where an RNG weakness + * leads directly to private key exposure unless this function is used. */ +int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM* priv, + const unsigned char *message, size_t message_len, + BN_CTX *ctx) + { + SHA512_CTX sha; + /* We use 512 bits of random data per iteration to + * ensure that we have at least |range| bits of randomness. */ + unsigned char random_bytes[64]; + unsigned char digest[SHA512_DIGEST_LENGTH]; + unsigned done, todo; + /* We generate |range|+8 bytes of random output. */ + const unsigned num_k_bytes = BN_num_bytes(range) + 8; + unsigned char private_bytes[96]; + unsigned char *k_bytes; + int ret = 0; + + k_bytes = OPENSSL_malloc(num_k_bytes); + if (!k_bytes) + goto err; + + /* We copy |priv| into a local buffer to avoid exposing its length. */ + todo = sizeof(priv->d[0])*priv->top; + if (todo > sizeof(private_bytes)) + { + /* No reasonable DSA or ECDSA key should have a private key + * this large and we don't handle this case in order to avoid + * leaking the length of the private key. */ + BNerr(BN_F_BN_GENERATE_DSA_NONCE, BN_R_PRIVATE_KEY_TOO_LARGE); + goto err; + } + memcpy(private_bytes, priv->d, todo); + memset(private_bytes + todo, 0, sizeof(private_bytes) - todo); + + for (done = 0; done < num_k_bytes;) { + if (RAND_bytes(random_bytes, sizeof(random_bytes)) != 1) + goto err; + SHA512_Init(&sha); + SHA512_Update(&sha, &done, sizeof(done)); + SHA512_Update(&sha, private_bytes, sizeof(private_bytes)); + SHA512_Update(&sha, message, message_len); + SHA512_Update(&sha, random_bytes, sizeof(random_bytes)); + SHA512_Final(digest, &sha); + + todo = num_k_bytes - done; + if (todo > SHA512_DIGEST_LENGTH) + todo = SHA512_DIGEST_LENGTH; + memcpy(k_bytes + done, digest, todo); + done += todo; + } + + if (!BN_bin2bn(k_bytes, num_k_bytes, out)) + goto err; + if (BN_mod(out, out, range, ctx) != 1) + goto err; + ret = 1; + +err: + if (k_bytes) + OPENSSL_free(k_bytes); + return ret; + } +#endif /* OPENSSL_NO_SHA512 */ |