2.2 随机数
首先介绍密码学中看似很简单,但是很难正确使用的算法,这就是随机数生成算法。在密码学中随机数的用途非常大,其他密码学算法内部都会用到随机数。
对于随机数,读者都有一些印象,网络上有很多随机数生成小工具。从开发者直观的角度看,随机数就是一串杂乱无序的字母、数字、符号组合,但这不是真正的随机数,更不能用在密码学中,为了理解随机数的本质,先介绍随机数的类型。
2.2.1 随机数的类型
通过表2-1可以看出,不同类型的随机数具备不同的特性,理解这些特性非常重要。
表2-1 随机数类型
1)效率
在软件或者密码学应用中需要大量的随机数,必须在很短的时间内生成随机数,否则就不是一个好的随机数生成器。
2)随机性
生成的随机数只要不存在统计学偏差,那么这个随机数就具备随机性(randomness),比如随机数生成器从0到9几个数字中随机选出四个数字,在生成的随机数中,0到9数字出现的次数是平均的,代表该随机数生成器具备随机性。
3)不可预测性
有些随机数看上去很随机,但是这些随机数之间可能存在一定的关联,比如通过以前的随机数可以推断出后续的随机数,这种随机数就具备不可预测性(unpredictable)。密码学中的随机数必须具备不可预测性,否则就会存在安全问题,当然非密码学应用使用具备随机性的随机数就足够了。
4)不可重现性
所谓不可重现性(unrepeat)就是不管经过多长时间,不会产生完全相同的随机数。在软件层面不可能生成完全不一样的随机数,在一定周期内,密码学随机数算法最终会生成两个完全相同的随机数,只是周期长短的问题。
在密码学中应该尽量使用周期相对长的随机数,为了实现真正不可重现性的随机数,必须基于物理设备或者物理现象。
2.2.2 随机数的工作原理
不管是真正的随机数生成器TRNG(True Random Number Generator),伪随机数生成器PRNG(Preudo Random Number Generator),还是密码学伪随机数生成器CPRNG(Cryptography secure Preudo Random Number Generator),内部工作原理是一样的,CPRNG是PRNG随机数生成器中的一种。
随机数生成器内部会维护一个状态(internal state),对于TRNG来说,内部状态的数值来自外部设备,称为熵(entrory),比如动态的时间、变化的温度、声音的变化、鼠标位置。
而对于PRNG来说,内部状态的数值来自于模拟的数值,称为种子(seed)。随机数生成器每次生成随机数的时候,内部状态的值都会变化,这样才能产生不一样的随机数,如果每次熵和种子是一样的,生成的随机数也是相同的,所以熵和种子对于随机数生成器非常重要。
一个优秀的随机数生成器就在于寻找尽可能多的熵和种子,一旦熵和种子不够,随机数生成器就会停止运行。
2.2.3 常见的随机数生成器
1)使用外部熵生成随机数
$ head -c 32 /dev/urandom | openssl enc -base64
2)伪随机数生成器算法
如果生成的随机数不是用于密码学,开发者可以自行设计一个生成算法,常见算法如表2-2所示。
表2-2 常见生成算法
大部分开发语言都有类库提供伪随机数生成算法,比如PHP语言可以通过下面的代码产生伪随机数:
//初始化种子 mt_srand(); $randval = mt_rand(); echo $randval;
OpenSSL命令行工具也能提供伪随机数,比如:
$ openssl rand -base64 24
3)密码学随机数生成算法
在密码学中,可以通过其他密码学算法生成密码学可以使用的随机数,比如表2-3中的算法。
表2-3 密码学伪随机数生成算法
2.2.4 密码学算法中的随机数
密码学应用中很多场景会涉及随机数,不同的用途有不同的称呼,常见用途见表2-4。
表2-4 随机数常见用途
目前读者不用关心这些概念,后续章节会讲解,在不同的算法中,随机数的称呼也有差异。