Split BN_prime_checks into two constants for generation and validation.
Although (somewhat) documented in prose, it is not obvious from the name that BN_prime_checks only works for randomly-selected candidate primes. Split into BN_prime_checks_for_generation and BN_prime_checks_for_validation. Fix internal call sites. Notably, DH_check now uses more iterations. Consistently call the parameter 'checks' rather than 'iterations', to match BN_prime_checks. This is in preparation for importing the Wycheproof primality testing vectors, some of which include Miller-Rabin worst case values. (Realistically the blinding mechanism meant, even for those inputs, our false positive rate was at most ~2^-64 anyway, but best to keep the use cases clear.) Update-Note: DH_check may be slower after this change. Change-Id: Ic13d03d8631e74bf2958979ee5ef45a69e603f46 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/39195 Commit-Queue: Adam Langley <agl@google.com> Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
parent
9511ca4c03
commit
0df6edff4f
@ -151,7 +151,7 @@ int DH_check(const DH *dh, int *out_flags) {
|
||||
*out_flags |= DH_CHECK_NOT_SUITABLE_GENERATOR;
|
||||
}
|
||||
}
|
||||
r = BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL);
|
||||
r = BN_is_prime_ex(dh->q, BN_prime_checks_for_validation, ctx, NULL);
|
||||
if (r < 0) {
|
||||
goto err;
|
||||
}
|
||||
@ -188,7 +188,7 @@ int DH_check(const DH *dh, int *out_flags) {
|
||||
*out_flags |= DH_CHECK_UNABLE_TO_CHECK_GENERATOR;
|
||||
}
|
||||
|
||||
r = BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL);
|
||||
r = BN_is_prime_ex(dh->p, BN_prime_checks_for_validation, ctx, NULL);
|
||||
if (r < 0) {
|
||||
goto err;
|
||||
}
|
||||
@ -198,7 +198,7 @@ int DH_check(const DH *dh, int *out_flags) {
|
||||
if (!BN_rshift1(t1, dh->p)) {
|
||||
goto err;
|
||||
}
|
||||
r = BN_is_prime_ex(t1, BN_prime_checks, ctx, NULL);
|
||||
r = BN_is_prime_ex(t1, BN_prime_checks_for_validation, ctx, NULL);
|
||||
if (r < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
@ -1986,16 +1986,17 @@ TEST_F(BNTest, PrimeChecking) {
|
||||
|
||||
ASSERT_TRUE(BN_set_word(p.get(), i));
|
||||
ASSERT_TRUE(BN_primality_test(
|
||||
&is_probably_prime_1, p.get(), BN_prime_checks, ctx(),
|
||||
&is_probably_prime_1, p.get(), BN_prime_checks_for_generation, ctx(),
|
||||
false /* do_trial_division */, nullptr /* callback */));
|
||||
EXPECT_EQ(is_prime ? 1 : 0, is_probably_prime_1);
|
||||
ASSERT_TRUE(BN_primality_test(
|
||||
&is_probably_prime_2, p.get(), BN_prime_checks, ctx(),
|
||||
&is_probably_prime_2, p.get(), BN_prime_checks_for_generation, ctx(),
|
||||
true /* do_trial_division */, nullptr /* callback */));
|
||||
EXPECT_EQ(is_prime ? 1 : 0, is_probably_prime_2);
|
||||
if (i > 3 && i % 2 == 1) {
|
||||
ASSERT_TRUE(BN_enhanced_miller_rabin_primality_test(
|
||||
&result_3, p.get(), BN_prime_checks, ctx(), nullptr /* callback */));
|
||||
&result_3, p.get(), BN_prime_checks_for_generation, ctx(),
|
||||
nullptr /* callback */));
|
||||
EXPECT_EQ(is_prime, result_3 == bn_probably_prime);
|
||||
}
|
||||
}
|
||||
@ -2003,13 +2004,13 @@ TEST_F(BNTest, PrimeChecking) {
|
||||
// Negative numbers are not prime.
|
||||
ASSERT_TRUE(BN_set_word(p.get(), 7));
|
||||
BN_set_negative(p.get(), 1);
|
||||
ASSERT_TRUE(BN_primality_test(&is_probably_prime_1, p.get(), BN_prime_checks,
|
||||
ctx(), false /* do_trial_division */,
|
||||
nullptr /* callback */));
|
||||
ASSERT_TRUE(BN_primality_test(
|
||||
&is_probably_prime_1, p.get(), BN_prime_checks_for_generation, ctx(),
|
||||
false /* do_trial_division */, nullptr /* callback */));
|
||||
EXPECT_EQ(0, is_probably_prime_1);
|
||||
ASSERT_TRUE(BN_primality_test(&is_probably_prime_2, p.get(), BN_prime_checks,
|
||||
ctx(), true /* do_trial_division */,
|
||||
nullptr /* callback */));
|
||||
ASSERT_TRUE(BN_primality_test(
|
||||
&is_probably_prime_2, p.get(), BN_prime_checks_for_generation, ctx(),
|
||||
true /* do_trial_division */, nullptr /* callback */));
|
||||
EXPECT_EQ(0, is_probably_prime_2);
|
||||
|
||||
static const char *kComposites[] = {
|
||||
@ -2068,17 +2069,18 @@ TEST_F(BNTest, PrimeChecking) {
|
||||
EXPECT_NE(0, DecimalToBIGNUM(&p, str));
|
||||
|
||||
ASSERT_TRUE(BN_primality_test(
|
||||
&is_probably_prime_1, p.get(), BN_prime_checks, ctx(),
|
||||
&is_probably_prime_1, p.get(), BN_prime_checks_for_generation, ctx(),
|
||||
false /* do_trial_division */, nullptr /* callback */));
|
||||
EXPECT_EQ(0, is_probably_prime_1);
|
||||
|
||||
ASSERT_TRUE(BN_primality_test(
|
||||
&is_probably_prime_2, p.get(), BN_prime_checks, ctx(),
|
||||
&is_probably_prime_2, p.get(), BN_prime_checks_for_generation, ctx(),
|
||||
true /* do_trial_division */, nullptr /* callback */));
|
||||
EXPECT_EQ(0, is_probably_prime_2);
|
||||
|
||||
ASSERT_TRUE(BN_enhanced_miller_rabin_primality_test(
|
||||
&result_3, p.get(), BN_prime_checks, ctx(), nullptr /* callback */));
|
||||
&result_3, p.get(), BN_prime_checks_for_generation, ctx(),
|
||||
nullptr /* callback */));
|
||||
EXPECT_EQ(bn_composite, result_3);
|
||||
}
|
||||
|
||||
@ -2257,25 +2259,27 @@ TEST_F(BNTest, PrimeChecking) {
|
||||
EXPECT_NE(0, HexToBIGNUM(&p, str));
|
||||
|
||||
ASSERT_TRUE(BN_primality_test(
|
||||
&is_probably_prime_1, p.get(), BN_prime_checks, ctx(),
|
||||
&is_probably_prime_1, p.get(), BN_prime_checks_for_generation, ctx(),
|
||||
false /* do_trial_division */, nullptr /* callback */));
|
||||
EXPECT_EQ(1, is_probably_prime_1);
|
||||
|
||||
ASSERT_TRUE(BN_primality_test(
|
||||
&is_probably_prime_2, p.get(), BN_prime_checks, ctx(),
|
||||
&is_probably_prime_2, p.get(), BN_prime_checks_for_generation, ctx(),
|
||||
true /* do_trial_division */, nullptr /* callback */));
|
||||
EXPECT_EQ(1, is_probably_prime_2);
|
||||
|
||||
ASSERT_TRUE(BN_enhanced_miller_rabin_primality_test(
|
||||
&result_3, p.get(), BN_prime_checks, ctx(), nullptr /* callback */));
|
||||
&result_3, p.get(), BN_prime_checks_for_generation, ctx(),
|
||||
nullptr /* callback */));
|
||||
EXPECT_EQ(bn_probably_prime, result_3);
|
||||
}
|
||||
|
||||
// BN_primality_test works with null |BN_CTX|.
|
||||
ASSERT_TRUE(BN_set_word(p.get(), 5));
|
||||
ASSERT_TRUE(BN_primality_test(
|
||||
&is_probably_prime_1, p.get(), BN_prime_checks, nullptr /* ctx */,
|
||||
false /* do_trial_division */, nullptr /* callback */));
|
||||
ASSERT_TRUE(
|
||||
BN_primality_test(&is_probably_prime_1, p.get(),
|
||||
BN_prime_checks_for_generation, nullptr /* ctx */,
|
||||
false /* do_trial_division */, nullptr /* callback */));
|
||||
EXPECT_EQ(1, is_probably_prime_1);
|
||||
}
|
||||
|
||||
|
@ -210,7 +210,7 @@ static const uint16_t kPrimes[] = {
|
||||
};
|
||||
|
||||
// BN_prime_checks_for_size returns the number of Miller-Rabin iterations
|
||||
// necessary for a 'bits'-bit prime.
|
||||
// necessary for generating a 'bits'-bit candidate prime.
|
||||
//
|
||||
//
|
||||
// This table is generated using the algorithm of FIPS PUB 186-4
|
||||
@ -604,9 +604,8 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BN_primality_test(int *out_is_probably_prime, const BIGNUM *w,
|
||||
int iterations, BN_CTX *ctx, int do_trial_division,
|
||||
BN_GENCB *cb) {
|
||||
int BN_primality_test(int *out_is_probably_prime, const BIGNUM *w, int checks,
|
||||
BN_CTX *ctx, int do_trial_division, BN_GENCB *cb) {
|
||||
// This function's secrecy and performance requirements come from RSA key
|
||||
// generation. We generate RSA keys by selecting two large, secret primes with
|
||||
// rejection sampling.
|
||||
@ -679,8 +678,8 @@ int BN_primality_test(int *out_is_probably_prime, const BIGNUM *w,
|
||||
}
|
||||
}
|
||||
|
||||
if (iterations == BN_prime_checks) {
|
||||
iterations = BN_prime_checks_for_size(BN_num_bits(w));
|
||||
if (checks == BN_prime_checks_for_generation) {
|
||||
checks = BN_prime_checks_for_size(BN_num_bits(w));
|
||||
}
|
||||
|
||||
BN_CTX *new_ctx = NULL;
|
||||
@ -736,7 +735,7 @@ int BN_primality_test(int *out_is_probably_prime, const BIGNUM *w,
|
||||
// Using |constant_time_lt_w| seems to prevent the compiler from optimizing
|
||||
// this into two jumps.
|
||||
for (int i = 1; (i <= BN_PRIME_CHECKS_BLINDED) |
|
||||
constant_time_lt_w(uniform_iterations, iterations);
|
||||
constant_time_lt_w(uniform_iterations, checks);
|
||||
i++) {
|
||||
// Step 4.1-4.2
|
||||
int is_uniform;
|
||||
@ -765,7 +764,7 @@ int BN_primality_test(int *out_is_probably_prime, const BIGNUM *w,
|
||||
}
|
||||
}
|
||||
|
||||
assert(uniform_iterations >= (crypto_word_t)iterations);
|
||||
assert(uniform_iterations >= (crypto_word_t)checks);
|
||||
*out_is_probably_prime = 1;
|
||||
ret = 1;
|
||||
|
||||
@ -792,7 +791,7 @@ int BN_is_prime_fasttest_ex(const BIGNUM *a, int checks, BN_CTX *ctx,
|
||||
}
|
||||
|
||||
int BN_enhanced_miller_rabin_primality_test(
|
||||
enum bn_primality_result_t *out_result, const BIGNUM *w, int iterations,
|
||||
enum bn_primality_result_t *out_result, const BIGNUM *w, int checks,
|
||||
BN_CTX *ctx, BN_GENCB *cb) {
|
||||
// Enhanced Miller-Rabin is only valid on odd integers greater than 3.
|
||||
if (!BN_is_odd(w) || BN_cmp_word(w, 3) <= 0) {
|
||||
@ -800,8 +799,8 @@ int BN_enhanced_miller_rabin_primality_test(
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (iterations == BN_prime_checks) {
|
||||
iterations = BN_prime_checks_for_size(BN_num_bits(w));
|
||||
if (checks == BN_prime_checks_for_generation) {
|
||||
checks = BN_prime_checks_for_size(BN_num_bits(w));
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
@ -848,7 +847,7 @@ int BN_enhanced_miller_rabin_primality_test(
|
||||
|
||||
// The following loop performs in inner iteration of the Enhanced Miller-Rabin
|
||||
// Primality test (Step 4).
|
||||
for (int i = 1; i <= iterations; i++) {
|
||||
for (int i = 1; i <= checks; i++) {
|
||||
// Step 4.1-4.2
|
||||
if (!BN_rand_range_ex(b, 2, w1)) {
|
||||
goto err;
|
||||
|
@ -809,6 +809,11 @@ int RSA_check_fips(RSA *key) {
|
||||
int ret = 1;
|
||||
|
||||
// Perform partial public key validation of RSA keys (SP 800-89 5.3.3).
|
||||
// Although this is not for primality testing, SP 800-89 cites an RSA
|
||||
// primality testing algorithm, so we use |BN_prime_checks_for_generation| to
|
||||
// match. This is only a plausibility test and we expect the value to be
|
||||
// composite, so too few iterations will cause us to reject the key, not use
|
||||
// an implausible one.
|
||||
enum bn_primality_result_t primality_result;
|
||||
if (BN_num_bits(key->e) <= 16 ||
|
||||
BN_num_bits(key->e) > 256 ||
|
||||
@ -817,7 +822,8 @@ int RSA_check_fips(RSA *key) {
|
||||
!BN_gcd(&small_gcd, key->n, g_small_factors(), ctx) ||
|
||||
!BN_is_one(&small_gcd) ||
|
||||
!BN_enhanced_miller_rabin_primality_test(&primality_result, key->n,
|
||||
BN_prime_checks, ctx, NULL) ||
|
||||
BN_prime_checks_for_generation,
|
||||
ctx, NULL) ||
|
||||
primality_result != bn_non_prime_power_composite) {
|
||||
OPENSSL_PUT_ERROR(RSA, RSA_R_PUBLIC_KEY_VALIDATION_FAILED);
|
||||
ret = 0;
|
||||
|
@ -1046,8 +1046,8 @@ static int generate_prime(BIGNUM *out, int bits, const BIGNUM *e,
|
||||
if (relatively_prime) {
|
||||
// Test |out| for primality (steps 4.5.1 and 5.6.1).
|
||||
int is_probable_prime;
|
||||
if (!BN_primality_test(&is_probable_prime, out, BN_prime_checks, ctx, 0,
|
||||
cb)) {
|
||||
if (!BN_primality_test(&is_probable_prime, out,
|
||||
BN_prime_checks_for_generation, ctx, 0, cb)) {
|
||||
goto err;
|
||||
}
|
||||
if (is_probable_prime) {
|
||||
|
@ -684,10 +684,22 @@ OPENSSL_EXPORT int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe,
|
||||
const BIGNUM *add, const BIGNUM *rem,
|
||||
BN_GENCB *cb);
|
||||
|
||||
// BN_prime_checks is magic value that can be used as the |checks| argument to
|
||||
// the primality testing functions in order to automatically select a number of
|
||||
// Miller-Rabin checks that gives a false positive rate of ~2^{-80}.
|
||||
#define BN_prime_checks 0
|
||||
// BN_prime_checks_for_validation can be used as the |checks| argument to the
|
||||
// primarily testing functions when validating an externally-supplied candidate
|
||||
// prime. It gives a false positive rate of at most 2^{-128}. (The worst case
|
||||
// false positive rate for a single iteration is 1/4, so we perform 32
|
||||
// iterations.)
|
||||
#define BN_prime_checks_for_validation 32
|
||||
|
||||
// BN_prime_checks_for_generation can be used as the |checks| argument to the
|
||||
// primality testing functions when generating random primes. It gives a false
|
||||
// positive rate at most the security level of the corresponding RSA key size.
|
||||
//
|
||||
// Note this value only performs enough checks if the candidate prime was
|
||||
// selected randomly. If validating an externally-supplied candidate, especially
|
||||
// one that may be selected adversarially, use |BN_prime_checks_for_validation|
|
||||
// instead.
|
||||
#define BN_prime_checks_for_generation 0
|
||||
|
||||
// bn_primality_result_t enumerates the outcomes of primality-testing.
|
||||
enum bn_primality_result_t {
|
||||
@ -698,7 +710,7 @@ enum bn_primality_result_t {
|
||||
|
||||
// BN_enhanced_miller_rabin_primality_test tests whether |w| is probably a prime
|
||||
// number using the Enhanced Miller-Rabin Test (FIPS 186-4 C.3.2) with
|
||||
// |iterations| iterations and returns the result in |out_result|. Enhanced
|
||||
// |checks| iterations and returns the result in |out_result|. Enhanced
|
||||
// Miller-Rabin tests primality for odd integers greater than 3, returning
|
||||
// |bn_probably_prime| if the number is probably prime,
|
||||
// |bn_non_prime_power_composite| if the number is a composite that is not the
|
||||
@ -706,12 +718,10 @@ enum bn_primality_result_t {
|
||||
// success and zero on failure. If |cb| is not NULL, then it is called during
|
||||
// each iteration of the primality test.
|
||||
//
|
||||
// If |iterations| is |BN_prime_checks|, then a value that results in a false
|
||||
// positive rate lower than the number-field sieve security level of |w| is
|
||||
// used, provided |w| was generated randomly. |BN_prime_checks| is not suitable
|
||||
// for inputs potentially crafted by an adversary.
|
||||
// See |BN_prime_checks_for_validation| and |BN_prime_checks_for_generation| for
|
||||
// recommended values of |checks|.
|
||||
OPENSSL_EXPORT int BN_enhanced_miller_rabin_primality_test(
|
||||
enum bn_primality_result_t *out_result, const BIGNUM *w, int iterations,
|
||||
enum bn_primality_result_t *out_result, const BIGNUM *w, int checks,
|
||||
BN_CTX *ctx, BN_GENCB *cb);
|
||||
|
||||
// BN_primality_test sets |*is_probably_prime| to one if |candidate| is
|
||||
@ -720,11 +730,9 @@ OPENSSL_EXPORT int BN_enhanced_miller_rabin_primality_test(
|
||||
//
|
||||
// If |do_trial_division| is non-zero then |candidate| will be tested against a
|
||||
// list of small primes before Miller-Rabin tests. The probability of this
|
||||
// function returning a false positive is 2^{2*checks}. If |checks| is
|
||||
// |BN_prime_checks| then a value that results in a false positive rate lower
|
||||
// than the number-field sieve security level of |candidate| is used, provided
|
||||
// |candidate| was generated randomly. |BN_prime_checks| is not suitable for
|
||||
// inputs potentially crafted by an adversary.
|
||||
// function returning a false positive is at most 2^{2*checks}. See
|
||||
// |BN_prime_checks_for_validation| and |BN_prime_checks_for_generation| for
|
||||
// recommended values of |checks|.
|
||||
//
|
||||
// If |cb| is not NULL then it is called during the checking process. See the
|
||||
// comment above |BN_GENCB|.
|
||||
@ -740,11 +748,9 @@ OPENSSL_EXPORT int BN_primality_test(int *is_probably_prime,
|
||||
//
|
||||
// If |do_trial_division| is non-zero then |candidate| will be tested against a
|
||||
// list of small primes before Miller-Rabin tests. The probability of this
|
||||
// function returning one when |candidate| is composite is 2^{2*checks}. If
|
||||
// |checks| is |BN_prime_checks| then a value that results in a false positive
|
||||
// rate lower than the number-field sieve security level of |candidate| is used,
|
||||
// provided |candidate| was generated randomly. |BN_prime_checks| is not
|
||||
// suitable for inputs potentially crafted by an adversary.
|
||||
// function returning one when |candidate| is composite is at most 2^{2*checks}.
|
||||
// See |BN_prime_checks_for_validation| and |BN_prime_checks_for_generation| for
|
||||
// recommended values of |checks|.
|
||||
//
|
||||
// If |cb| is not NULL then it is called during the checking process. See the
|
||||
// comment above |BN_GENCB|.
|
||||
@ -939,6 +945,12 @@ OPENSSL_EXPORT int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod,
|
||||
// Use |BN_bn2bin_padded| instead. It is |size_t|-clean.
|
||||
OPENSSL_EXPORT int BN_bn2binpad(const BIGNUM *in, uint8_t *out, int len);
|
||||
|
||||
// BN_prime_checks is a deprecated alias for |BN_prime_checks_for_validation|.
|
||||
// Use |BN_prime_checks_for_generation| or |BN_prime_checks_for_validation|
|
||||
// instead. (This defaults to the |_for_validation| value in order to be
|
||||
// conservative.)
|
||||
#define BN_prime_checks BN_prime_checks_for_validation
|
||||
|
||||
|
||||
// Private functions
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user