说实话,作为一个工作了好几年的一个老程序员。我对 SecureRandom 了解的也不是很多,知道最近在读一个框架的源码时遇到了 SecureRandom 这个类。我一下子就被他吸引住了,SecureRandom 类提供加密的强随机数生成器。下面我们一起来学习它吧。
Random 类中实现的随机算法是伪随机,也就是有规则的随机。在进行随机时,随机算法的起源数字称为种子数(seed),在种子数的基础上进行一定的变换,从而产生需要的随机数字。相同种子数的 Random 对象,相同次数生成的随机数字是完全相同的。也就是说,两个种子数相同的 Random 对象,生成的随机数字完全相同。所以在需要频繁生成随机数,或者安全要求较高的时候,不要使用Random,因为其生成的值其实是可以预测的。
SecureRandom 和 Random 都是,也是如果种子一样,产生的随机数也一样: 因为种子确定,随机数算法也确定,因此输出是确定的。只是说,SecureRandom 类收集了一些随机事件,比如鼠标点击,键盘点击等等,SecureRandom 使用这些随机事件作为种子。这意味着,种子是不可预测的,而不像 Random 默认使用系统当前时间的毫秒数作为种子,有规律可寻。
SecureRandom 内置两种随机数算法,NativePRNG 和 SHA1PRNG。下面我们分别来学习它们。
通过 new 来初始化,默认来说会使用 NativePRNG 算法生成随机数,但是也可以配置 -Djava.security 参数来修改调用的算法,如果是 /dev/[u]random 两者之一就是 NativePRNG,否则就是 SHA1PRNG。在JVM启动时设置下面的参数,即可切换算法。
-Djava.security=file:/dev/urandom -Djava.security=file:/dev/random
上面两个设置一个即可,不要重复设置参数。
另外我们也可以通过 SecureRandom.getInstance 获取不同的算法。
SecureRandom secureRandom = new SecureRandom(); SecureRandom secureRandom3 = SecureRandom.getInstance("SHA1PRNG"); SecureRandom secureRandom2 = SecureRandom.getInstance("SHA1PRNG", "SUN");
SecureRandom 提供的一些方法和 Random 类似。通过 nextInt 即可获取随机数。
nextBytes(byte[] bytes) 可以获取随机的一个byte数组,注意这里不是返回,这个方法是void返回类型,是直接随机改变了 test。
SecureRandom random = new SecureRandom(); byte[] test = new byte[20]; random.nextBytes(test);
generateSeed(int numBytes) 方法可以获取一个随机的byte数组,这个数组中的数通常可以用来做其他随机生成器的种子。
byte seed[] = random.generateSeed(20);
产生高强度的随机数,有两个重要的因素:种子和算法。当然算法是可以有很多的,但是如何选择种子是非常关键的因素。
下面看一个简单的例子:
private List<List<Integer>> generateCakes(int num, int seedLength, int rowLen) { SecureRandom random = new SecureRandom(); byte[] seeds = SecureRandom.getSeed(seedLength); //获取随机的byte数组,用来后续作为种子 int counter = 0; int realCount = 0; int tmprows = 0; List<List<Integer>> CakesList = new ArrayList<List<Integer>>(); while (num > tmprows) { List<Integer> list = new ArrayList<Integer>(); while (counter < rowLen) { random.setSeed(seeds); //设置种子 int cake = random.nextInt(38); //随机生成0-37的数字 if (!list.contains(cake) && 0 != cake) { list.add(cake); counter++; } random.nextBytes(seeds); //随机获取新的byte数组用以作为下次的种子,不断循环 realCount++; } Collections.sort(list); pairs++; tmprows++; counter = 0; CakesList.add(list); if (pairs % Constants.MSG_COUNT == 0) { System.out.println(pairs + " cakes generated."); } } System.out.println("乱数取得回数:" + realCount); return CakesList; }
参考资料
- SecureRandom的江湖偏方与真实效果
- Java 随机数 Random VS SecureRandom
- Java中的随机数生成器:Random,ThreadLocalRandom,SecureRandom(转)
- Java中生成随机数Random、ThreadLocalRandom、SecureRandom
- API参考 SecureRandom(示例,出错代码)
: » SecureRandom 教程
原创文章,作者:Carrie001128,如若转载,请注明出处:https://blog.ytso.com/251721.html