Packages
hackney
3.0.3
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/boringssl/crypto/fipsmodule/rand/ctrdrbg.cc.inc
// Copyright 2017 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <openssl/ctrdrbg.h>
#include <assert.h>
#include <openssl/mem.h>
#include <algorithm>
#include "../aes/internal.h"
#include "../service_indicator/internal.h"
#include "internal.h"
// Section references in this file refer to SP 800-90Ar1:
// http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf
// Also see table 3.
constexpr uint64_t kMaxReseedCount = UINT64_C(1) << 48;
// Implements the BCC function as described in Section 10.3.3.
static void bcc(uint8_t out[AES_BLOCK_SIZE], const AES_KEY *aes_key,
const uint8_t *data, size_t data_len) {
// 1. chaining_value = 0^outlen.
uint8_t *chaining_value = out;
OPENSSL_memset(chaining_value, 0, AES_BLOCK_SIZE);
// 2. n = len (data)/outlen.
BSSL_CHECK(data_len % AES_BLOCK_SIZE == 0);
const size_t n = data_len / AES_BLOCK_SIZE;
for (size_t i = 0; i < n; i++) {
const uint8_t *block = data + (i * AES_BLOCK_SIZE);
uint8_t input_block[AES_BLOCK_SIZE];
// 4.1: input_block = chaining_value ⊕ block_i.
CRYPTO_xor16(input_block, chaining_value, block);
// 4.2: chaining_value = Block_Encrypt (Key, input_block).
BCM_aes_encrypt(input_block, chaining_value, aes_key);
}
// 5. output_block = chaining_value.
}
// Implements the derivation function as described in Section 10.3.2.
static int block_cipher_df(uint8_t *out, size_t out_len, const uint8_t *input,
size_t input_len) {
// Constants for AES-256
constexpr size_t kAESKeyLen = 32;
constexpr size_t kAESOutLen = AES_BLOCK_SIZE;
constexpr size_t kMaxNumBits = 512;
if (out_len > kMaxNumBits / 8 || input_len > (1u << 30)) {
return 0;
}
// 4. S = L || N || input_string || 0x80.
const size_t s_rawlen = sizeof(uint32_t) + sizeof(uint32_t) + input_len + 1;
// S is padded up to a block size.
const size_t s_len = (s_rawlen + kAESOutLen - 1) & ~(kAESOutLen - 1);
uint8_t iv_plus_s[/* space used below */ kAESOutLen + 4 + 4 +
CTR_DRBG_MAX_ENTROPY_LEN + CTR_DRBG_NONCE_LEN +
CTR_DRBG_SEED_LEN + 1 +
/* padding */ 7];
if (kAESOutLen + s_len > sizeof(iv_plus_s)) {
return 0;
}
OPENSSL_memset(iv_plus_s, 0, sizeof(iv_plus_s));
uint8_t *s_ptr = iv_plus_s + kAESOutLen;
// 2. L = len (input_string)/8.
CRYPTO_store_u32_be(s_ptr, (uint32_t)input_len);
s_ptr += sizeof(uint32_t);
// 3. N = number_of_bits_to_return/8.
CRYPTO_store_u32_be(s_ptr, (uint32_t)out_len);
s_ptr += sizeof(uint32_t);
OPENSSL_memcpy(s_ptr, input, input_len);
s_ptr += input_len;
*s_ptr = 0x80;
uint8_t temp[kAESKeyLen + kAESOutLen];
size_t temp_len = 0;
// 8. K = leftmost (0x00010203...1D1E1F, keylen).
static const uint8_t kInitialKey[kAESKeyLen] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
AES_KEY aes_key;
bcm_status status =
BCM_aes_set_encrypt_key(kInitialKey, 8 * sizeof(kInitialKey), &aes_key);
BSSL_CHECK(status != bcm_status::failure);
// 7. i = 0.
uint32_t i = 0;
while (temp_len < sizeof(temp)) {
// 9.1 IV = i || 0^(outlen - len(i)).
CRYPTO_store_u32_be(iv_plus_s, i);
// 9.2 temp = temp || BCC (K, (IV || S)).
bcc(temp + temp_len, &aes_key, iv_plus_s, kAESOutLen + s_len);
temp_len += kAESOutLen;
// 9.3 i = i + 1.
i++;
}
// 10. K = leftmost (temp, keylen).
uint8_t *const k = temp;
// 11. X = select (temp, keylen+1, keylen+outlen).
uint8_t *const x = temp + kAESKeyLen;
// 12. temp = the Null string.
temp_len = 0;
// Create an AES key schedule for the final encryption steps.
status = BCM_aes_set_encrypt_key(k, kAESKeyLen * 8, &aes_key);
BSSL_CHECK(status != bcm_status::failure);
// 13. While len (temp) < number_of_bits_to_return, do:
while (temp_len < out_len) {
// 13.1 X = Block_Encrypt (K, X).
BCM_aes_encrypt(x, x, &aes_key);
// 13.2 temp = temp || X.
size_t to_copy = std::min(kAESOutLen, out_len - temp_len);
OPENSSL_memcpy(out + temp_len, x, to_copy);
temp_len += to_copy;
}
return 1;
}
CTR_DRBG_STATE *CTR_DRBG_new(const uint8_t entropy[CTR_DRBG_ENTROPY_LEN],
const uint8_t *personalization,
size_t personalization_len) {
CTR_DRBG_STATE *drbg = reinterpret_cast<CTR_DRBG_STATE *>(
OPENSSL_malloc(sizeof(CTR_DRBG_STATE)));
if (drbg == nullptr ||
!CTR_DRBG_init(drbg, /*df=*/false, entropy, CTR_DRBG_ENTROPY_LEN,
/*nonce=*/nullptr, personalization, personalization_len)) {
CTR_DRBG_free(drbg);
return nullptr;
}
return drbg;
}
CTR_DRBG_STATE *CTR_DRBG_new_df(const uint8_t *entropy, size_t entropy_len,
const uint8_t nonce[CTR_DRBG_NONCE_LEN],
const uint8_t *personalization,
size_t personalization_len) {
CTR_DRBG_STATE *drbg = reinterpret_cast<CTR_DRBG_STATE *>(
OPENSSL_malloc(sizeof(CTR_DRBG_STATE)));
if (drbg == nullptr ||
!CTR_DRBG_init(drbg, /*df=*/true, entropy, entropy_len, nonce,
personalization, personalization_len)) {
CTR_DRBG_free(drbg);
return nullptr;
}
return drbg;
}
void CTR_DRBG_free(CTR_DRBG_STATE *state) { OPENSSL_free(state); }
int CTR_DRBG_init(CTR_DRBG_STATE *drbg, int df, const uint8_t *entropy,
size_t entropy_len, const uint8_t nonce[CTR_DRBG_NONCE_LEN],
const uint8_t *personalization, size_t personalization_len) {
// Section 10.2.1.3.1 and 10.2.1.3.2
if (personalization_len > CTR_DRBG_SEED_LEN ||
(!df && entropy_len != CTR_DRBG_ENTROPY_LEN) ||
(df && (entropy_len < CTR_DRBG_MIN_ENTROPY_LEN ||
entropy_len > CTR_DRBG_MAX_ENTROPY_LEN)) || //
(df != (nonce != nullptr))) {
return 0;
}
uint8_t seed_material[CTR_DRBG_SEED_LEN];
if (df) {
uint8_t pre_seed_material[CTR_DRBG_MAX_ENTROPY_LEN + CTR_DRBG_NONCE_LEN +
CTR_DRBG_SEED_LEN];
OPENSSL_memcpy(pre_seed_material, entropy, entropy_len);
OPENSSL_memcpy(pre_seed_material + entropy_len, nonce, CTR_DRBG_NONCE_LEN);
OPENSSL_memcpy(pre_seed_material + entropy_len + CTR_DRBG_NONCE_LEN,
personalization, personalization_len);
const size_t pre_seed_material_length =
entropy_len + CTR_DRBG_NONCE_LEN + personalization_len;
if (!block_cipher_df(seed_material, sizeof(seed_material),
pre_seed_material, pre_seed_material_length)) {
return 0;
}
} else {
OPENSSL_memcpy(seed_material, entropy, CTR_DRBG_ENTROPY_LEN);
for (size_t i = 0; i < personalization_len; i++) {
seed_material[i] ^= personalization[i];
}
}
// Section 10.2.1.2
// kInitMask is the result of encrypting blocks with big-endian value 1, 2
// and 3 with the all-zero AES-256 key.
static const uint8_t kInitMask[CTR_DRBG_SEED_LEN] = {
0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, 0xa9, 0x63, 0xb4, 0xf1,
0xc4, 0xcb, 0x73, 0x8b, 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e,
0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18, 0x72, 0x60, 0x03, 0xca,
0x37, 0xa6, 0x2a, 0x74, 0xd1, 0xa2, 0xf5, 0x8e, 0x75, 0x06, 0x35, 0x8e,
};
for (size_t i = 0; i < sizeof(kInitMask); i++) {
seed_material[i] ^= kInitMask[i];
}
drbg->df = df;
drbg->ctr =
aes_ctr_set_key(&drbg->ks, nullptr, &drbg->block, seed_material, 32);
OPENSSL_memcpy(drbg->counter, seed_material + 32, 16);
drbg->reseed_counter = 1;
return 1;
}
static_assert(CTR_DRBG_SEED_LEN % AES_BLOCK_SIZE == 0,
"not a multiple of AES block size");
// ctr_inc adds |n| to the last four bytes of |drbg->counter|, treated as a
// big-endian number.
static void ctr32_add(CTR_DRBG_STATE *drbg, uint32_t n) {
uint32_t ctr = CRYPTO_load_u32_be(drbg->counter + 12);
CRYPTO_store_u32_be(drbg->counter + 12, ctr + n);
}
static int ctr_drbg_update(CTR_DRBG_STATE *drbg,
const uint8_t data[CTR_DRBG_SEED_LEN]) {
uint8_t temp[CTR_DRBG_SEED_LEN];
for (size_t i = 0; i < CTR_DRBG_SEED_LEN; i += AES_BLOCK_SIZE) {
ctr32_add(drbg, 1);
drbg->block(drbg->counter, temp + i, &drbg->ks);
}
for (size_t i = 0; i < CTR_DRBG_SEED_LEN; i++) {
temp[i] ^= data[i];
}
drbg->ctr = aes_ctr_set_key(&drbg->ks, nullptr, &drbg->block, temp, 32);
OPENSSL_memcpy(drbg->counter, temp + 32, 16);
return 1;
}
int CTR_DRBG_reseed(CTR_DRBG_STATE *drbg,
const uint8_t entropy[CTR_DRBG_ENTROPY_LEN],
const uint8_t *additional_data,
size_t additional_data_len) {
return CTR_DRBG_reseed_ex(drbg, entropy, CTR_DRBG_ENTROPY_LEN,
additional_data, additional_data_len);
}
int CTR_DRBG_reseed_ex(CTR_DRBG_STATE *drbg, const uint8_t *entropy,
size_t entropy_len, const uint8_t *additional_data,
size_t additional_data_len) {
if (additional_data_len > CTR_DRBG_SEED_LEN ||
(drbg->df && (entropy_len > CTR_DRBG_MAX_ENTROPY_LEN ||
entropy_len < CTR_DRBG_MIN_ENTROPY_LEN)) ||
(!drbg->df && entropy_len != CTR_DRBG_ENTROPY_LEN)) {
return 0;
}
uint8_t seed_material[CTR_DRBG_SEED_LEN];
if (drbg->df) {
// Section 10.2.1.4.2
uint8_t pre_seed_material[CTR_DRBG_MAX_ENTROPY_LEN + CTR_DRBG_SEED_LEN];
static_assert(CTR_DRBG_MAX_ENTROPY_LEN <= sizeof(pre_seed_material));
OPENSSL_memcpy(pre_seed_material, entropy, entropy_len);
OPENSSL_memcpy(pre_seed_material + entropy_len, additional_data,
additional_data_len);
const size_t pre_seed_material_len = entropy_len + additional_data_len;
if (!block_cipher_df(seed_material, sizeof(seed_material),
pre_seed_material, pre_seed_material_len)) {
return 0;
}
} else {
// Section 10.2.1.4
static_assert(CTR_DRBG_ENTROPY_LEN == sizeof(seed_material));
OPENSSL_memcpy(seed_material, entropy, CTR_DRBG_ENTROPY_LEN);
if (additional_data_len > 0) {
for (size_t i = 0; i < additional_data_len; i++) {
seed_material[i] ^= additional_data[i];
}
}
}
if (!ctr_drbg_update(drbg, seed_material)) {
return 0;
}
drbg->reseed_counter = 1;
return 1;
}
int CTR_DRBG_generate(CTR_DRBG_STATE *drbg, uint8_t *out, size_t out_len,
const uint8_t *additional_data,
size_t additional_data_len) {
// See 9.3.1
if (out_len > CTR_DRBG_MAX_GENERATE_LENGTH) {
return 0;
}
// See 10.2.1.5.1
if (drbg->reseed_counter > kMaxReseedCount) {
return 0;
}
uint8_t processed_additional_data[CTR_DRBG_SEED_LEN];
OPENSSL_memset(processed_additional_data, 0,
sizeof(processed_additional_data));
if (additional_data_len != 0) {
if (drbg->df) {
if (!block_cipher_df(processed_additional_data,
sizeof(processed_additional_data), additional_data,
additional_data_len)) {
return 0;
}
} else {
if (additional_data_len > sizeof(processed_additional_data)) {
return 0;
}
OPENSSL_memcpy(processed_additional_data, additional_data,
additional_data_len);
}
if (!ctr_drbg_update(drbg, processed_additional_data)) {
return 0;
}
}
// kChunkSize is used to interact better with the cache. Since the AES-CTR
// code assumes that it's encrypting rather than just writing keystream, the
// buffer has to be zeroed first. Without chunking, large reads would zero
// the whole buffer, flushing the L1 cache, and then do another pass (missing
// the cache every time) to “encrypt” it. The code can avoid this by
// chunking.
constexpr size_t kChunkSize = 8 * 1024;
while (out_len >= AES_BLOCK_SIZE) {
size_t todo = kChunkSize;
if (todo > out_len) {
todo = out_len;
}
todo &= ~(AES_BLOCK_SIZE - 1);
const size_t num_blocks = todo / AES_BLOCK_SIZE;
OPENSSL_memset(out, 0, todo);
ctr32_add(drbg, 1);
drbg->ctr(out, out, num_blocks, &drbg->ks, drbg->counter);
ctr32_add(drbg, (uint32_t)(num_blocks - 1));
out += todo;
out_len -= todo;
}
if (out_len > 0) {
uint8_t block[AES_BLOCK_SIZE];
ctr32_add(drbg, 1);
drbg->block(drbg->counter, block, &drbg->ks);
OPENSSL_memcpy(out, block, out_len);
}
if (!ctr_drbg_update(drbg, processed_additional_data)) {
return 0;
}
drbg->reseed_counter++;
FIPS_service_indicator_update_state();
return 1;
}
void CTR_DRBG_clear(CTR_DRBG_STATE *drbg) {
OPENSSL_cleanse(drbg, sizeof(CTR_DRBG_STATE));
}