应用安全系列之二十八:随机数
随机数产生器有两种:非确定性的随机数产生器和确定性的随机数产生器。
非确定性的随机数产生器(Non-deterministic Random Bit Generators),也称为真随机数产生器,简称NRBG,主要是利用物理熵源的随机数发生器,它的随机性是不可预测的,(熵源是一种产生完全不可预测的无序数据的比特源,而且各比特之间满足统计独立,例如:噪声源、热源、硬盘寻道时间、模数转换过程,等等)。
确定性的随机数产生器(Deterministic Random Bit Generators)也称为伪随机数产生器,简称DRBG,包括DRBG产生算法和一个熵源的输出作为输入,产生一个依赖于输入的确定的比特序列。目前广泛拥护各个平台和软件的API之中,例如,C、C++的rand、Java的random等,在指定初始种子之后,确定性随机数产生器产生一个确定的比特序列,因此称之为“确定性”。一般都是使用非确定性的随机数产生器产生种子,然后,再使用确定性的随机数产生器产生随机数。
实际上没有真正的随机性,伪随机数生成器 (PRNG) 近似于随机算法。在实际的编程过程中,大部分使用的都是伪随机数生成器 (PRNG)。PRNG 包括两种类型:统计学的 PRNG 和密码学的 PRNG。统计学的 PRNG 提供很多有用的统计属性,导致输出结果很容易预测,因此产生的随机数随机性就比较差。如果需要生成值不可预测的随机数,这种类型并不适用。密码学的 PRNG 生成的输出结果较难预测,可以很好地解决随机数的随机性问题。
各种语言都提供了不同的随机数产生接口,建议使用安全版本的随机数产生接口。例如,Java语言中的Math.random()和java.util.Random()是非常不好的伪随机数产生接口,java.security.SecureRandom()基于Linux虚拟文件/dev/urandom产生随机数,是比较安全的随机数产生接口。
例如,如下代码就是不安全的代码:
final static BASE = 100000;long generateRandomID() throws Exception{double rand = BASE * Math.random();while (rand < BASE / 10){rand = rand * 10;}return= Long.parseLong(Double.toString(rand).substring(0, 6));}
正确的代码如下:
final static BASE = 100000;static java.security.SecureRandom secureRandom =new java.security.SecureRandom ();long generateRandomID() throws Exception{double rand = BASE * secureRandom.nextDouble();while (rand < BASE / 10){rand = rand * 10;}return = Long.parseLong(Double.toString(rand).substring(0, 6));}
这里需要记住的是:使用SecureRandom 也不一定能够产生安全的随机数,需要注意如果使用不安全的随机数种子,还是会产生不安全的随机数,示例代码如下:
final static BASE = 100000;static java.security.SecureRandom secureRandom =new java.security.SecureRandom ();long generateRandomID() throws Exception{double rand = BASE * secureRandom.nextDouble();
secureRandom.setSeed(1000);while (rand < BASE / 10){rand = rand * 10;}return = Long.parseLong(Double.toString(rand).substring(0, 6));}
这里的代码调用了setSeed并且传递了一个常数,其实是画蛇添足,反而导致随机数不够随机了,正确的做法就是不要设置种子。
在实际的使用的时候,需要根据实际需要尽量选择安全的随机数产生器,特别是跟加密相关的地方,一定要使用安全的随机数生成器,否则,可能会影响加密内容的安全性。各种语言的随机数产生器罗列如下表,:
| 语言 | 不安全的随机数产生器 | 安全的随机数产生器 | 说明 |
| Java | Math.random | java.security.SecureRandom | |
| java.util.Random | |||
| C# | System.Random | System.Security.Cryptography.RNGCryptoServiceProvider | |
| C | rand() | randombytes_buf() | randombytes_buf是libsodium库提供的 |
| PHP | rand() | mt_rand() | |
| gmp_random_bits(int $bits): GMP | uniqid(string $prefix = "", bool $more_entropy = false): string | 建议设置more_entropy为true | |
| gmp_random_range() | random_bytes(int $length): string | ||
| gmp_random(int $limiter = 20): GMP | random_int(int $min, int $max): int | ||
| Python | rand() | os.urandom() | |
| random.randint | random.SystemRandom | ||
| secrets.token_bytes() | secrets模块需要Python3.6以及更高的版本 | ||
| secrets.token_hex() | |||
| secrets.SystemRandom | |||
| Objective C | rand() | arc4random() | Objective C可以直接使用C的函数 |
| random() | arc4random_uniform() | ||
| randomize() | |||
| Swift | sqlite3_randomness() | arc4random() | |
| drand48() | arc4random_buf() | ||
| JavaScript | Math.random | window.crypto. getRandomValues() | |
| Math.round | |||
| Ruby | rand() | SecureRandom.random_bytes() | |
| SecureRandom.hex() | |||
| SecureRandom.uuid() | |||
| SecureRandom.base64() |
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
