summaryrefslogtreecommitdiffstats
path: root/crypto/bn/bn_rand.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/bn/bn_rand.c')
-rw-r--r--crypto/bn/bn_rand.c164
1 files changed, 125 insertions, 39 deletions
diff --git a/crypto/bn/bn_rand.c b/crypto/bn/bn_rand.c
index a94dfcecdf..650d057470 100644
--- a/crypto/bn/bn_rand.c
+++ b/crypto/bn/bn_rand.c
@@ -184,8 +184,8 @@ static int bnrand_range(BNRAND_FLAG flag, BIGNUM *r, const BIGNUM *range,
} else {
do {
/* range = 11..._2 or range = 101..._2 */
- if (!bnrand(flag, r, n, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY, 0,
- ctx))
+ if (!bnrand(flag, r, n, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY,
+ strength, ctx))
return 0;
if (!--count) {
@@ -238,17 +238,63 @@ int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range)
# endif
#endif
+int ossl_bn_priv_rand_range_fixed_top(BIGNUM *r, const BIGNUM *range,
+ unsigned int strength, BN_CTX *ctx)
+{
+ int n;
+ int count = 100;
+
+ if (r == NULL) {
+ ERR_raise(ERR_LIB_BN, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ if (range->neg || BN_is_zero(range)) {
+ ERR_raise(ERR_LIB_BN, BN_R_INVALID_RANGE);
+ return 0;
+ }
+
+ n = BN_num_bits(range); /* n > 0 */
+
+ /* BN_is_bit_set(range, n - 1) always holds */
+
+ if (n == 1) {
+ BN_zero(r);
+ } else {
+ BN_set_flags(r, BN_FLG_CONSTTIME);
+ do {
+ if (!bnrand(PRIVATE, r, n + 1, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY,
+ strength, ctx))
+ return 0;
+
+ if (!--count) {
+ ERR_raise(ERR_LIB_BN, BN_R_TOO_MANY_ITERATIONS);
+ return 0;
+ }
+ ossl_bn_mask_bits_fixed_top(r, n);
+ }
+ while (BN_ucmp(r, range) >= 0);
+#ifdef BN_DEBUG
+ /* With BN_DEBUG on a fixed top number cannot be returned */
+ bn_correct_top(r);
+#endif
+ }
+
+ return 1;
+}
+
/*
- * 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|
+ * ossl_bn_gen_dsa_nonce_fixed_top 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)
+int ossl_bn_gen_dsa_nonce_fixed_top(BIGNUM *out, const BIGNUM *range,
+ const BIGNUM *priv,
+ const unsigned char *message,
+ size_t message_len, BN_CTX *ctx)
{
EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
/*
@@ -258,20 +304,24 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
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;
+ /* We generate |range|+1 bytes of random output. */
+ const unsigned num_k_bytes = BN_num_bytes(range) + 1;
unsigned char private_bytes[96];
unsigned char *k_bytes = NULL;
+ const int max_n = 64; /* Pr(failure to generate) < 2^max_n */
+ int n;
int ret = 0;
EVP_MD *md = NULL;
OSSL_LIB_CTX *libctx = ossl_bn_get_libctx(ctx);
if (mdctx == NULL)
- goto err;
+ goto end;
k_bytes = OPENSSL_malloc(num_k_bytes);
if (k_bytes == NULL)
- goto err;
+ goto end;
+ /* Ensure top byte is set to avoid non-constant time in bin2bn */
+ k_bytes[0] = 0xff;
/* We copy |priv| into a local buffer to avoid exposing its length. */
if (BN_bn2binpad(priv, private_bytes, sizeof(private_bytes)) < 0) {
@@ -281,41 +331,60 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
* length of the private key.
*/
ERR_raise(ERR_LIB_BN, BN_R_PRIVATE_KEY_TOO_LARGE);
- goto err;
+ goto end;
}
md = EVP_MD_fetch(libctx, "SHA512", NULL);
if (md == NULL) {
ERR_raise(ERR_LIB_BN, BN_R_NO_SUITABLE_DIGEST);
- goto err;
- }
- for (done = 0; done < num_k_bytes;) {
- if (RAND_priv_bytes_ex(libctx, random_bytes, sizeof(random_bytes), 0) <= 0)
- goto err;
-
- if (!EVP_DigestInit_ex(mdctx, md, NULL)
- || !EVP_DigestUpdate(mdctx, &done, sizeof(done))
- || !EVP_DigestUpdate(mdctx, private_bytes,
- sizeof(private_bytes))
- || !EVP_DigestUpdate(mdctx, message, message_len)
- || !EVP_DigestUpdate(mdctx, random_bytes, sizeof(random_bytes))
- || !EVP_DigestFinal_ex(mdctx, digest, NULL))
- goto err;
-
- todo = num_k_bytes - done;
- if (todo > SHA512_DIGEST_LENGTH)
- todo = SHA512_DIGEST_LENGTH;
- memcpy(k_bytes + done, digest, todo);
- done += todo;
+ goto end;
}
+ for (n = 0; n < max_n; n++) {
+ unsigned char i = 0;
+
+ for (done = 1; done < num_k_bytes;) {
+ if (RAND_priv_bytes_ex(libctx, random_bytes, sizeof(random_bytes),
+ 0) <= 0)
+ goto end;
+
+ if (!EVP_DigestInit_ex(mdctx, md, NULL)
+ || !EVP_DigestUpdate(mdctx, &i, sizeof(i))
+ || !EVP_DigestUpdate(mdctx, private_bytes,
+ sizeof(private_bytes))
+ || !EVP_DigestUpdate(mdctx, message, message_len)
+ || !EVP_DigestUpdate(mdctx, random_bytes,
+ sizeof(random_bytes))
+ || !EVP_DigestFinal_ex(mdctx, digest, NULL))
+ goto end;
+
+ todo = num_k_bytes - done;
+ if (todo > SHA512_DIGEST_LENGTH)
+ todo = SHA512_DIGEST_LENGTH;
+ memcpy(k_bytes + done, digest, todo);
+ done += todo;
+ ++i;
+ }
- if (!BN_bin2bn(k_bytes, num_k_bytes, out))
- goto err;
- if (BN_mod(out, out, range, ctx) != 1)
- goto err;
- ret = 1;
+ if (!BN_bin2bn(k_bytes, num_k_bytes, out))
+ goto end;
- err:
+ /* Clear out the top bits and rejection filter into range */
+ BN_set_flags(out, BN_FLG_CONSTTIME);
+ ossl_bn_mask_bits_fixed_top(out, BN_num_bits(range));
+
+ if (BN_ucmp(out, range) < 0) {
+ ret = 1;
+#ifdef BN_DEBUG
+ /* With BN_DEBUG on a fixed top number cannot be returned */
+ bn_correct_top(out);
+#endif
+ goto end;
+ }
+ }
+ /* Failed to generate anything */
+ ERR_raise(ERR_LIB_BN, ERR_R_INTERNAL_ERROR);
+
+ end:
EVP_MD_CTX_free(mdctx);
EVP_MD_free(md);
OPENSSL_clear_free(k_bytes, num_k_bytes);
@@ -324,3 +393,20 @@ int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
OPENSSL_cleanse(private_bytes, sizeof(private_bytes));
return ret;
}
+
+int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range,
+ const BIGNUM *priv, const unsigned char *message,
+ size_t message_len, BN_CTX *ctx)
+{
+ int ret;
+
+ ret = ossl_bn_gen_dsa_nonce_fixed_top(out, range, priv, message,
+ message_len, ctx);
+ /*
+ * This call makes the BN_generate_dsa_nonce non-const-time, thus we
+ * do not use it internally. But fixed_top BNs currently cannot be returned
+ * from public API calls.
+ */
+ bn_correct_top(out);
+ return ret;
+}