前两天在开发中遇到一个问题,就是一个服务部署在 Window 系统上的,而另一个服务部署在 Linux 系统上,Linux 系统上的服务需要通过 WebService 向 Window 系统上的服务获取数据,而这个数据是经过 AES 加密的,获取到密文之后需要进行解密,然后拿到解密之后的数据进行处理,但是在 Linux 系统服务上进行解密时却报错了,下面就是报错信息。
遇到错误第一时间找度娘 ( 其实应该找 Google ),结果发现原来是操作系统的原因,Linux 系统下在进行 AES 加解密时生成 key 时是有问题的,key 值的生成方式如下:
1 2 3 4
| KeyGenerator generator = KeyGenerator.getInstance("AES"); //password 为加解密使用的密钥 generator.init(128, new SecureRandom(password.getBytes())); Key key = generator.generateKey();
|
SecureRandom 的实现尝试完全随机化生成器本身的内部状态,因此随操作系统本身的內部状态而定,该实现在 windows 上每次生成的 key 都相同,但是在 linux 系统上则不同,除非调用方在调用 getInstance 方法之后又调用了 setSeed 方法,将上述生成 key 值的方式改为如下:
1 2 3 4 5 6 7
| KeyGenerator generator = KeyGenerator.getInstance("AES"); //generator.init(128, new SecureRandom(password.getBytes())); SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); //password 为加解密使用的密钥 secureRandom.setSeed(password.getBytes()); generator.init(128, secureRandom); Key key = generator.generateKey();
|
上面只是修改了 key 值的生成方式,这样就能够避免在 Linux 系统上加解密失败的错误了。完整的 AES 加解密工具类如下:
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
| package com.ecjtu.common.util;
import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;
import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom;
/** * @author zhouxh */ public class AesEncodeUtil {
public static void main(String[] args) {
String content = "www.baidu.com"; String pwd = "ecjtu";
System.out.println("加密前content:" + content); // 加密 String enContent = encodeByAes(content, pwd); System.out.println("加密后content:" + enContent);
// 解密 String deContent = decodeByAes(enContent, pwd); System.out.println("解密后content:" + deContent); }
/** * 加密 * * @param content 待加密内容 * @param password 加密密钥 * @return */ public static String encodeByAes(String content, String password) { Key key = generateKey(password); BASE64Encoder base64en = new BASE64Encoder(); try { // 创建密码器 Cipher cipher = Cipher.getInstance("AES"); byte[] byteContent = content.getBytes("utf-8"); // 初始化 cipher.init(Cipher.ENCRYPT_MODE, key); // 加密 content = base64en.encode(cipher.doFinal(byteContent)); } catch (Exception e) { e.printStackTrace(); } return content; }
/** * 解密 * * @param content 待解密内容 * @param password 解密密钥 * @return */ public static String decodeByAes(String content, String password) { Key key = generateKey(password); BASE64Decoder base64de = new BASE64Decoder(); try { byte[] byteContent = base64de.decodeBuffer(content); // 创建密码器 Cipher cipher = Cipher.getInstance("AES"); // 初始化 cipher.init(Cipher.DECRYPT_MODE, key); // 解密 content = new String(cipher.doFinal(byteContent), "UTF8"); } catch (Exception e) { e.printStackTrace(); } return content; }
/** * 根据密钥生成加解密使用的 key 值 * * @param password 加解密密钥 * @return */ public static Key generateKey(String password) { Key key = null; try { KeyGenerator generator = KeyGenerator.getInstance("AES"); //下面这种方式在 Linux 系统下会报错 //generator.init(128, new SecureRandom(password.getBytes())); SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); secureRandom.setSeed(password.getBytes()); generator.init(128, secureRandom); key = generator.generateKey(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return key; } }
|