int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv, const uint8_t *message, size_t message_len) { /* We use 512 bits of random data per iteration to * ensure that we have at least |range| bits of randomness. */ uint8_t random_bytes[64]; uint8_t digest[SHA512_DIGEST_LENGTH]; size_t done, todo, attempt; const unsigned num_k_bytes = BN_num_bytes(range); const unsigned bits_to_mask = (8 - (BN_num_bits(range) % 8)) % 8; uint8_t private_bytes[96]; uint8_t *k_bytes = NULL; int ret = 0; if (out == NULL) { return 0; } if (BN_is_zero(range)) { OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); goto err; } k_bytes = OPENSSL_malloc(num_k_bytes); if (!k_bytes) { OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); goto err; } /* We copy |priv| into a local buffer to avoid furthur 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. */ OPENSSL_PUT_ERROR(BN, BN_R_PRIVATE_KEY_TOO_LARGE); goto err; } memcpy(private_bytes, priv->d, todo); memset(private_bytes + todo, 0, sizeof(private_bytes) - todo); for (attempt = 0;; attempt++) { for (done = 0; done < num_k_bytes;) { if (!RAND_bytes(random_bytes, sizeof(random_bytes)) || !BN_generate_dsa_nonce_digest(digest, sizeof(digest), (const uint8_t *)attempt, sizeof(attempt), (const uint8_t *)done, sizeof(done), private_bytes, sizeof(private_bytes), message, message_len, random_bytes, sizeof(random_bytes))) { goto err; } todo = num_k_bytes - done; if (todo > sizeof(digest)) { todo = sizeof(digest); } memcpy(k_bytes + done, digest, todo); done += todo; } k_bytes[0] &= 0xff >> bits_to_mask; if (!BN_bin2bn(k_bytes, num_k_bytes, out)) { goto err; } if (BN_cmp(out, range) < 0) { break; } } ret = 1; err: OPENSSL_free(k_bytes); return ret; }
int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv, const uint8_t *message, size_t message_len) { /* We use 512 bits of random data per iteration to * ensure that we have at least |range| bits of randomness. */ uint8_t random_bytes[64]; uint8_t digest[SHA512_DIGEST_LENGTH]; const unsigned num_k_bytes = BN_num_bytes(range); const unsigned bits_to_mask = (8 - (BN_num_bits(range) % 8)) % 8; uint8_t private_bytes[SHA512_DIGEST_LENGTH]; uint8_t *k_bytes = NULL; int ret = 0; if (out == NULL) { return 0; } if (BN_is_zero(range)) { OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); goto err; } k_bytes = OPENSSL_malloc(num_k_bytes); if (!k_bytes) { OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); goto err; } /* We copy |priv| into a local buffer to avoid furthur exposing its * length. */ size_t todo = sizeof(priv->d[0]) * priv->top; if (todo > sizeof(private_bytes)) { /* No ECDSA key for a curve we support has a private key this large and we * don't handle this case in order to avoid leaking the length of the * private key and so we can generate the nonce with just one call to * |BN_generate_dsa_nonce_digest|. */ OPENSSL_PUT_ERROR(BN, BN_R_PRIVATE_KEY_TOO_LARGE); goto err; } memcpy(private_bytes, priv->d, todo); memset(private_bytes + todo, 0, sizeof(private_bytes) - todo); OPENSSL_COMPILE_ASSERT(sizeof(digest) == sizeof(private_bytes), BN_generate_dsa_nonce_digest_may_not_generate_enough); for (uint32_t attempt = 0;; attempt++) { uint8_t attempt_be[4]; to_be_u32_ptr(attempt_be, attempt); if (!RAND_bytes(random_bytes, sizeof(random_bytes)) || !BN_generate_dsa_nonce_digest(digest, sizeof(digest), attempt_be, sizeof(attempt_be), private_bytes, sizeof(private_bytes), message, message_len, random_bytes, sizeof(random_bytes))) { goto err; } memcpy(k_bytes, digest, num_k_bytes); k_bytes[0] &= 0xff >> bits_to_mask; if (!BN_bin2bn(k_bytes, num_k_bytes, out)) { goto err; } if (BN_cmp(out, range) < 0) { break; } if (attempt == 255) { /* This should never happen in practice. If it were to happen then it is * very likely that the something is very wrong. Note that 255 is * arbitrary; the limit should be |UINT32_MAX| or less in order for * |attempt| to avoid wrapping around; */ OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); goto err; } } ret = 1; err: OPENSSL_free(k_bytes); return ret; }