前言
项目使用到了AES加解密,本地Windows环境测试没有问题,放到生产Linux(Centos7)环境后加解密结果不一致导致程序错误的问题
解决方案
经过检查之后,发现有一点比较奇怪的是linux下每次加密同一字符串出来的结果都不同,于是就怀疑应该是加密的Key这里出了问题,导致每次的加密结果不同,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
private static SecretKeySpec getSecretKey(final String password) { KeyGenerator kg = null; try { kg = KeyGenerator.getInstance(KEY_ALGORITHM); kg.init(128, new SecureRandom(password.getBytes())); SecretKey secretKey = kg.generateKey(); return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM); } catch (NoSuchAlgorithmException ex) { Logger.getLogger(AesEncryptUtils.class.getName()).log(Level.SEVERE, null, ex); }
return null; }
|
修改为如下方式即可解决问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
private static SecretKeySpec getSecretKey(final String password) { KeyGenerator kg = null; try { kg = KeyGenerator.getInstance(KEY_ALGORITHM); SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); secureRandom.setSeed(password.getBytes()); kg.init(128, secureRandom); SecretKey secretKey = kg.generateKey(); return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM); } catch (NoSuchAlgorithmException ex) { Logger.getLogger(AesEncryptUtils.class.getName()).log(Level.SEVERE, null, ex); }
return null; }
|
原因分析
查询资料后发现是:kg.init(128, new SecureRandom(password.getBytes()));
这一段代码有问题。
SecureRandom
实现完全随操作系统本身的内部状态,除非调用方在调用 getInstance
方法之后又调用了 setSeed
方法;改实现在Windows上每次生成的Key都相同,但是在 Solaris
或部分 Linux
系统上则不同;
最后附上AesEncryptUtils工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
| import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.logging.Level; import java.util.logging.Logger;
public class AesEncryptUtils { private static final String KEY_ALGORITHM = "AES"; private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
public static String encrypt(String content, String password) { try { Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); byte[] byteContent = content.getBytes(StandardCharsets.UTF_8); cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password)); byte[] result = cipher.doFinal(byteContent); return Base64.encodeBase64String(result); } catch (Exception ex) { Logger.getLogger(AesEncryptUtils.class.getName()).log(Level.SEVERE, null, ex); }
return null; }
public static String decrypt(String content, String password) { try { Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password)); byte[] result = cipher.doFinal(Base64.decodeBase64(content)); return new String(result, StandardCharsets.UTF_8); } catch (Exception ex) { Logger.getLogger(AesEncryptUtils.class.getName()).log(Level.SEVERE, null, ex); } return null; }
private static SecretKeySpec getSecretKey(final String password) { KeyGenerator kg = null; try { kg = KeyGenerator.getInstance(KEY_ALGORITHM); SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); secureRandom.setSeed(password.getBytes()); kg.init(128, secureRandom); SecretKey secretKey = kg.generateKey(); return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM); } catch (NoSuchAlgorithmException ex) { Logger.getLogger(AesEncryptUtils.class.getName()).log(Level.SEVERE, null, ex); }
return null; }
public static void main(String[] args) { String s = "20191127120752-833";
System.out.println("s:" + s);
String s1 = AesEncryptUtils.encrypt(s, "b8e7f17e785f450e"); System.out.println("s1:" + s1);
System.out.println("s2:" + AesEncryptUtils.decrypt(s1, "b8e7f17e785f450e")); } }
|