在编写代码时,一般会使用伪随机函数,不过对于安全通讯往往存在风险,Linux 提供了随机生成设备,可以提供基本满足真随机内容。
这里介绍常见的使用技巧。
简介
在 Linux 的 /dev/
目录下存在两个相关的随机数发生器 random
和 urandom
,后者也就是 unblocked random
,两个特殊的设备文件中产生,会利用系统熵池计算出一定数量的随机比特,然后将这些比特作为字节流返回。
熵池就是当前系统的环境噪音,可以通过很多参数来评估,如内存、文件的使用、不同类型的进程数量等等。
两者区别
如果当前环境噪音变化的不是很剧烈或者当前环境噪音很小,比如刚开机的时候,而当前需要大量的随机比特,这时产生的随机数的随机效果就不是很好了。
这也就是上述两个文件的区别,前者不能产生新的随机数时会阻塞,直到根据熵池产生新的随机字节之后才返回;而后者不会阻塞,只是此时产生的可能是伪随机数,对加密解密这样的应用来说就不是一种很好的选择。
所以使用 /dev/random
比使用 /dev/urandom
产生大量随机数的速度要慢。
$ dd if=/dev/random of=random.dat bs=1024b count=1
0+1 records in
0+1 records out
128 bytes (128 B) copied, 0.000169 seconds, 757 kB/s
$ dd if=/dev/urandom of=random.dat bs=1024b count=1
1+0 records in
1+0 records out
524288 bytes (524 kB) copied, 0.091297 seconds, 5.7 MB/s
相比来说,前者在内核中熵不足时会阻塞,而后者则不会,详细可以查看 Myths about /dev/urandom 。
常用命令
可以通过命令行直接读取字符串的内容,从而生成随机的字符串,如下的命令中,其中 C
表示生成的字符串的字符数,L
表示要生成多少行随机字符。
----- 生成全字符随机的字串
$ cat /dev/urandom | strings -n C | head -n L
----- 生成数字加字母的随机字串
$ cat /dev/urandom | sed 's/[^a-zA-Z0-9]//g' | strings -n C | head -n L
----- 也可以直接通过Base64转换
$ head -c 32 /dev/random | base64
注意,如上的方式中会存在换行符,只有在出现长度是 C
的字符串时才打印,会导致打印速度很慢;所以,最好是通过如下方式生成,然后手动截取。
$ cat /dev/urandom | sed 's/[^a-zA-Z0-9]//g' | strings | tr -d '\n\r'
如果要生成随机整数,可以通过 shell 中的一个环境变量 RANDOM
,它的范围是 0~32767
。
----- 生成 [0, 25] 的随机数
$ echo $(($RANDOM%26))
----- 生成 [6, 100] 的随机数
$ echo $(($RANDOM%95+6))
参考
- Myths about /dev/urandom 详细的原理介绍。