1. 现象
windows操作系统下进行"123456"的AES加密
encrypted message is below :
QLNYZyjRnKF/zxAjzDt/lw==
decrypted message is below :
123456
阿里云服务器,同样是"123456"的密码,每次加密结果都不一样,且不是QLNYZyjRnKF/zxAjzDt/lw==,解密是报错的
2.解决方法
经过检查之后,定位在生成KEY的方法上,如下:
public static Key getSecretKey(String key) throws Exception { SecretKey secureKey = null; if (key == null) { key = ""; } KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(new SecureRandom(key.getBytes())); secureKey = keyGenerator.generateKey(); return secureKey; }
修改到如下方式,问题解决:
public static Key getKey(String strKey) { try { if (strKey == null) { strKey = ""; } KeyGenerator _generator = KeyGenerator.getInstance("AES"); SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); secureRandom.setSeed(strKey.getBytes()); _generator.init(128, secureRandom); return _generator.generateKey(); } catch (Exception e) { throw new RuntimeException(" 初始化密钥出现异常 "); } }
3.原因分析
原因一:
SecureRandom 实现完全隨操作系统本身的内部状态,除非调用方在调用 getInstance 方法之后又调用了 setSeed 方法;该实现在 windows 上每次生成的 key 都相同,但是在 solaris 或部分 linux 系统上则不同。
原因二:
1、加密完byte[] 后,需要将加密了的byte[] 转换成base64保存,如:
BASE64Encoder base64encoder = new BASE64Encoder();
String encode=base64encoder.encode(bytes);
2、解密前,需要将加密后的字符串从base64转回来再解密,如:
BASE64Decoder base64decoder = new BASE64Decoder();
byte[] encodeByte = base64decoder.decodeBuffer(str);
BASE64Encoder base64encoder = new BASE64Encoder();
String encode=base64encoder.encode(bytes);
2、解密前,需要将加密后的字符串从base64转回来再解密,如:
BASE64Decoder base64decoder = new BASE64Decoder();
byte[] encodeByte = base64decoder.decodeBuffer(str);
4. 附录完整代码
package com.binfoo.wechat.util; import java.security.Key; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class SecurityUtil { public static String DES = "AES"; // optional value AES/DES/DESede public static String CIPHER_ALGORITHM = "AES"; // optional value AES/DES/DESede public static Key getKey(String strKey) { try { if (strKey == null) { strKey = ""; } KeyGenerator _generator = KeyGenerator.getInstance("AES"); SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); secureRandom.setSeed(strKey.getBytes()); _generator.init(128, secureRandom); return _generator.generateKey(); } catch (Exception e) { throw new RuntimeException(" 初始化密钥出现异常 "); } } public static String encrypt(String data, String key) throws Exception { SecureRandom sr = new SecureRandom(); Key secureKey = getKey(key); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, secureKey, sr); byte[] bt = cipher.doFinal(data.getBytes()); String strS = new BASE64Encoder().encode(bt); return strS; } public static String decrypt(String message, String key) throws Exception { SecureRandom sr = new SecureRandom(); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); Key secureKey = getKey(key); cipher.init(Cipher.DECRYPT_MODE, secureKey, sr); byte[] res = new BASE64Decoder().decodeBuffer(message); res = cipher.doFinal(res); return new String(res); } public static void main(String[] args) throws Exception { String message = "123456"; String key = "landLeaf"; String encryptMsg = encrypt(message, key); System.out.println("encrypted message is below :"); System.out.println(encryptMsg); String decryptedMsg = decrypt(encryptMsg, key); System.out.println("decrypted message is below :"); System.out.println(decryptedMsg); } }