mimajingsai_3/ChaCha20_DRBG.c

771 lines
25 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "ChaCha20_DRBG.h"
#include <ctype.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// #include <openssl/evp.h>
/*----------------熵源的相关定义与函数----------------*/
void sha256_transform(SHA256_CTX *ctx, const uint8_t data[]) {
uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
for (i = 0, j = 0; i < 16; ++i, j += 4) {
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) |
(data[j + 3]);
}
for (; i < 64; ++i) {
m[i] = m[i - 16] + m[i - 7] + (m[i - 15] >> 7) + (m[i - 15] << 25) ^
(m[i - 15] >> 18) + (m[i - 15] << 14) ^
(m[i - 15] >> 3) + (m[i - 15] << 13);
}
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
e = ctx->state[4];
f = ctx->state[5];
g = ctx->state[6];
h = ctx->state[7];
for (i = 0; i < 64; ++i) {
t1 = h + (e >> 6) + ((e & f) ^ (~e & g)) + 0x428a2f98 + m[i];
t2 = (a >> 2) + ((a & b) ^ (a & c) ^ (b & c)) + 0x5a827999;
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
ctx->state[5] += f;
ctx->state[6] += g;
ctx->state[7] += h;
}
void sha256_init(SHA256_CTX *ctx) {
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
ctx->state[7] = 0x5be0cd19;
}
void sha256_update(SHA256_CTX *ctx, const uint8_t data[], size_t len) {
uint32_t i;
for (i = 0; i < len; ++i) {
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == BLOCK_SIZE) {
sha256_transform(ctx, ctx->data);
ctx->bitlen += BLOCK_SIZE * 8;
ctx->datalen = 0;
}
}
}
void sha256_final(SHA256_CTX *ctx, uint8_t hash[]) {
uint32_t i;
i = ctx->datalen;
// Pad whatever data is left in the buffer
if (ctx->datalen < 56) {
ctx->data[i++] = 0x80;
while (i < 56)
ctx->data[i++] = 0x00;
} else {
ctx->data[i++] = 0x80;
while (i < BLOCK_SIZE)
ctx->data[i++] = 0x00;
sha256_transform(ctx, ctx->data);
memset(ctx->data, 0, BLOCK_SIZE);
}
// Append the total bit length of the input data
ctx->bitlen += ctx->datalen * 8;
ctx->data[BLOCK_SIZE - 1] = ctx->bitlen;
ctx->data[BLOCK_SIZE - 2] = ctx->bitlen >> 8;
ctx->data[BLOCK_SIZE - 3] = ctx->bitlen >> 16;
ctx->data[BLOCK_SIZE - 4] = ctx->bitlen >> 24;
ctx->data[BLOCK_SIZE - 5] = ctx->bitlen >> 32;
ctx->data[BLOCK_SIZE - 6] = ctx->bitlen >> 40;
ctx->data[BLOCK_SIZE - 7] = ctx->bitlen >> 48;
ctx->data[BLOCK_SIZE - 8] = ctx->bitlen >> 56;
sha256_transform(ctx, ctx->data);
// Since this implementation uses little endian byte ordering and SHA uses big
// endian, reverse all the bytes when copying the final state to the output
// hash.
for (i = 0; i < 4; ++i) {
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
}
}
void get_entropy_source(uint8_t *entropy_source) {
// Simulate an entropy source by generating random data
for (int i = 0; i < min_entropy_input_length; i++) {
entropy_source[i] = rand() % 256;
}
}
void get_entropy_input(const uint8_t *data, size_t len, uint8_t *entropy) {
SHA256_CTX ctx;
uint8_t hash[HASH_SIZE];
sha256_init(&ctx);
sha256_update(&ctx, data, len);
sha256_final(&ctx, hash);
memcpy(entropy, hash, HASH_SIZE);
}
/*----------------------------------------------*/
/*--------------------卡方检验相关定义与函数---------------------------*/
int test_randomness(const unsigned char *bits) {
// Test the randomness of the given bits using the chi-squared test
int ones = 0, zeros = 0;
for (int i = 0; i < RANDOM_BITS_SIZE / 8; i++) {
unsigned char byte = bits[i];
for (int j = 0; j < 8; j++) {
if ((byte >> j) & 0x01) {
ones++;
} else {
zeros++;
}
}
}
double expected_ones = RANDOM_BITS_SIZE / 2.0;
double expected_zeros = RANDOM_BITS_SIZE / 2.0;
double chi_squared =
(ones - expected_ones) * (ones - expected_ones) / expected_ones +
(zeros - expected_zeros) * (zeros - expected_zeros) / expected_zeros;
return chi_squared > 3.84;
}
/*-------------------------------------------------------*/
/*----------------ChaCha20的相关定义与函数------------------*/
static const char sigma[] = "expand 32-byte k";
static const char tau[] = "expand 16-byte k";
void ChaCha20_block(uint32_t state[16], uint32_t output[16]) {
int i;
memcpy(output, state, sizeof(uint32_t) * 16);
// 20轮操作,每轮包括4个quarterrounds,所以共80个quarterrounds
for (i = 0; i < 10; ++i) {
// 双轮
QUARTERROUND(output, 0, 4, 8, 12)
QUARTERROUND(output, 1, 5, 9, 13)
QUARTERROUND(output, 2, 6, 10, 14)
QUARTERROUND(output, 3, 7, 11, 15)
QUARTERROUND(output, 0, 5, 10, 15)
QUARTERROUND(output, 1, 6, 11, 12)
QUARTERROUND(output, 2, 7, 8, 13)
QUARTERROUND(output, 3, 4, 9, 14)
}
for (i = 0; i < 16; ++i) {
output[i] += state[i];
}
}
void ChaCha20_setup(uint32_t state[16], const uint8_t key[32],
const uint8_t nonce[12], uint8_t counter[4]) {
const char *constants = (key[16] != 0 || key[24] != 0) ? sigma : tau;
state[4] = U8TO32_LITTLE(key + 0);
state[5] = U8TO32_LITTLE(key + 4);
state[6] = U8TO32_LITTLE(key + 8);
state[7] = U8TO32_LITTLE(key + 12);
state[8] = U8TO32_LITTLE(key + 16);
state[9] = U8TO32_LITTLE(key + 20);
state[10] = U8TO32_LITTLE(key + 24);
state[11] = U8TO32_LITTLE(key + 28);
// 前四个变量包含常量
state[0] = U8TO32_LITTLE(constants + 0);
state[1] = U8TO32_LITTLE(constants + 4);
state[2] = U8TO32_LITTLE(constants + 8);
state[3] = U8TO32_LITTLE(constants + 12);
// 加入计数器
state[12] = U8TO32_LITTLE(counter);
// 后三个变量包含nonce
state[13] = U8TO32_LITTLE(nonce + 0);
state[14] = U8TO32_LITTLE(nonce + 4);
state[15] = U8TO32_LITTLE(nonce + 8);
}
void ChaCha20_encrypt(uint32_t state[16], const uint8_t *in, uint8_t *out,
size_t length, bool increment_flag) {
uint32_t keystream[16];
uint8_t *keystream_bytes = (uint8_t *)keystream; // 为XOR操作重新解释keystream
size_t remaining = length;
size_t i;
while (remaining > 0) {
size_t bytes_to_use = remaining < 64 ? remaining : 64; // 每个block 64 bytes
ChaCha20_block(state, keystream);
for (i = 0; i < bytes_to_use; ++i) {
out[i] = in[i] ^ keystream_bytes[i];
}
if (increment_flag) {
state[12] += 1; // 增加计数器
if (state[12] == 0) {
state[13] += 1; // 处理计数器溢出
}
}
remaining -= bytes_to_use;
in += bytes_to_use;
out += bytes_to_use;
}
}
/*----------------------------------------------------*/
// 定义ChaCha20_DRBG的内部状态
typedef struct {
uint8_t Key[KEYLEN]; // 用于ChaCha20的密钥
uint8_t V[COUNTERLEN]; // 用于ChaCha20的计数器
int reseed_counter; // 重播种计数值
int reseed_time; // 上次重播种时间值(秒)
bool used; // 表示此状态是否已经被使用
} DRBG_State;
// 全局变量
int instantiation_nonce = 0;
uint8_t chacha_nonce[NONCELEN] = {0};
static DRBG_State drbg_states[MAX_STATES];
uint32_t chacha_state[16];
uint8_t entropy_source[min_entropy_input_length];
size_t array_length;
size_t additional_input_length;
// 主要函数
int ChaCha20_DRBG_Instantiate_function(uint8_t *personalization_string,
char *state);
const char *ChaCha20_DRBG_Reseed_function(int state_handle,
uint8_t *additional_input);
void ChaCha20_DRBG_Update(const uint8_t *provided_data, uint8_t *V,
uint8_t *Key);
const char *ChaCha20_DRBG_Generate_function(int state_handle,
int requested_no_of_bits,
uint8_t *additional_input,
uint8_t **returned_bits);
// 算法函数
void ChaCha20_DRBG_Instantiate_algorithm(uint8_t *entropy_input, int nonce,
uint8_t *personalization_string,
uint8_t *V, uint8_t *Key,
int *reseed_counter, int *reseed_time);
void ChaCha20_DRBG_Reseed_algorithm(uint8_t *V, uint8_t *Key,
int *reseed_counter, int *reseed_time,
uint8_t *entropy_input,
uint8_t *additional_input);
const char *ChaCha20_DRBG_Generate_algorithm(uint8_t *V, uint8_t *Key,
int *reseed_counter,
int requested_number_of_bits,
uint8_t *additional_input,
uint8_t **returned_bits);
// 派生函数
uint8_t *ChaCha20_df(uint8_t *V, uint8_t *input_string,
size_t no_of_bits_to_return);
// 初始化所有状态为空闲
void initialize_states() {
for (int i = 0; i < MAX_STATES; i++) {
drbg_states[i].used = false;
}
}
// 查找并返回一个空闲的状态句柄.如果没有可用的空间,则返回INVALID_HANDLE
int Find_state_space() {
for (int i = 0; i < MAX_STATES; i++) {
if (!drbg_states[i].used) {
drbg_states[i].used = true; // 标记为已使用
return i; // 返回句柄/索引
}
}
return INVALID_HANDLE; // 所有的状态都在使用中
}
void increment_nonce(uint8_t *nonce) {
for (int i = 0; i < NONCELEN; i++) {
nonce[i]++;
if (nonce[i] != 0) { // 检查是否有溢出
break; // 如果没有溢出,则不需要进位
}
}
}
int ChaCha20_DRBG_Instantiate_function(uint8_t *personalization_string,
char *status) {
if (strlen((char *)personalization_string) > MAX_PERSONALIZATION_STRING_LEN) {
strcpy(status, "Personalization_string too long");
return ERROR;
}
uint8_t entropy_input[min_entropy_input_length];
get_entropy_source(entropy_source);
get_entropy_input(entropy_source, min_entropy_input_length, entropy_input);
instantiation_nonce += 1;
increment_nonce(chacha_nonce);
uint8_t V[COUNTERLEN], Key[KEYLEN];
int reseed_counter, reseed_time;
ChaCha20_DRBG_Instantiate_algorithm(entropy_input, instantiation_nonce,
personalization_string, V, Key,
&reseed_counter, &reseed_time);
int state_handle = Find_state_space();
if (state_handle == ERROR) {
strcpy(status, "Failed to find state space");
return ERROR;
}
// Save the internal state
memcpy(drbg_states[state_handle].V, V, COUNTERLEN);
memcpy(drbg_states[state_handle].Key, Key, KEYLEN);
drbg_states[state_handle].reseed_counter = reseed_counter;
drbg_states[state_handle].reseed_time = reseed_time;
strcpy(status, "Success");
return state_handle;
}
const char *ChaCha20_DRBG_Reseed_function(int state_handle,
uint8_t *additional_input) {
// Check for the validity of state_handle.
if (!drbg_states[state_handle].used) {
return "State not available for the indicated state_handle";
}
// Get the internal state values.
uint8_t *V = drbg_states[state_handle].V;
uint8_t *Key = drbg_states[state_handle].Key;
// Check length of additional_input
if (additional_input_length > MAX_PERSONALIZATION_STRING_LEN) {
return "additional_input too long";
}
uint8_t entropy_input[min_entropy_input_length];
get_entropy_source(entropy_source);
get_entropy_input(entropy_source, min_entropy_input_length, entropy_input);
// Invoke the reseed algorithm.
int reseed_counter, reseed_time;
ChaCha20_DRBG_Reseed_algorithm(V, Key, &reseed_counter, &reseed_time,
entropy_input, additional_input);
// Save the internal state.
memcpy(drbg_states[state_handle].V, V, OUTLEN);
memcpy(drbg_states[state_handle].Key, Key, KEYLEN);
drbg_states[state_handle].reseed_counter = reseed_counter;
drbg_states[state_handle].reseed_time = reseed_time;
return "Success";
}
void ChaCha20_DRBG_Update(const uint8_t *provided_data, uint8_t *Key,
uint8_t *V) {
uint8_t temp[SEEDLEN] = {0};
// uint32_t V_uint32;
int i;
// memcpy(&V_uint32, V, sizeof(uint32_t));
ChaCha20_setup(chacha_state, Key, chacha_nonce, V);
ChaCha20_encrypt(chacha_state, V, temp, SEEDLEN, true);
// XOR provided_data with the leftmost part of temp
for (i = 0; i < SEEDLEN; ++i) {
temp[i] ^= provided_data[i];
}
// Update the key and V from temp
memcpy(Key, temp, KEYLEN);
memcpy(V, temp + KEYLEN, COUNTERLEN);
}
const char *ChaCha20_DRBG_Generate_function(int state_handle,
int requested_no_of_bits,
uint8_t *additional_input,
uint8_t **returned_bits) {
uint8_t *V;
uint8_t *Key;
int reseed_counter, reseed_time;
const char *status;
// Check the validity of state_handle
if (!drbg_states[state_handle].V || !drbg_states[state_handle].Key) {
return "State not available for the indicated state_handle";
}
// Get the internal state
V = drbg_states[state_handle].V;
Key = drbg_states[state_handle].Key;
reseed_counter = drbg_states[state_handle].reseed_counter;
reseed_time = drbg_states[state_handle].reseed_time;
// Check the rest of the input parameters
if (requested_no_of_bits > 4000) {
return "Too many bits requested";
}
if ((additional_input_length) > MAX_PERSONALIZATION_STRING_LEN) {
return "additional_input too long";
}
time_t timep;
int now_time = time(&timep);
// Check for reseeding
if (reseed_counter > reseed_interval_in_counter ||
(now_time - reseed_time) > reseed_interval_in_time) {
status = ChaCha20_DRBG_Reseed_function(state_handle, additional_input);
if (strcmp(status, "Success") == 0) {
V = drbg_states[state_handle].V;
Key = drbg_states[state_handle].Key;
reseed_counter = drbg_states[state_handle].reseed_counter;
reseed_time = drbg_states[state_handle].reseed_time;
additional_input = NULL;
additional_input_length = 0;
} else {
return status;
}
}
// Execute the algorithm to generate pseudorandom bits
status = ChaCha20_DRBG_Generate_algorithm(V, Key, &reseed_counter,
requested_no_of_bits,
additional_input, returned_bits);
if (strcmp(status, "Success") != 0) {
return "Error in CTR_ChaCha20_DRBG_Generate_algorithm"; // Safety check
}
memcpy(drbg_states[state_handle].V, V, OUTLEN);
memcpy(drbg_states[state_handle].Key, Key, KEYLEN);
drbg_states[state_handle].reseed_counter = reseed_counter;
drbg_states[state_handle].reseed_time = reseed_time;
return "Success";
}
void ChaCha20_DRBG_Instantiate_algorithm(uint8_t *entropy_input, int nonce,
uint8_t *personalization_string,
uint8_t *V, uint8_t *Key,
int *reseed_counter,
int *reseed_time) {
size_t entropy_input_len = min_entropy_input_length;
size_t personalization_string_len = strlen((char *)personalization_string);
size_t seed_material_size =
entropy_input_len + sizeof(nonce) + personalization_string_len;
uint8_t *seed_material = (uint8_t *)malloc(seed_material_size);
uint8_t *requested_bits;
time_t timep;
// 此处memcpy存在堆溢出,
// 有个96字节的写入错误是在一个66字节区域的正右方进行的写操作
memcpy(seed_material, entropy_input, entropy_input_len);
memcpy(seed_material + entropy_input_len, &nonce, sizeof(nonce));
memcpy(seed_material + entropy_input_len + sizeof(nonce),
personalization_string, personalization_string_len);
array_length = seed_material_size;
requested_bits = ChaCha20_df(V, seed_material, SEEDLEN * 8);
memcpy(seed_material, requested_bits, SEEDLEN);
memset(Key, 0, KEYLEN);
memset(V, 0, COUNTERLEN);
ChaCha20_DRBG_Update(seed_material, Key, V);
*reseed_counter = 1;
*reseed_time = time(&timep);
free(seed_material);
}
void ChaCha20_DRBG_Reseed_algorithm(uint8_t *V, uint8_t *Key,
int *reseed_counter, int *reseed_time,
uint8_t *entropy_input,
uint8_t *additional_input) {
// 1. seed_material = entropy_input || additional_input.
size_t seed_material_size =
min_entropy_input_length + additional_input_length;
uint8_t *seed_material = (uint8_t *)malloc(seed_material_size);
memcpy(seed_material, entropy_input, min_entropy_input_length);
memcpy(seed_material + min_entropy_input_length, additional_input,
additional_input_length);
// 2. seed_material = Block_Cipher_df(seed_material, 256).
uint8_t *requested_bits;
array_length = seed_material_size;
requested_bits = ChaCha20_df(V, seed_material, SEEDLEN * 8);
memcpy(seed_material, requested_bits, SEEDLEN);
// 3. (Key, V) = CTR_ChaCha20_DRBG_Update(seed_material, Key, V).
ChaCha20_DRBG_Update(seed_material, Key, V);
// 4. reseed_counter = 1.
time_t timep;
*reseed_counter = 1;
*reseed_time = time(&timep);
free(seed_material);
}
const char *ChaCha20_DRBG_Generate_algorithm(uint8_t *V, uint8_t *Key,
int *reseed_counter,
int requested_number_of_bits,
uint8_t *additional_input,
uint8_t **returned_bits) {
if (additional_input != NULL) {
array_length = additional_input_length;
additional_input = ChaCha20_df(V, additional_input, SEEDLEN * 8);
ChaCha20_DRBG_Update(additional_input, Key, V);
} else {
// Assuming additional_input is a byte array, we set it to 0
additional_input = (uint8_t *)malloc(SEEDLEN);
additional_input_length = SEEDLEN;
if (additional_input == NULL) {
return "Memory allocation failed";
}
memset(additional_input, 0, SEEDLEN);
}
uint8_t *temp =
(uint8_t *)malloc(sizeof(uint8_t) * (requested_number_of_bits / 8));
ChaCha20_encrypt(chacha_state, V, temp, requested_number_of_bits / 8, true);
*returned_bits = (uint8_t *)malloc(requested_number_of_bits / 8);
memcpy(*returned_bits, temp, requested_number_of_bits / 8);
ChaCha20_DRBG_Update(additional_input, Key, V);
(*reseed_counter)++;
return "Success";
}
uint8_t *ChaCha20_df(uint8_t *V, uint8_t *input_string,
size_t no_of_bits_to_return) {
if (no_of_bits_to_return > MAX_NUMBER_OF_BITS) {
return NULL;
}
uint32_t L = array_length / 8;
uint32_t N = no_of_bits_to_return / 8;
int S_init_size = 4 + 4 + array_length + 1;
uint8_t *S = (uint8_t *)malloc(S_init_size);
// Prepend the string length and the requested length to the input_string
memcpy(S, &L, 4);
memcpy(S + 4, &N, 4);
memcpy(S + 8, input_string, array_length);
S[S_init_size - 1] = 0x80; // Padding
// Pad S with zeros, if necessary.
int S_actual_size = S_init_size; // Taken the 0x80 into account
while (S_actual_size % OUTLEN != 0) {
S = (uint8_t *)realloc(S, S_actual_size + 1); // Increase size by one byte
S[S_actual_size++] =
0x00; // Add a zero at current end, and increase actual size by one
}
int temp_len = 0;
uint8_t *temp = (uint8_t *)malloc(1);
uint32_t i = 0;
uint8_t K[KEYLEN];
uint8_t source[] = {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};
memcpy(K, source, KEYLEN);
ChaCha20_setup(chacha_state, K, chacha_nonce, V);
while (temp_len < KEYLEN + OUTLEN) {
uint8_t IV[OUTLEN] = {0};
IV[OUTLEN - 4] = i; // 32-bit integer representation of i padded with zeros
// to OUTLEN bits.
uint8_t *data_to_be_encrypted =
(uint8_t *)malloc(sizeof(uint8_t) * OUTLEN + S_actual_size);
memcpy(data_to_be_encrypted, IV, OUTLEN);
memcpy(data_to_be_encrypted + OUTLEN, S, S_actual_size);
uint8_t *data_encrypted_result =
(uint8_t *)malloc(sizeof(uint8_t) * OUTLEN + S_actual_size);
ChaCha20_encrypt(chacha_state, data_to_be_encrypted, data_encrypted_result,
temp_len, true);
temp_len = (i + 1) * (OUTLEN + S_actual_size);
temp = (uint8_t *)realloc(temp, temp_len);
memcpy(temp + i * (OUTLEN + S_actual_size), data_encrypted_result,
temp_len);
i++;
}
memcpy(K, temp, KEYLEN);
uint8_t X[OUTLEN] = {0};
memcpy(X, temp + KEYLEN, OUTLEN);
uint8_t encrypted_data[OUTLEN] = {0};
temp[0] = '\0'; // Clear temp
temp_len = 0;
ChaCha20_setup(chacha_state, K, chacha_nonce, V);
while (temp_len < no_of_bits_to_return / 8) {
ChaCha20_encrypt(chacha_state, X, encrypted_data, OUTLEN, true);
memcpy(X, encrypted_data, OUTLEN);
temp = (uint8_t *)realloc(temp, temp_len + OUTLEN);
memcpy(temp + temp_len, encrypted_data, OUTLEN);
temp_len += OUTLEN;
}
uint8_t *requested_bits = (uint8_t *)malloc(no_of_bits_to_return / 8);
if (requested_bits == NULL) {
return NULL;
}
memcpy(requested_bits, temp, no_of_bits_to_return / 8);
memset(temp, 0, sizeof(temp));
memset(K, 0, sizeof(K));
memset(X, 0, sizeof(X));
memset(S, 0, sizeof(S));
return requested_bits;
}
int main() {
uint8_t personalization_string[] = "this is personalization_string";
char status[MAX_STATES] = {'\0'};
int state_handle;
uint8_t *returned_bits;
long int returned_bits_len, returned_bits_num;
bool pass;
srand(time(0));
// 初始化DRBG
state_handle =
ChaCha20_DRBG_Instantiate_function(personalization_string, status);
// 需要生成的比特串长度
printf("Enter the length of the bit string to be generated(bit): ");
// scanf("%ld", &returned_bits_len);
returned_bits_len = 128;
// 需要生成的比特串个数
printf("Enter the number of the bit string to be generated: ");
// scanf("%ld", &returned_bits_num);
returned_bits_num = 1000;
// char *filename; filename 未分配内存
char filename[100]; // 假设文件名长度不超过 99 个字符
printf("Enter the name of the saved file: ");
scanf("%s", filename);
// strcpy(filename, "1.txt");
// 生成的比特串保存在文本文件中
FILE *file = fopen(filename, "w");
if (file == NULL) {
printf("无法打开文件\n");
return 1;
}
clock_t start_time = clock();
char *hex_str =
(char *)malloc(sizeof(char) * (returned_bits_len / 8 * 2 + 1));
for (int j = 1; j <= returned_bits_num; ++j) {
do {
int zero_count = 0;
int one_count = 0;
additional_input_length = 0;
ChaCha20_DRBG_Generate_function(state_handle, returned_bits_len, NULL,
&returned_bits);
for (int i = 0; i < returned_bits_len / 8; i++) {
int bits = returned_bits[i];
for (int j = 0; j < 8; j++) {
if (bits & 1)
one_count++;
else
zero_count++;
bits >>= 1;
}
}
const float expected_count = returned_bits_len / 2;
float chisq = (pow(zero_count - expected_count, 2) / expected_count) +
(pow(one_count - expected_count, 2) / expected_count);
if (chisq < 3.841)
pass = true;
else
pass = false;
} while (!pass);
// 将二进制数据转为十六进制后写入文件
for (int i = 0; i < returned_bits_len / 8; ++i) {
sprintf(&hex_str[i * 2], "%02x", returned_bits[i]);
}
hex_str[returned_bits_len / 8 * 2] = '\0';
fprintf(file, "%s\n", hex_str); // 写入带有换行符的十六进制字符串
}
free(hex_str);
clock_t end_time = clock();
double execution_time = (double)(end_time - start_time) / CLOCKS_PER_SEC;
printf("running time: %f s\n", execution_time);
fclose(file);
return 0;
}