[seed-labs] 伪随机数生成器
文章目录
实验目的
- 了解伪随机数生成算法及其相关概念
- 通过案例了解伪随机数生成过程中的漏洞
- 掌握安全生成伪随机数的方法
- 了解如何安全地生成加密密钥
实验过程
Task 1: 用错误的方式生成加密密钥
-
使用当前时间作为伪随机数生成器的种子
#include <stdio.h> #include <stdlib.h> #include <time.h> #define KEYSIZE 16 void main() { int i; char key[KEYSIZE]; printf("%lld\n", (long long) time(NULL)); srand (time(NULL)); //➀ for (i = 0; i< KEYSIZE; i++){ key[i] = rand()%256; printf("%.2x", (unsigned char)key[i]); } printf("\n"); }
-
结果
-
根据观察结果和查找资料我们可以得到:
- 代码中
srand()
函数通过time()
得到一个种子,在使用rand()
函数生成该随机数时是根据种子进行的,如果没有srand()函数则产生的随机数相同,即:time()
和srand(time())
是随机的rand()
是伪随机的srand(seed)
用于给rand()
设定种子
- 代码中
Task 2: 猜测密钥
-
首先分析加密密钥为该程序生成,那么该密钥一定与时间戳有关,我们先得到加密文件创建的前两个小时的所有秒数,
time()
的范围一定在计算机可测时间范围内,求出密钥空间根据第一题改变代码
#include <stdio.h> #include <stdlib.h> #include <time.h> #define KEYSIZE 16 void main() { int i; long long t; char key[KEYSIZE]; //printf("%lld\n", (long long) time(NULL)); //srand (time(NULL)); // for (t=1524013729;t<1524020929;t++){ srand(t); for(i=0;i<KEYSIZE;i++){ key[i] = rand()%256; printf("%.2x", (unsigned char)key[i]); } printf("\n"); } printf("\n"); }
-
密钥生成
from Crypto.Cipher import AES data = bytearray.fromhex('255044462d312e350a25d0d4c5d80a34') ciphertext = bytearray.fromhex('d06bf9d0dab8e8ef880660d2af65aa82') iv = bytearray.fromhex('09080706050403020100A2B2C2D2E2F2') with open('C:/Users/Laotie666/Desktop/key.txt') as f: keys = f.readlines() for k in keys: k = k.rstrip('\n') key = bytearray.fromhex(k) cipher = AES.new(key=key, mode=AES.MODE_CBC, iv=iv) guess = cipher.encrypt(data) if guess == ciphertext: print("the key is : ", k) break
Task 3: 测量内核的熵
-
测量kernel的熵
-
发现打开大文件然后写入时增加熵较快,大概一下+10左右,鼠标点击一下+5左右,当然这些也是大概估计,他的值一直是动态的非线性不可预测时间间隔下变化的
Task 4: 从 /dev/random 中获取伪随机数
- 从/dev/random中获取伪随机数。请运行给出的命令,同时使用watch命令来监测熵。
- 我发现如果不移动鼠标或者不输入内容,观测到的熵会逐渐的增加,每次增加1-2左右(频率也不固定),然后每两次增加到63时,随机数池会多生成一行;同时每次增加到63时,观测到的熵会从0开始
- 对于需要为client生成随机会话密钥的Server,可以对它的Server一直发起此类攻击,使得random pool的熵被耗尽,这样随机数的生成基本也就停止了,也就无法继续为Client服务了,成功发起了DDOS攻击。
Task 5: 从 /dev/urandom 获取随机数
-
Linux 提供了另一种方式,可以通过 /dev/urandom 设备访问随机池。
-
/dev/random 和 /dev/urandom 都可以使用随机池中的数据生成伪随机数。当熵不足时,/dev/random 将会暂停,而 /dev/urandom 会继续生成新的数。将随机池中的数据视作“种子”,我们可以使用种子想生成多少随机数就生成多少。
-
再次使用cat从设备中获取伪随机数
cat /dev/urandom | hexdump
答案是不会,会连续生成很多的随机数,完全够用
-
生成并测试质量
head -c 1M /dev/urandom > output.bin ent output.bin
结论是质量很高
-
下列代码实现使用/dev/random获取随机数
#include <stdio.h> #include <stdlib.h> #define LEN 32 // 32*8 bits int main(){ unsigned char * key = (unsigned char *)malloc(sizeof(unsigned char) * LEN); FILE * random = fopen("/dev/urandom", "r"); int i; fread(key, sizeof(unsigned char) * LEN, 1, random); fclose(random); printf("the key is : "); for (i=0; i<LEN; i++){ printf("%.2x", key[i]); } printf("\n"); return 0; }
篇外
- 5分钟看懂蒙特卡洛模拟 - 知乎
- https://seedsecuritylabs.org/Labs_20.04/Crypto/Crypto_Random_Number/
- 漏洞分析Pseudo Random Number Generation