#include #include #include #include #include #include #include #include // #include #define SUCCESS 0 #define ERROR -1 // 为ChaCha20设置适当的长度。 #define KEYLEN 32 // ChaCha20的密钥长度(字节) #define COUNTERLEN 4 // ChaCha20的计数器长度(字节) #define NONCELEN 12 // ChaCha20的nonce长度(字节) #define OUTLEN 64 // 输出长度是64字节(512位) #define SEEDLEN 96 // KEYLEN + OUTLEN(字节) // for Instantiate #define MAX_PERSONALIZATION_STRING_LEN 800 // (字节) #define min_entropy_input_length 32 // (字节) #define max_entropy_input_length pow(2, 35) / 8 // (字节) // for handles #define MAX_STATES 100 #define INVALID_HANDLE -1 // for Get_entropy_input #define reseed_interval_in_counter pow(2, 10) // (次) #define reseed_interval_in_time 60 //(秒) #define MAX_NUMBER_OF_BITS 1024 // (比特) // for entropy #define BLOCK_SIZE 64 #define HASH_SIZE 32 /*----------------熵源的相关定义与函数----------------*/ typedef struct { uint8_t data[BLOCK_SIZE]; uint32_t datalen; uint64_t bitlen; uint32_t state[8]; } SHA256_CTX; 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); } /*----------------------------------------------*/ /*--------------------卡方检验相关定义与函数---------------------------*/ #define RANDOM_BITS_NUMBER 100 #define RANDOM_BITS_SIZE 128 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的相关定义与函数------------------*/ #define ROTL32(v, n) (((v) << (n)) | ((v) >> (32 - (n)))) #define U32TO8_LITTLE(p, v) \ { \ (p)[0] = (uint8_t)((v)); \ (p)[1] = (uint8_t)((v) >> 8); \ (p)[2] = (uint8_t)((v) >> 16); \ (p)[3] = (uint8_t)((v) >> 24); \ } #define U8TO32_LITTLE(p) \ (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \ ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)) // ChaCha的轮函数 #define QUARTERROUND(x, a, b, c, d) \ x[a] += x[b]; \ x[d] = ROTL32(x[d] ^ x[a], 16); \ x[c] += x[d]; \ x[b] = ROTL32(x[b] ^ x[c], 12); \ x[a] += x[b]; \ x[d] = ROTL32(x[d] ^ x[a], 8); \ x[c] += x[d]; \ x[b] = ROTL32(x[b] ^ x[c], 7); 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); 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); 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); 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) { int i = 0; for (i; 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; } 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); } 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; 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 = malloc(seed_material_size); uint8_t *requested_bits; time_t timep; int i = 0; 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); } 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 = 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); } 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[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 = 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[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[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("%d", &returned_bits_len); // returned_bits_len = 128; // 需要生成的比特串个数 printf("Enter the number of the bit string to be generated: "); scanf("%d", &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); // 生成的比特串保存在文本文件中 FILE *file = fopen(filename, "w"); if (file == NULL) { printf("无法打开文件\n"); return 1; } clock_t start_time = clock(); 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); // 将二进制数据转为十六进制后写入文件 char hex_str[returned_bits_len / 8 * 2 + 1]; 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); // 写入带有换行符的十六进制字符串 } 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; }