Securerandom Aes

2017/08/31

AES 加密


/** 
 * 加密 
 *  
 * @param content 需要加密的内容 
 * @param password  加密密码 
 * @return 
 */  
public static byte[] encrypt(String content, String password) {  
        try {             
                KeyGenerator kgen = KeyGenerator.getInstance("AES");  
                kgen.init(128, new SecureRandom(password.getBytes()));  
                SecretKey secretKey = kgen.generateKey();  
                byte[] enCodeFormat = secretKey.getEncoded();  
                SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");  
                Cipher cipher = Cipher.getInstance("AES");// 创建密码器  
                byte[] byteContent = content.getBytes("utf-8");  
                cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化  
                byte[] result = cipher.doFinal(byteContent);  
                return result; // 加密  
        } catch (NoSuchAlgorithmException e) {  
                e.printStackTrace();  
        } catch (NoSuchPaddingException e) {  
                e.printStackTrace();  
        } catch (InvalidKeyException e) {  
                e.printStackTrace();  
        } catch (UnsupportedEncodingException e) {  
                e.printStackTrace();  
        } catch (IllegalBlockSizeException e) {  
                e.printStackTrace();  
        } catch (BadPaddingException e) {  
                e.printStackTrace();  
        }  
        return null;  
} 

AES解密

/**解密 
 * @param content  待解密内容 
 * @param password 解密密钥 
 * @return 
 */  
public static byte[] decrypt(byte[] content, String password) {  
        try {  
                 KeyGenerator kgen = KeyGenerator.getInstance("AES");  
                 kgen.init(128, new SecureRandom(password.getBytes()));  
                 SecretKey secretKey = kgen.generateKey();  
                 byte[] enCodeFormat = secretKey.getEncoded();  
                 SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");              
                 Cipher cipher = Cipher.getInstance("AES");// 创建密码器  
                cipher.init(Cipher.DECRYPT_MODE, key);// 初始化  
                byte[] result = cipher.doFinal(content);  
                return result; // 加密  
        } catch (NoSuchAlgorithmException e) {  
                e.printStackTrace();  
        } catch (NoSuchPaddingException e) {  
                e.printStackTrace();  
        } catch (InvalidKeyException e) {  
                e.printStackTrace();  
        } catch (IllegalBlockSizeException e) {  
                e.printStackTrace();  
        } catch (BadPaddingException e) {  
                e.printStackTrace();  
        }  
        return null;  
}  

分析

该加解密算法SecureRandom存在坑。在不同平台window/linux,不同jdk 6/7/8, 不同系统配置时多台分布式服务器参加加解密时可能会出现:在一台服务加密的文件在另外一台服务器上不能解密。

原因跟SecureRandom实现的PRNG随机算法有关。PRNG是Java加密服务提供商(CSP)的一部分。在Sun的Java实现中,默认情况下使用SUN CSP。在Windows上,SUN CSP默认使用在sun.security.provider.SecureRandom中实现的SHA1PRNG。在Solaris和Linux上,SUN CSP默认是使用sun.security.provider.NativePRNG,它只提供操作系统提供的/dev/urandomPRNG 的输出。

经测试,指定SecureRandom算法SHA1PRNG没有问题。在我们环境(linux/jdk6/8)中没有显式指定默认走NativePRNG。SecureRandom默认算法选择逻辑:

     static void More ...putEntries(Map<Object, Object> map) {
86 
87         /*
88          * SecureRandom
89          *
90          * Register these first to speed up "new SecureRandom()",
91          * which iterates through the list of algorithms
92          */
93         // register the native PRNG, if available
94         // if user selected /dev/urandom, we put it before SHA1PRNG,
95         // otherwise after it
96         boolean nativeAvailable = NativePRNG.isAvailable();
97         boolean useNativePRNG = seedSource.equals(URL_DEV_URANDOM) ||
98             seedSource.equals(URL_DEV_RANDOM);
99 
100        if (nativeAvailable && useNativePRNG) {
101            map.put("SecureRandom.NativePRNG",
102                "sun.security.provider.NativePRNG");
103        }
104        map.put("SecureRandom.SHA1PRNG",
105             "sun.security.provider.SecureRandom");
106        if (nativeAvailable && !useNativePRNG) {
107            map.put("SecureRandom.NativePRNG",
108                "sun.security.provider.NativePRNG");
109        }
  
  		  ......

从上面可以看出,linux下指定了/dev/urandom或者/dev/random采用优先级高的NativePRNG。否则SHA1PRNG优先级高。

至于通过-Djava.security.egd=file:/dev/./urandom 而不是 file:/dev/urandom 那又是另外一个忧伤的故事。http://blog.csdn.net/raintungli/article/details/42876073

Search

    Table of Contents