Koodi: Valitse kaikki
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <openssl/crypto.h> // OPENSSL_cleanse
#include <immintrin.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/file.h> // flock
#define BLOCK_SIZE 16 // AES-lohkon koko tavuina
#define CHUNK_BLOCKS 16384 // 16k * 16 = 262 144 B = 256 KB per erä
#define RESEED_INTERVAL (4096) // 4096 * 256 KB = 1 048 576 KB = 1 GB
#define SEED_SIZE 32 // 256-bittinen siemen
#define SALT_SIZE 64 // 512-bittinen suola
#define RDSEED_TIMEOUT_NS 10000000000 // 10 s aikaraja RDSEED:lle per 64 bittiä
#define LOG_FILE "aes_ctr_drbg.log" // Lokitiedoston nimi
static volatile sig_atomic_t keep_running = 1;
static EVP_CIPHER_CTX *global_ctx = NULL;
static FILE *log_file = NULL;
// Lokitusfunktio virheille (kirjoittaa lokiin ja stderr:iin)
void log_message(const char *message) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
char timestamp[32];
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", localtime(&ts.tv_sec));
flock(fileno(log_file), LOCK_EX);
fprintf(log_file, "[%s.%03ld] %s\n", timestamp, ts.tv_nsec / 1000000, message);
fprintf(stderr, "[%s.%03ld] %s\n", timestamp, ts.tv_nsec / 1000000, message);
fflush(log_file);
flock(fileno(log_file), LOCK_UN);
}
// Lokitusfunktio tapahtumille (kirjoittaa vain lokiin)
void log_event(const char *message) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
char timestamp[32];
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", localtime(&ts.tv_sec));
flock(fileno(log_file), LOCK_EX);
fprintf(log_file, "[%s.%03ld] %s\n", timestamp, ts.tv_nsec / 1000000, message);
fflush(log_file);
flock(fileno(log_file), LOCK_UN);
}
// Signaalinkäsittelijä Ctrl+C:lle
void handle_sigint(int sig) {
(void)sig;
keep_running = 0;
}
// Generoi 64-bittinen satunnaisluku RDSEED:llä
int get_random_64(unsigned long long *val) {
struct timespec start, now;
clock_gettime(CLOCK_REALTIME, &start);
while (1) {
if (_rdseed64_step(val) == 1) {
return 1;
}
clock_gettime(CLOCK_REALTIME, &now);
long elapsed_ns = (now.tv_sec - start.tv_sec) * 1000000000L + (now.tv_nsec - start.tv_nsec);
if (elapsed_ns > RDSEED_TIMEOUT_NS) {
log_message("RDSEED timeout exceeded");
return 0;
}
nanosleep(&(struct timespec){.tv_nsec = 1000000}, NULL); // 1 ms tauko
}
}
// Generoi 256-bittinen siemen ja 512-bittinen suola RDSEED:llä
int generate_seed_and_salt(uint8_t *seed, uint8_t *salt) {
for (int i = 0; i < SEED_SIZE / sizeof(unsigned long long); i++) {
unsigned long long val;
if (!get_random_64(&val)) {
log_message("Failed to generate seed");
return 0;
}
memcpy(seed + i * sizeof(unsigned long long), &val, sizeof(unsigned long long));
}
for (int i = 0; i < SALT_SIZE / sizeof(unsigned long long); i++) {
unsigned long long val;
if (!get_random_64(&val)) {
log_message("Failed to generate salt");
return 0;
}
memcpy(salt + i * sizeof(unsigned long long), &val, sizeof(unsigned long long));
}
return 1;
}
// Aseta uusi siemen ja alusta laskuri
int reseed(EVP_CIPHER_CTX *ctx, uint8_t *iv) {
uint8_t seed[SEED_SIZE];
uint8_t salt[SALT_SIZE];
uint8_t key[SEED_SIZE];
int ret = 0;
if (!generate_seed_and_salt(seed, salt)) {
goto cleanup;
}
EVP_KDF *kdf = EVP_KDF_fetch(NULL, "HKDF", NULL);
if (!kdf) {
log_message("EVP_KDF_fetch failed");
goto cleanup;
}
EVP_KDF_CTX *kdf_ctx = EVP_KDF_CTX_new(kdf);
EVP_KDF_free(kdf);
if (!kdf_ctx) {
log_message("EVP_KDF_CTX_new failed");
goto cleanup;
}
OSSL_PARAM params = {
OSSL_PARAM_construct_utf8_string("digest", "SHA3-512", 0),
OSSL_PARAM_construct_octet_string("salt", salt, SALT_SIZE),
OSSL_PARAM_construct_octet_string("key", seed, SEED_SIZE),
OSSL_PARAM_construct_end()
};
if (EVP_KDF_derive(kdf_ctx, key, SEED_SIZE, params) != 1) {
log_message("EVP_KDF_derive failed");
EVP_KDF_CTX_free(kdf_ctx);
goto cleanup;
}
EVP_KDF_CTX_free(kdf_ctx);
memset(iv, 0, BLOCK_SIZE);
if (EVP_CIPHER_CTX_reset(ctx) != 1) {
log_message("EVP_CIPHER_CTX_reset failed");
goto cleanup;
}
if (EVP_EncryptInit_ex2(ctx, EVP_aes_256_ctr(), key, iv, NULL) != 1) {
log_message("EVP_EncryptInit_ex2 failed");
goto cleanup;
}
ret = 1;
cleanup:
OPENSSL_cleanse(seed, SEED_SIZE);
OPENSSL_cleanse(salt, SALT_SIZE);
OPENSSL_cleanse(key, SEED_SIZE);
return ret;
}
int main() {
signal(SIGPIPE, SIG_IGN);
log_file = fopen(LOG_FILE, "a");
if (!log_file) {
fprintf(stderr, "Failed to open log file " LOG_FILE "\n");
return 1;
}
log_event("Program started");
signal(SIGINT, handle_sigint);
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
log_message("EVP_CIPHER_CTX_new failed");
fclose(log_file);
return 1;
}
global_ctx = ctx;
uint8_t iv[BLOCK_SIZE] = {0};
uint8_t buffer[CHUNK_BLOCKS * BLOCK_SIZE]; // 256 KB
uint8_t zero_buffer[CHUNK_BLOCKS * BLOCK_SIZE] = {0}; // 256 KB nollapuskuri
uint64_t chunk_counter = 0;
if (!reseed(ctx, iv)) {
EVP_CIPHER_CTX_free(ctx);
fclose(log_file);
return 1;
}
// Main loop: Generate random data in 256 KB chunks using AES-256-CTR,
// reseed every 1 GB, and write to stdout until interrupted or pipe closes.
while (keep_running) {
int outlen;
if (EVP_EncryptUpdate(ctx, buffer, &outlen, zero_buffer, CHUNK_BLOCKS * BLOCK_SIZE) != 1) {
log_message("EVP_EncryptUpdate failed");
EVP_CIPHER_CTX_free(ctx);
fclose(log_file);
return 1;
}
if (outlen != CHUNK_BLOCKS * BLOCK_SIZE) {
log_message("Unexpected output length");
EVP_CIPHER_CTX_free(ctx);
fclose(log_file);
return 1;
}
if (fwrite(buffer, 1, outlen, stdout) != (size_t)outlen) {
if (errno == EPIPE) {
log_event("Output pipe closed, shutting down");
keep_running = 0;
} else {
log_message("fwrite failed");
EVP_CIPHER_CTX_free(ctx);
fclose(log_file);
return 1;
}
} else {
fflush(stdout);
chunk_counter++;
if (chunk_counter % RESEED_INTERVAL == 0) {
if (!reseed(ctx, iv)) {
EVP_CIPHER_CTX_free(ctx);
fclose(log_file);
return 1;
}
char msg[64];
uint64_t gb_generated = chunk_counter / RESEED_INTERVAL; // Kokonaisluku GB
snprintf(msg, sizeof(msg), "Reseeded after %ld GB", gb_generated);
log_event(msg);
}
}
}
char msg[64];
uint64_t gb_generated = chunk_counter * CHUNK_BLOCKS * BLOCK_SIZE / (1024LL * 1024 * 1024);
snprintf(msg, sizeof(msg), "Total data generated: %ld GB", gb_generated);
log_event(msg);
EVP_CIPHER_CTX_free(ctx);
log_event("Program terminated");
fclose(log_file);
global_ctx = NULL;
return 0;
}
Koodi: Valitse kaikki
./aes_ctr_drbg_new | dieharder -a -g 200
#=============================================================================#
# dieharder version 3.31.1 Copyright 2003 Robert G. Brown #
#=============================================================================#
rng_name |rands/second| Seed |
stdin_input_raw| 5.97e+07 |1115297810|
#=============================================================================#
test_name |ntup| tsamples |psamples| p-value |Assessment
#=============================================================================#
diehard_birthdays| 0| 100| 100|0.43543630| PASSED
diehard_operm5| 0| 1000000| 100|0.78361743| PASSED
diehard_rank_32x32| 0| 40000| 100|0.31692885| PASSED
diehard_rank_6x8| 0| 100000| 100|0.99171666| PASSED
diehard_bitstream| 0| 2097152| 100|0.72565079| PASSED
diehard_opso| 0| 2097152| 100|0.99991762| WEAK
diehard_oqso| 0| 2097152| 100|0.04022020| PASSED
diehard_dna| 0| 2097152| 100|0.64703788| PASSED
diehard_count_1s_str| 0| 256000| 100|0.71883437| PASSED
diehard_count_1s_byt| 0| 256000| 100|0.86836429| PASSED
diehard_parking_lot| 0| 12000| 100|0.79252967| PASSED
diehard_2dsphere| 2| 8000| 100|0.49861982| PASSED
diehard_3dsphere| 3| 4000| 100|0.29861975| PASSED
diehard_squeeze| 0| 100000| 100|0.11465672| PASSED
diehard_sums| 0| 100| 100|0.06486198| PASSED
diehard_runs| 0| 100000| 100|0.35574496| PASSED
diehard_runs| 0| 100000| 100|0.32528130| PASSED
diehard_craps| 0| 200000| 100|0.18823885| PASSED
diehard_craps| 0| 200000| 100|0.52891535| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.96210375| PASSED
marsaglia_tsang_gcd| 0| 10000000| 100|0.25112654| PASSED
sts_monobit| 1| 100000| 100|0.98529115| PASSED
sts_runs| 2| 100000| 100|0.62428014| PASSED
sts_serial| 1| 100000| 100|0.91093142| PASSED
sts_serial| 2| 100000| 100|0.69339930| PASSED
sts_serial| 3| 100000| 100|0.20406129| PASSED
sts_serial| 3| 100000| 100|0.01815481| PASSED
sts_serial| 4| 100000| 100|0.02411009| PASSED
sts_serial| 4| 100000| 100|0.06759275| PASSED
sts_serial| 5| 100000| 100|0.05452092| PASSED
sts_serial| 5| 100000| 100|0.16006190| PASSED
sts_serial| 6| 100000| 100|0.01524816| PASSED
sts_serial| 6| 100000| 100|0.41673603| PASSED
sts_serial| 7| 100000| 100|0.55377725| PASSED
sts_serial| 7| 100000| 100|0.89397256| PASSED
sts_serial| 8| 100000| 100|0.16507489| PASSED
sts_serial| 8| 100000| 100|0.59537615| PASSED
sts_serial| 9| 100000| 100|0.67552873| PASSED
sts_serial| 9| 100000| 100|0.26031571| PASSED
sts_serial| 10| 100000| 100|0.99999975| FAILED
sts_serial| 10| 100000| 100|0.56633487| PASSED
sts_serial| 11| 100000| 100|0.81544127| PASSED
sts_serial| 11| 100000| 100|0.54121691| PASSED
sts_serial| 12| 100000| 100|0.90719346| PASSED
sts_serial| 12| 100000| 100|0.53679143| PASSED
sts_serial| 13| 100000| 100|0.93000961| PASSED
sts_serial| 13| 100000| 100|0.49730862| PASSED
sts_serial| 14| 100000| 100|0.18158707| PASSED
sts_serial| 14| 100000| 100|0.52665864| PASSED
sts_serial| 15| 100000| 100|0.71076563| PASSED
sts_serial| 15| 100000| 100|0.29000691| PASSED
sts_serial| 16| 100000| 100|0.89369003| PASSED
sts_serial| 16| 100000| 100|0.97384299| PASSED
rgb_bitdist| 1| 100000| 100|0.63346740| PASSED
rgb_bitdist| 2| 100000| 100|0.53480556| PASSED
rgb_bitdist| 3| 100000| 100|0.05411541| PASSED
rgb_bitdist| 4| 100000| 100|0.65614719| PASSED
rgb_bitdist| 5| 100000| 100|0.47350279| PASSED
rgb_bitdist| 6| 100000| 100|0.12222463| PASSED
rgb_bitdist| 7| 100000| 100|0.53464355| PASSED
rgb_bitdist| 8| 100000| 100|0.13057620| PASSED
rgb_bitdist| 9| 100000| 100|0.43533794| PASSED
rgb_bitdist| 10| 100000| 100|0.39422938| PASSED
rgb_bitdist| 11| 100000| 100|0.91978077| PASSED
rgb_bitdist| 12| 100000| 100|0.21919621| PASSED
rgb_minimum_distance| 2| 10000| 1000|0.08090195| PASSED
rgb_minimum_distance| 3| 10000| 1000|0.02079021| PASSED
rgb_minimum_distance| 4| 10000| 1000|0.29876387| PASSED
rgb_minimum_distance| 5| 10000| 1000|0.46438021| PASSED
rgb_permutations| 2| 100000| 100|0.87353070| PASSED
rgb_permutations| 3| 100000| 100|0.52552605| PASSED
rgb_permutations| 4| 100000| 100|0.91774575| PASSED
rgb_permutations| 5| 100000| 100|0.86219339| PASSED
rgb_lagged_sum| 0| 1000000| 100|0.97810078| PASSED
rgb_lagged_sum| 1| 1000000| 100|0.36232370| PASSED
rgb_lagged_sum| 2| 1000000| 100|0.28509842| PASSED
rgb_lagged_sum| 3| 1000000| 100|0.91208516| PASSED
rgb_lagged_sum| 4| 1000000| 100|0.12288336| PASSED
rgb_lagged_sum| 5| 1000000| 100|0.66442364| PASSED
rgb_lagged_sum| 6| 1000000| 100|0.64970350| PASSED
rgb_lagged_sum| 7| 1000000| 100|0.48952773| PASSED
rgb_lagged_sum| 8| 1000000| 100|0.88901015| PASSED
rgb_lagged_sum| 9| 1000000| 100|0.48118278| PASSED
rgb_lagged_sum| 10| 1000000| 100|0.69794978| PASSED
rgb_lagged_sum| 11| 1000000| 100|0.10677097| PASSED
rgb_lagged_sum| 12| 1000000| 100|0.72159961| PASSED
rgb_lagged_sum| 13| 1000000| 100|0.63723486| PASSED
rgb_lagged_sum| 14| 1000000| 100|0.31263455| PASSED
rgb_lagged_sum| 15| 1000000| 100|0.76732644| PASSED
rgb_lagged_sum| 16| 1000000| 100|0.25360204| PASSED
rgb_lagged_sum| 17| 1000000| 100|0.91180734| PASSED
rgb_lagged_sum| 18| 1000000| 100|0.98559464| PASSED
rgb_lagged_sum| 19| 1000000| 100|0.82360676| PASSED
rgb_lagged_sum| 20| 1000000| 100|0.05047740| PASSED
rgb_lagged_sum| 21| 1000000| 100|0.52650681| PASSED
rgb_lagged_sum| 22| 1000000| 100|0.44660144| PASSED
rgb_lagged_sum| 23| 1000000| 100|0.66982129| PASSED
rgb_lagged_sum| 24| 1000000| 100|0.46483777| PASSED
rgb_lagged_sum| 25| 1000000| 100|0.51657381| PASSED
rgb_lagged_sum| 26| 1000000| 100|0.04200830| PASSED
rgb_lagged_sum| 27| 1000000| 100|0.67524992| PASSED
rgb_lagged_sum| 28| 1000000| 100|0.95076360| PASSED
rgb_lagged_sum| 29| 1000000| 100|0.65131173| PASSED
rgb_lagged_sum| 30| 1000000| 100|0.23827590| PASSED
rgb_lagged_sum| 31| 1000000| 100|0.29841371| PASSED
rgb_lagged_sum| 32| 1000000| 100|0.79204731| PASSED
rgb_kstest_test| 0| 10000| 1000|0.67597377| PASSED
dab_bytedistrib| 0| 51200000| 1|0.82307693| PASSED
dab_dct| 256| 50000| 1|0.12245871| PASSED
Preparing to run test 207. ntuple = 0
dab_filltree| 32| 15000000| 1|0.86454674| PASSED
dab_filltree| 32| 15000000| 1|0.15622413| PASSED
Preparing to run test 208. ntuple = 0
dab_filltree2| 0| 5000000| 1|0.47355166| PASSED
dab_filltree2| 1| 5000000| 1|0.25204152| PASSED
Preparing to run test 209. ntuple = 0
dab_monobit2| 12| 65000000| 1|0.64480429| PASSED