articles
articles copied to clipboard
003-chromium boringssl随机数生成分析
boringssl随机数生成分析
所有代码均来源于特定boringssl开源版本,无任何定制
-
boringssl随机数生成分析
- 调用流程
-
具体流程分析
- 生成additional_data
- 生成seed
- 生成熵值
- 生成随机数
- 参考
boringssl
随机数据生成分析
调用流程
boringssl
的随机数据生成算法的整个流程
RAND_bytes
|-> RAND_bytes_with_additional_data
|
| # 1. 生成additional_data数据
| // 硬件指令/compiler相关
|-> rdrand(additional_data, sizeof(additional_data))
| -> OPENSSL_memset(additional_data, 0, sizeof(additional_data))
| -> memset
| // 平台相关
|-> CRYPTO_sysrand(additional_data, sizeof(additional_data))
| -> linux实现
| -> windows实现
|
| # 2. 生成seed和entropy
|-> rand_get_seed
| -> get_seed_entropy // 熵值
| -> CRYPTO_get_seed_entropy
| -> rdrand|CRYPTO_sysrand_for_seed 生成熵值
| -> RAND_load_entropy // 熵值传入entropy_buffer
|
| # 3. 利用seed和entropy生成随机数
|-> CTR_DRBG_init // 初始化
|
|-> CTR_DRBG_generate // 结合seed,生成随机数
| -> ctr_drbg_update // 更新init初始化后的数据
|
|-> CTR_DRBG_clear
整个流程大概分为三步
- 利用
rdrand/CRYPTO_sysrand
生成additional_data
数据 - 利用
rdrand/CRYPTO_sysrand
生成seed
和entropy
- 结合生成的
seed/entropy/additional_data
,利用AES256-CTR-DRBG
算法最终生成随机数据
具体流程分析
总入口RAND_bytes
int RAND_bytes(uint8_t *out, size_t out_len) {
static const uint8_t kZeroAdditionalData[32] = {0};
// 调用真正的实现函数
RAND_bytes_with_additional_data(out, out_len, kZeroAdditionalData);
return 1;
}
将全为0的数组kZeroAdditionalData
带入RAND_bytes_with_additional_data
boringssl
的随机数真正实现在RAND_bytes_with_additional_data
中,看一下该函数的具体使用
void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len,
const uint8_t user_additional_data[32]) {
if (out_len == 0) {
return;
}
// 是否是fork mode
const uint64_t fork_generation = CRYPTO_get_fork_generation();
// Additional data is mixed into every CTR-DRBG call to protect, as best we
// can, against forks & VM clones. We do not over-read this information and
// don't reseed with it so, from the point of view of FIPS, this doesn't
// provide “prediction resistance”. But, in practice, it does.
uint8_t additional_data[32];
// Intel chips have fast RDRAND instructions while, in other cases, RDRAND can
// be _slower_ than a system call.
if (
// intel cpu,支持硬件RDRAND
!have_fast_rdrand() ||
// 其他支持硬件RDRAND
!rdrand(additional_data, sizeof(additional_data))) {
// Without a hardware RNG to save us from address-space duplication, the OS
// entropy is used. This can be expensive (one read per |RAND_bytes| call)
// and so is disabled when we have fork detection, or if the application has
// promised not to fork.
if (fork_generation != 0 || rand_fork_unsafe_buffering_enabled()) {
OPENSSL_memset(additional_data, 0, sizeof(additional_data));
} else if (!have_rdrand()) {
// 没有 GCC/Clang __RAND__ 预处理,调用系统
// No alternative so block for OS entropy.
CRYPTO_sysrand(additional_data, sizeof(additional_data));
} else if (!CRYPTO_sysrand_if_available(additional_data,
sizeof(additional_data)) &&
!rdrand(additional_data, sizeof(additional_data))) {
// RDRAND failed: block for OS entropy.
CRYPTO_sysrand(additional_data, sizeof(additional_data));
}
}
for (size_t i = 0; i < sizeof(additional_data); i++) {
additional_data[i] ^= user_additional_data[i];
}
// TLS数据设置
struct rand_thread_state stack_state;
struct rand_thread_state *state =
CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_RAND);
// 根据状态会决定如何生成数据
// 1. 状态为空
if (state == NULL) {
state = OPENSSL_malloc(sizeof(struct rand_thread_state));
if (state == NULL ||
!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_RAND, state,
rand_thread_state_free)) {
// If the system is out of memory, use an ephemeral state on the
// stack.
state = &stack_state;
}
state->last_block_valid = 0;
uint8_t seed[CTR_DRBG_ENTROPY_LEN];
uint8_t personalization[CTR_DRBG_ENTROPY_LEN] = {0};
size_t personalization_len = 0;
// 获取seed
rand_get_seed(state, seed, personalization, &personalization_len);
if (!CTR_DRBG_init(&state->drbg, seed, personalization,
personalization_len)) {
abort();
}
state->calls = 0;
state->fork_generation = fork_generation;
#if defined(BORINGSSL_FIPS)
// 状态不空,设置状态链
if (state != &stack_state) {
CRYPTO_STATIC_MUTEX_lock_write(thread_states_list_lock_bss_get());
struct rand_thread_state **states_list = thread_states_list_bss_get();
state->next = *states_list;
if (state->next != NULL) {
state->next->prev = state;
}
state->prev = NULL;
*states_list = state;
CRYPTO_STATIC_MUTEX_unlock_write(thread_states_list_lock_bss_get());
}
#endif
}
if (state->calls >= kReseedInterval ||
state->fork_generation != fork_generation) {
uint8_t seed[CTR_DRBG_ENTROPY_LEN];
uint8_t reseed_additional_data[CTR_DRBG_ENTROPY_LEN] = {0};
size_t reseed_additional_data_len = 0;
rand_get_seed(state, seed, reseed_additional_data,
&reseed_additional_data_len);
#if defined(BORINGSSL_FIPS)
// Take a read lock around accesses to |state->drbg|. This is needed to
// avoid returning bad entropy if we race with
// |rand_thread_state_clear_all|.
//
// This lock must be taken after any calls to |CRYPTO_sysrand| to avoid a
// bug on ppc64le. glibc may implement pthread locks by wrapping user code
// in a hardware transaction, but, on some older versions of glibc and the
// kernel, syscalls made with |syscall| did not abort the transaction.
CRYPTO_STATIC_MUTEX_lock_read(state_clear_all_lock_bss_get());
#endif
// 如果超过了最大调用数,需要重新生成
if (!CTR_DRBG_reseed(&state->drbg, seed, reseed_additional_data,
reseed_additional_data_len)) {
abort();
}
state->calls = 0;
state->fork_generation = fork_generation;
} else {
#if defined(BORINGSSL_FIPS)
CRYPTO_STATIC_MUTEX_lock_read(state_clear_all_lock_bss_get());
#endif
}
int first_call = 1;
while (out_len > 0) {
size_t todo = out_len;
if (todo > CTR_DRBG_MAX_GENERATE_LENGTH) {
todo = CTR_DRBG_MAX_GENERATE_LENGTH;
}
// 利用CTR-DRBG伪随机数算法生成随机数据
if (!CTR_DRBG_generate(&state->drbg, out, todo, additional_data,
first_call ? sizeof(additional_data) : 0)) {
abort();
}
out += todo;
out_len -= todo;
// Though we only check before entering the loop, this cannot add enough to
// overflow a |size_t|.
state->calls++;
first_call = 0;
}
if (state == &stack_state) {
CTR_DRBG_clear(&state->drbg);
}
#if defined(BORINGSSL_FIPS)
CRYPTO_STATIC_MUTEX_unlock_read(state_clear_all_lock_bss_get());
#endif
}
生成additional_data
具体分析该函数
一、判读是否为fork mode
const uint64_t fork_generation = CRYPTO_get_fork_generation();
二、 生成additional_data
的三种方式
// 通过cpu硬件指令生成
rdrand(additional_data, sizeof(additional_data))
// 调用memset全设置为0,fork mode
OPENSSL_memset(additional_data, 0, sizeof(additional_data))
// 调用系统system call
CRYPTO_sysrand(additional_data, sizeof(additional_data))
其中调用硬件指令生成rdrand
// 将生成的数据分为两部分
// 1. CRYPTO_rdrand_multiple8_buf,生成8的倍数数据
// 2. rand_buf,生成剩余数据
static int rdrand(uint8_t *buf, const size_t len) {
const size_t len_multiple8 = len & ~7;
if (!CRYPTO_rdrand_multiple8_buf(buf, len_multiple8)) {
return 0;
}
const size_t remainder = len - len_multiple8;
if (remainder != 0) {
assert(remainder < 8);
uint8_t rand_buf[8];
if (!CRYPTO_rdrand(rand_buf)) {
return 0;
}
OPENSSL_memcpy(buf + len_multiple8, rand_buf, remainder);
}
return 1;
}
其中fork mode
用的memset
static inline void *OPENSSL_memset(void *dst, int c, size_t n) {
if (n == 0) {
return dst;
}
return memset(dst, c, n);
}
其中CRYPTO_sysrand(Linux)
实现
// CRYPTO_sysrand puts |requested| random bytes into |out|.
void CRYPTO_sysrand(uint8_t *out, size_t requested) {
if (!fill_with_entropy(out, requested, /*block=*/1, /*seed=*/0)) {
perror("entropy fill failed");
abort();
}
}
fill_with_entropy
函数内容比较多,只截取部分
if defined(USE_NR_getrandom)
// 普通类linux系统实现
r = boringssl_getrandom(out, len, getrandom_flags);
#elif defined(FREEBSD_GETRANDOM)
// freebsd系统实现
r = getrandom(out, len, getrandom_flags);
#elif defined(OPENSSL_MACOS)
// macOS系统
if (__builtin_available(macos 10.12, *)) {
// |getentropy| can only request 256 bytes at a time.
size_t todo = len <= 256 ? len : 256;
if (getentropy(out, todo) != 0) {
r = -1;
} else {
r = (ssize_t)todo;
}
} else {
fprintf(stderr, "urandom fd corrupt.\n");
abort();
}
#else // USE_NR_getrandom
fprintf(stderr, "urandom fd corrupt.\n");
abort();
#endif
} else {
do {
// 比较简单的一种方式直接取/dev/random的数据
r = read(*urandom_fd_bss_get(), out, len);
} while (r == -1 && errno == EINTR);
}
if (r <= 0) {
return 0;
}
out += r;
len -= r;
}
做一下归纳,主要是类linux
平台(包含macOS
)下的几种随机数产生的方式
-
USE_NR_getrandom
调用
boringssl_getrandom
,利用系统syscall(__NR_getrandom, buf, buf_len, flags)
生成数据 -
FREEBSD_GETRANDOM
freebsd
调用系统getrandom(out, len, getrandom_flags)
来生成 -
OPENSSL_MACOS
macOS
调用系统etentropy(out, todo)
来生成 -
最后一种
调用
open("/dev/urandom", O_RDONLY | O_CLOEXEC)
来获取,北大开源的国密算法实现的方式
其中CRYPTO_sysrand(Windows)
实现
// 直接调用windows系统实现的算法
void CRYPTO_sysrand(uint8_t *out, size_t requested) {
while (requested > 0) {
ULONG output_bytes_this_pass = ULONG_MAX;
if (requested < output_bytes_this_pass) {
output_bytes_this_pass = (ULONG)requested;
}
// On non-UWP configurations, use RtlGenRandom instead of BCryptGenRandom
// to avoid accessing resources that may be unavailable inside the
// Chromium sandbox. See https://crbug.com/boringssl/307
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
if (!BCRYPT_SUCCESS(BCryptGenRandom(
/*hAlgorithm=*/NULL, out, output_bytes_this_pass,
BCRYPT_USE_SYSTEM_PREFERRED_RNG))) {
#else
// 调用windows系统随机数
if (RtlGenRandom(out, output_bytes_this_pass) == FALSE) {
#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
abort();
}
requested -= output_bytes_this_pass;
out += output_bytes_this_pass;
}
return;
}
异或处理additional_data
for (size_t i = 0; i < sizeof(additional_data); i++) {
additional_data[i] ^= user_additional_data[i];
}
生成seed
根据TLS
的状态会调用rand_get_seed
去生成seed
或者是重置seed
数据
struct rand_thread_state *state =
CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_RAND);
第一种情况state == NULL
if (state == NULL) {
// 设置state状态
state = OPENSSL_malloc(sizeof(struct rand_thread_state));
if (state == NULL ||
!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_RAND, state,
rand_thread_state_free)) {
// If the system is out of memory, use an ephemeral state on the
// stack.
state = &stack_state;
}
a
state->last_block_valid = 0;
uint8_t seed[CTR_DRBG_ENTROPY_LEN]; //CTR_DRBG_ENTROPY_LEN == 48
uint8_t personalization[CTR_DRBG_ENTROPY_LEN] = {0};
size_t personalization_len = 0;
// 设置seed数据
rand_get_seed(state, seed, personalization, &personalization_len);
// 根据seed初始化
if (!CTR_DRBG_init(&state->drbg, seed, personalization,
personalization_len)) {
abort();
}
// 设置调用间隔为0
state->calls = 0;
state->fork_generation = fork_generation;
#if defined(BORINGSSL_FIPS)
// 设置线程状态链
if (state != &stack_state) {
CRYPTO_STATIC_MUTEX_lock_write(thread_states_list_lock_bss_get());
struct rand_thread_state **states_list = thread_states_list_bss_get();
state->next = *states_list;
if (state->next != NULL) {
state->next->prev = state;
}
state->prev = NULL;
*states_list = state;
CRYPTO_STATIC_MUTEX_unlock_write(thread_states_list_lock_bss_get());
}
#endif
}
第二种情况
// 超出调用数,需要重置种子
if (state->calls >= kReseedInterval ||
state->fork_generation != fork_generation) {
uint8_t seed[CTR_DRBG_ENTROPY_LEN];
uint8_t reseed_additional_data[CTR_DRBG_ENTROPY_LEN] = {0};
size_t reseed_additional_data_len = 0;
// 获取seed
rand_get_seed(state, seed, reseed_additional_data,
&reseed_additional_data_len);
#if defined(BORINGSSL_FIPS)
// Take a read lock around accesses to |state->drbg|. This is needed to
// avoid returning bad entropy if we race with
// |rand_thread_state_clear_all|.
//
// This lock must be taken after any calls to |CRYPTO_sysrand| to avoid a
// bug on ppc64le. glibc may implement pthread locks by wrapping user code
// in a hardware transaction, but, on some older versions of glibc and the
// kernel, syscalls made with |syscall| did not abort the transaction.
CRYPTO_STATIC_MUTEX_lock_read(state_clear_all_lock_bss_get());
#endif
// 重置种子数据
if (!CTR_DRBG_reseed(&state->drbg, seed, reseed_additional_data,
reseed_additional_data_len)) {
abort();
}
state->calls = 0;
state->fork_generation = fork_generation;
} else {
#if defined(BORINGSSL_FIPS)
CRYPTO_STATIC_MUTEX_lock_read(state_clear_all_lock_bss_get());
#endif
}
来具体看看rand_get_seed
,该函数根据是否定义了BORINGSSL_FIPS
,会有不同的操作
- 已定义
BORINGSSL_FIPS
具体使用
// rand_get_seed fills |seed| with entropy. In some cases, it will additionally
// fill |additional_input| with entropy to supplement |seed|. It sets
// |*out_additional_input_len| to the number of extra bytes.
static void rand_get_seed(struct rand_thread_state *state,
uint8_t seed[CTR_DRBG_ENTROPY_LEN],
uint8_t additional_input[CTR_DRBG_ENTROPY_LEN],
size_t *out_additional_input_len) {
uint8_t entropy_bytes[sizeof(state->last_block) +
CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD];
uint8_t *entropy = entropy_bytes;
size_t entropy_len = sizeof(entropy_bytes);
if (state->last_block_valid) {
// No need to fill |state->last_block| with entropy from the read.
entropy += sizeof(state->last_block);
entropy_len -= sizeof(state->last_block);
}
int want_additional_input;
// 获取seed的熵值
get_seed_entropy(entropy, entropy_len, &want_additional_input);
if (!state->last_block_valid) {
OPENSSL_memcpy(state->last_block, entropy, sizeof(state->last_block));
entropy += sizeof(state->last_block);
entropy_len -= sizeof(state->last_block);
}
// See FIPS 140-2, section 4.9.2. This is the “continuous random number
// generator test” which causes the program to randomly abort. Hopefully the
// rate of failure is small enough not to be a problem in practice.
if (CRYPTO_memcmp(state->last_block, entropy, sizeof(state->last_block)) ==
0) {
fprintf(stderr, "CRNGT failed.\n");
BORINGSSL_FIPS_abort();
}
assert(entropy_len % CRNGT_BLOCK_SIZE == 0);
for (size_t i = CRNGT_BLOCK_SIZE; i < entropy_len; i += CRNGT_BLOCK_SIZE) {
if (CRYPTO_memcmp(entropy + i - CRNGT_BLOCK_SIZE, entropy + i,
CRNGT_BLOCK_SIZE) == 0) {
fprintf(stderr, "CRNGT failed.\n");
BORINGSSL_FIPS_abort();
}
}
OPENSSL_memcpy(state->last_block, entropy + entropy_len - CRNGT_BLOCK_SIZE,
CRNGT_BLOCK_SIZE);
assert(entropy_len == BORINGSSL_FIPS_OVERREAD * CTR_DRBG_ENTROPY_LEN);
OPENSSL_memcpy(seed, entropy, CTR_DRBG_ENTROPY_LEN);
// 异或处理
for (size_t i = 1; i < BORINGSSL_FIPS_OVERREAD; i++) {
for (size_t j = 0; j < CTR_DRBG_ENTROPY_LEN; j++) {
seed[j] ^= entropy[CTR_DRBG_ENTROPY_LEN * i + j];
}
}
// If we used something other than system entropy then also
// opportunistically read from the system. This avoids solely relying on the
// hardware once the entropy pool has been initialized.
*out_additional_input_len = 0;
if (want_additional_input &&
CRYPTO_sysrand_if_available(additional_input, CTR_DRBG_ENTROPY_LEN)) {
*out_additional_input_len = CTR_DRBG_ENTROPY_LEN;
}
}
生成熵值
生成seed
之前,需要获取熵值
// get_seed_entropy fills |out_entropy_len| bytes of |out_entropy| from the
// global |entropy_buffer|.
static void get_seed_entropy(uint8_t *out_entropy, size_t out_entropy_len,
int *out_want_additional_input) {
// 这里获取到的是空值
struct entropy_buffer *const buffer = entropy_buffer_bss_get();
if (out_entropy_len > sizeof(buffer->bytes)) {
abort();
}
CRYPTO_STATIC_MUTEX_lock_write(entropy_buffer_lock_bss_get());
while (buffer->bytes_valid < out_entropy_len) {
CRYPTO_STATIC_MUTEX_unlock_write(entropy_buffer_lock_bss_get());
// 会调用passive.c中的函数去实现
RAND_need_entropy(out_entropy_len - buffer->bytes_valid);
CRYPTO_STATIC_MUTEX_lock_write(entropy_buffer_lock_bss_get());
}
// 将数据存入struct entropy_buffer中
*out_want_additional_input = buffer->want_additional_input;
OPENSSL_memcpy(out_entropy, buffer->bytes, out_entropy_len);
OPENSSL_memmove(buffer->bytes, &buffer->bytes[out_entropy_len],
buffer->bytes_valid - out_entropy_len);
buffer->bytes_valid -= out_entropy_len;
if (buffer->bytes_valid == 0) {
buffer->want_additional_input = 0;
}
CRYPTO_STATIC_MUTEX_unlock_write(entropy_buffer_lock_bss_get());
}
调用entropy_buffer_bss_get
获取熵值,结合宏定义DEFINE_BSS_GET(struct entropy_buffer, entropy_buffer)
,真正起作用的是RAND_need_entropy(out_entropy_len - buffer->bytes_valid)
void RAND_need_entropy(size_t bytes_needed) {
uint8_t buf[/* last_block size */ 16 +
CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD];
size_t todo = sizeof(buf);
if (todo > bytes_needed) {
todo = bytes_needed;
}
int want_additional_input;
// 下面两个函数都是在rand.c中实现
CRYPTO_get_seed_entropy(buf, todo, &want_additional_input);
RAND_load_entropy(buf, todo, want_additional_input);
}
跟踪CRYPTO_get_seed_entropy
生成熵值
void CRYPTO_get_seed_entropy(uint8_t *out_entropy, size_t out_entropy_len,
int *out_want_additional_input) {
*out_want_additional_input = 0;
// 硬件/编译器相关函数实现
if (have_rdrand() && rdrand(out_entropy, out_entropy_len)) {
*out_want_additional_input = 1;
} else {
// 直接调用平台相关函数实现
CRYPTO_sysrand_for_seed(out_entropy, out_entropy_len);
}
if (boringssl_fips_break_test("CRNG")) {
// This breaks the "continuous random number generator test" defined in FIPS
// 140-2, section 4.9.2, and implemented in |rand_get_seed|.
OPENSSL_memset(out_entropy, 0, out_entropy_len);
}
}
将对应的熵值传入结构体entropy_buffer
中
void RAND_load_entropy(const uint8_t *entropy, size_t entropy_len,
int want_additional_input) {
// 获取entropy_buffer
struct entropy_buffer *const buffer = entropy_buffer_bss_get();
CRYPTO_STATIC_MUTEX_lock_write(entropy_buffer_lock_bss_get());
const size_t space = sizeof(buffer->bytes) - buffer->bytes_valid;
if (entropy_len > space) {
entropy_len = space;
}
// entropy存入buffer中
OPENSSL_memcpy(&buffer->bytes[buffer->bytes_valid], entropy, entropy_len);
buffer->bytes_valid += entropy_len;
buffer->want_additional_input |=
want_additional_input && (entropy_len != 0);
CRYPTO_STATIC_MUTEX_unlock_write(entropy_buffer_lock_bss_get());
}
获取熵值之后,具体如何生成seed
在循环中
OPENSSL_memcpy(seed, entropy, CTR_DRBG_ENTROPY_LEN);
// 异或处理
for (size_t i = 1; i < BORINGSSL_FIPS_OVERREAD; i++) {
for (size_t j = 0; j < CTR_DRBG_ENTROPY_LEN; j++) {
seed[j] ^= entropy[CTR_DRBG_ENTROPY_LEN * i + j];
}
}
生成随机数
随机数生成算法可以根据是否是hash
还是分组加密,可以分为以下几种
// 基于hash算法
HMAC-DRBG
KHF-DRBG
Hash-DRBG
// 基于分组加密算法
AES-OFB
AES-CTR
TDEA-OFB
TDEA-CTR
boringssl
的随机数生成算法使用的是NIST SP 800-90A
伪随机数生成器算法AES256-CTR-DRBG
生成完seed
和熵值,最终调用CTR_DRBG_generate
来生成具体随机数
真正生成之前需要初始化,调用CTR_DRBG_init
,设置CTR
算法部分初始化状态
int CTR_DRBG_init(CTR_DRBG_STATE *drbg,
const uint8_t entropy[CTR_DRBG_ENTROPY_LEN],
const uint8_t *personalization, size_t personalization_len) {
// Section 10.2.1.3.1
if (personalization_len > CTR_DRBG_ENTROPY_LEN) {
return 0;
}
uint8_t seed_material[CTR_DRBG_ENTROPY_LEN];
// 将上一个步骤生成的entropy熵值复制
OPENSSL_memcpy(seed_material, entropy, CTR_DRBG_ENTROPY_LEN);
// 结合entropy和前一步生成的personalization做异或计算
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.
// 异或的初始化table
static const uint8_t kInitMask[CTR_DRBG_ENTROPY_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,
};
// 再次跟table做异或计算
for (size_t i = 0; i < sizeof(kInitMask); i++) {
seed_material[i] ^= kInitMask[i];
}
// 根据seed_material初始化ctr
drbg->ctr = aes_ctr_set_key(&drbg->ks, NULL, &drbg->block, seed_material, 32);
OPENSSL_memcpy(drbg->counter, seed_material + 32, 16);
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
// 是否超过最大reseed数
if (drbg->reseed_counter > kMaxReseedCount) {
return 0;
}
// 利用第一步生成的additional_data,更新init初始化后的数据
if (additional_data_len != 0 &&
!ctr_drbg_update(drbg, additional_data, additional_data_len)) {
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.
static const 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;
// 处理每组数据
if (drbg->ctr) {
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));
} else {
for (size_t i = 0; i < todo; i += AES_BLOCK_SIZE) {
ctr32_add(drbg, 1);
drbg->block(drbg->counter, out + i, &drbg->ks);
}
}
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);
// 最终的out随机数据
OPENSSL_memcpy(out, block, out_len);
}
// Right-padding |additional_data| in step 2.2 is handled implicitly by
// |ctr_drbg_update|, to save a copy.
// 再次更新
if (!ctr_drbg_update(drbg, additional_data, additional_data_len)) {
return 0;
}
// 生成数需要+1
drbg->reseed_counter++;
FIPS_service_indicator_update_state();
return 1;
}
至此boringssl
的随机数相关内容分析完毕
参考
NIST Cryptographic Module Validation Program
Five DRBG Algorithms Based on Hash Functions and Block
Pseudorandom Black Swans Cache Attacks on CTR_DRBG
Faster Randomness Testing with the NIST Statistical Test Suite