在Windows上,我在C语言中使用CryptGenRandom
API(我认为这等效于Linux上的/dev/random
或/dev/urandom
)。为了确认这一点,我在Windows上使用CryptGenRandom
制作了随机文件,在Linux上从/dev/urandom
读取了文件,然后使用ent
分析了结果。
我曾经使用CryptGenRandom
(最初来自here)生成随机文件的代码示例:
#include <windows.h>
static void
secure_entropy(void *buf, size_t len)
{
HCRYPTPROV h = 0;
DWORD type = PROV_RSA_FULL;
DWORD flags = CRYPT_VERIFYCONTEXT | CRYPT_SILENT;
if (!CryptAcquireContext(&h, 0, 0, type, flags) ||
!CryptGenRandom(h, len, buf)) {
printf("failed to gather entropy");
abort();
}
CryptReleaseContext(h, 0);
}
void test4()
{
size_t size = 1 << 20;
FILE *tfile = fopen("random_file", "w");
char *buf = malloc(size);
secure_entropy(buf, size);
fwrite(buf, 1, size, tfile);
fclose(tfile);
free(buf);
}
但是,ent
向我展示了随机结果的算术平均值约为127.05,而不是127.5(在Linux上是)。我有信心这不是偶然的事情,因为我在不同的计算机上多次复制它,并且结果是一致的。为了进一步研究它,我编写了一个python脚本来分析每个数字的频率(从0到255)。
f = open("random_file", "rb")
a = f.read()
f.close()
tmp = [0 for _ in range(256)]
for x in a:
tmp[int(x)] += 1
print(tmp)
结果看起来像这样:
[4101, 4026, 4027, 4074, 4200, 4021, 4121, 4066, 4035, 3972, 4127, 4010,
3978, 8214, 4009, 4155, 4083, 4065, 4067, 4064, 3993, 4021, 4136, 4112, 4221,
4172, 4134, 4117, 3972, 4127, 4175, 4110, 4125, 4181, 4092, 4157, 4122, 4024,
4020, 4088, 3980, 4140, 4159, 4129, 4064, 4141, 4096, 4238, 4036, 4080, 4151,
4115, 4086, 4156, 4111, 4106, 4086, 4058, 4179, 4193, 4144, 4206, 4180, 4028,
4148, 4015, 3979, 4201, 4098, 4146, 4169, 4120, 4044, 4066, 4049, 4051, 4051,
4122, 4048, 4139, 4125, 4052, 4224, 4091, 4084, 4040, 4183, 4134, 3948, 4132,
3955, 4162, 4183, 4014, 4100, 4091, 4005, 4146, 4182, 4032, 4037, 3985, 4098,
4078, 4147, 4060, 4085, 4215, 4039, 4187, 4207, 4161, 4086, 4159, 4018, 4073,
4051, 4008, 4095, 4110, 4160, 4288, 4077, 4074, 4113, 4104, 4097, 4115, 4049,
3963, 4083, 4111, 4066, 4084, 4107, 4035, 3977, 4078, 4035, 4008, 3993, 4080,
4152, 4121, 4111, 4033, 4094, 4191, 4131, 3978, 4082, 4134, 4119, 4135, 4071,
3993, 3888, 4137, 4188, 4110, 4078, 4186, 4188, 4074, 4196, 4110, 4069, 4135,
4043, 4150, 4023, 4095, 4074, 4179, 4112, 4084, 4124, 4180, 4154, 3996, 4103,
4199, 4137, 4155, 4039, 4077, 4159, 4167, 4171, 4115, 4025, 4218, 4046, 4008,
4178, 3969, 4135, 4077, 4044, 4080, 4085, 4230, 4161, 4151, 4056, 4222, 4033,
4020, 4187, 4034, 4175, 4167, 3962, 4102, 4054, 3978, 4111, 4001, 4028, 4103,
4088, 4054, 4049, 4164, 4136, 4110, 4181, 3964, 4098, 4046, 3997, 4151, 4122,
4272, 4067, 4112, 4037, 4083, 4072, 4106, 4105, 4104, 4166, 4090, 4071, 4080,
4070, 4087, 4162, 4060, 4237, 4061, 4044, 4128, 4051, 4097]
很明显,第13个数字(第14个数字)的出现概率是所有其他数字的两倍,这也可以解释127.05的算术平均值。
我不确定这是CryptGenRandom
的错误还是执行不正确,但是我已经在64位Windows 10和32位Windows 7计算机上对其进行了测试,并且结果一致。那么有人有什么想法或可以帮助进一步调查和确认吗?
答案 0 :(得分:6)
FILE *tfile = fopen("random_file", "w");
您正在以文本模式打开文件,并且每个字符分别写入约4000次。包括'\r'
和'\n'
个字符。
每次编写'\n'
时,程序都会插入一个额外的'\r'
,因此大约有8000个'\r'
字符,其ASCII值为13
在Windows中,您应以二进制模式fopen("random_file", "wb")
打开非文本文件的文件。