java中的SecureRandom在linux中的实现

http://blog.csdn.net/raintungli/article/details/42876073

在安全系统中,通常我们会使用securerandom去更安全的生成随机数,而默认的SecureRandom里使用的算法是SHA1PRNG。

 

Linux中的随机数发生器

在Linux操作系统中,有一个特殊的设备文件,可以用作随机数发生器或伪随机数发生器。

/dev/random

在读取时,/dev/random设备会返回小于熵池噪声总数的随机字节。/dev/random可生成高随机性的公钥或一次性密码本。若熵池空了,对/dev/random的读操作将会被阻塞,直到从别的设备中收集到了足够的环境噪声为止。

当然你也可以设置成不堵塞,当你在open 的时候设置参数O_NONBLOCK, 但是当你read的时候,如果熵池空了,会返回-1

/dev/urandom

/dev/random的一个副本是/dev/urandom ("unlocked",非阻塞的随机数发生器[4]),它会重复使用熵池中的数据以产生伪随机数据。这表示对/dev/urandom的读取操作不会产生阻塞,但其输出的熵可能小于/dev/random的。它可以作为生成较低强度密码的伪随机数生成器,不建议用于生成高强度长期密码。


Linux下设置随机数

/proc/sys/kernel/random

在此目录下,可以配置/dev/random的参数

Poolsize

The file poolsize gives the size of the entropy pool

Read-wakeup_threadhold

The file read_wakeup_threshold contains the number of bits ofentropy required for waking up processes that sleep waiting for entropy from /dev/random.  The default is 64. 

write_wakeup_threshold

The filewrite_wakeup_threshold contains the number of bits of entropy below which wewake up processes that do a select(2) or poll(2) for write access to /dev/random.


在JAVA中的配置发生器

在JAVA中可以通过两种方式去设置指定的随机数发生器

1.      -Djava.security.egd=file:/dev/random或者 -Djava.security.egd=file:/dev/urandom

2.      修改配置文件java.security 在jvm_home\jre\lib\security

参数securerandom.source=file:/dev/urandom

/dev/random 是堵塞的,在读取随机数的时候,当熵池值为空的时候会堵塞影响性能,尤其是系统大并发的生成随机数的时候,如果在随机数要求不高的情况下,可以去读取/dev/urandom

整个流程如下:

JAVA中首先读取系统参数java.security.egd,如果值为空的时候,读取java.security配置文件中的参数securerandom.source, 在通常情况下,就是读取参数securerandom.source,默认值是/dev/urandom,也就是因该是不堵塞的。

但实际情况是,在测试linux环境下的时候,你会发现默认值却是堵塞的。

查看代码sun.security.provider.SeedGenerator.java

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (egdSource.equals(URL_DEV_RANDOM) || egdSource.equals(URL_DEV_URANDOM)){    
  2.             try {    
  3.                 instance = new NativeSeedGenerator();    
  4.                 if (debug != null) {    
  5.                   debug.println("the instance:"+instance.getClass());    
  6.                     debug.println("Using operating system seed generator");    
  7.                 }    
  8.             } catch (IOException e) {    
  9.                 if (debug != null) {    
  10.                     debug.println("Failed to use operating system seed "    
  11.                                   + "generator: "+ e.toString());    
  12.                 }    
  13.             }    
  14.         }    
  15. else if (egdSource.length() != 0) {    
  16.             try {    
  17.                 instance = new URLSeedGenerator(egdSource);    
  18.                 if (debug != null) {    
  19.                     debug.println("Using URL seed generator reading from "    
  20.                                   + egdSource);    
  21.                 }    
  22.             } catch (IOException e) {    
  23.                 if (debug != null)    
  24.                     debug.println("Failed to create seed generator with "    
  25.                                   + egdSource + ": " + e.toString());    
  26.             }    
  27.         }    

在代码中可以看到当配置值是file:/dev/random或者file:/dev/urandom的时候,启用NativeSeedGenerator, 而在linux下的NativeSeedGenerator类

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class NativeSeedGenerator extends SeedGenerator.URLSeedGenerator{  
  2.     NativeSeedGenerator() throws IOException {  
  3.   
  4.         super();  
  5.   
  6.     }  
  7.   
  8. }  

只是简单的继承了一下URLSeedGenerator, 而对URLSeedGenerator默认的构造函数里则强制读取了文件/dev/random

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. URLSeedGenerator()throwsIOException {  
  2.   
  3.             this(SeedGenerator.URL_DEV_RANDOM);  
  4.   
  5.         }  

也就是说哪怕设置了-Djava.security.egd=file:/dev/urandom,最后的结果一样是读取file:/dev/random, 不清楚究竟是代码的bug,还是有意为之?但解决办法相当的有趣,因为在上面的代码中强匹配了file:/dev/random,file:/dev/urandom的值

而对linux来说要表示urandom的路径就很多种方式了

比如file:/dev/./urandom 或者 file:/dev/../dev/urandom 这样就可以绕过JAVA的简单检查了,这应该是JAVA的一个security的bug

设置

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. -Djava.security.egd=file:/dev/./urandom  

就可以绕过保护,而使用URLSeedGenerator,读取文件/dev/./urandom 也就是/dev/urandom文件


Tip: 打开security的debug log

通过设置参数 

-Djava.security.debug=all

可以控制台看到所有security的log 

SecureRandomJava用于生成随机数的类。在CBC加密算法,需要使用SecureRandom生成随机的IV(Initialization Vector),以增强加密的安全性。 以下是Java编程实现CBC对任意大小文件的加解密SecureRandom的编写示例: ```java import java.security.SecureRandom; public class CBCSecureRandomExample { public static void main(String[] args) { byte[] iv = generateIV(16); // 生成16字节的随机IV System.out.println("IV: " + bytesToHex(iv)); } // 生成指定长度的随机字节数组 private static byte[] generateRandomBytes(int length) { byte[] bytes = new byte[length]; SecureRandom random = new SecureRandom(); random.nextBytes(bytes); return bytes; } // 生成指定长度的随机IV public static byte[] generateIV(int length) { return generateRandomBytes(length); } // 字节数组转十六进制字符串 private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X", b)); } return sb.toString(); } } ``` 以上代码,我们先定义了一个generateRandomBytes方法,用于生成指定长度的随机字节数组。然后在generateIV方法调用该方法生成指定长度的随机IV。 最后,我们定义了一个bytesToHex方法,用于将字节数组转为十六进制字符串。在main方法,我们调用generateIV方法生成16字节的随机IV,并将其输出。 在实际应用,我们可以将生成的随机IV和加密后的密文一起存储,以便在解密时使用相同的IV进行解密。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值