Bạn có thể buộc FIPS ANSI X9.31 RNG vào chế độ thử nghiệm khi chạy, nhưng không phải là SSLNG RNG (mặc định). Nếu bạn biên dịch lại OpenSSL với -DPREDICT
, RNG mặc định sẽ xuất ra một chuỗi số có thể dự đoán được, nhưng điều đó không thuận tiện lắm.
Chức năng RAND_pseudo_bytes
tạo chuỗi số có thể dự đoán được, có nghĩa là nó không thêm entropy vào chính nó tự động như RAND_bytes
. Nhưng giống như bạn nhận thấy nó chỉ có thể thêm entropy vào hạt giống, không cung cấp hạt giống một cách rõ ràng, vì vậy giữa các lần chạy chương trình bạn sẽ nhận được các số khác nhau. Cũng không hữu ích.
Nhưng viết động cơ RNG có thể dự đoán của riêng bạn thì không khó. Trong thực tế, tôi sẽ đưa bạn qua nó bằng cách làm cho một động cơ rand với stdlib của rand()
tại cốt lõi của nó:
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <openssl/rand.h>
// These don't need to do anything if you don't have anything for them to do.
static void stdlib_rand_cleanup() {}
static void stdlib_rand_add(const void *buf, int num, double add_entropy) {}
static int stdlib_rand_status() { return 1; }
// Seed the RNG. srand() takes an unsigned int, so we just use the first
// sizeof(unsigned int) bytes in the buffer to seed the RNG.
static void stdlib_rand_seed(const void *buf, int num)
{
assert(num >= sizeof(unsigned int));
srand(*((unsigned int *) buf));
}
// Fill the buffer with random bytes. For each byte in the buffer, we generate
// a random number and clamp it to the range of a byte, 0-255.
static int stdlib_rand_bytes(unsigned char *buf, int num)
{
for(int index = 0; index < num; ++index)
{
buf[index] = rand() % 256;
}
return 1;
}
// Create the table that will link OpenSSL's rand API to our functions.
RAND_METHOD stdlib_rand_meth = {
stdlib_rand_seed,
stdlib_rand_bytes,
stdlib_rand_cleanup,
stdlib_rand_add,
stdlib_rand_bytes,
stdlib_rand_status
};
// This is a public-scope accessor method for our table.
RAND_METHOD *RAND_stdlib() { return &stdlib_rand_meth; }
int main()
{
// If we're in test mode, tell OpenSSL to use our special RNG. If we
// don't call this function, OpenSSL uses the SSLeay RNG.
int test_mode = 1;
if(test_mode)
{
RAND_set_rand_method(RAND_stdlib());
}
unsigned int seed = 0x00beef00;
unsigned int rnum[5];
RAND_seed(&seed, sizeof(seed));
RAND_bytes((unsigned char *)&rnum[0], sizeof(rnum));
printf("%u %u %u %u %u\n", rnum[0], rnum[1], rnum[2], rnum[3], rnum[4]);
return 0;
}
Mỗi khi bạn chạy chương trình này, nó giống srand()
với cùng số lượng và do đó cung cấp cho bạn cùng một chuỗi số ngẫu nhiên mỗi lần.
corruptor:scratch indiv$ g++ rand.cpp -o r -lcrypto -g
corruptor:scratch indiv$ ./r
1547399009 981369121 2368920148 925292993 788088604
corruptor:scratch indiv$ ./r
1547399009 981369121 2368920148 925292993 788088604
corruptor:scratch indiv$
Bạn không cần PRNG. Bạn chỉ cần một luồng giá trị dự đoán được; ngay cả một quầy sẽ làm. –