我注意到我运行的应用程序在同时解密时抛出异常。我写了下面对此进行测试:AES Java多线程例外
public void run() {
for(int i=0; i<100000; i++){
String encrypted = Crypt.encrypt(
"Lorem ipsum dolor sit amet.",
"password"
);
String decrypted = Crypt.decrypt(encrypted, "password")[0];
System.out.println(decrypted);
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new Main());
Thread t2 = new Thread(new Main());
t1.start();
t2.start();
}
地穴方法如下:
public static String encrypt(String input, String key){
try {
byte[] ivBytes = new byte[16];
SecureRandom.getInstance("SHA1PRNG").nextBytes(ivBytes);
IvParameterSpec ips = new IvParameterSpec(ivBytes);
byte[] keybytes = md5(key);//This isn't final. Don't worry ;)
byte[] crypted = null;
SecretKeySpec skey = new SecretKeySpec(keybytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skey, ips);
byte[] ptext = input.getBytes("UTF-8");
crypted = cipher.doFinal(ptext);
return Base64.encodeBase64String(ivBytes)+Base64.encodeBase64String(crypted);
}catch(Exception e){
e.printStackTrace();
}
return null;
}
public static String[] decrypt(String input, String key){
String iv = input.substring(0, 24);
String encrypted = input.substring(24);
try {
IvParameterSpec ips = new IvParameterSpec(Base64.decodeBase64(iv));
byte[] keybytes = md5(key);//This isn't final. Don't worry ;)
byte[] output = null;
SecretKeySpec skey = new SecretKeySpec(keybytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skey, ips);
output = cipher.doFinal(Base64.decodeBase64(encrypted));
if(output==null){
throw new Exception();
}
return new String[]{new String(output),iv};
}catch(Exception e){
e.printStackTrace();
}
}
果然在两个线程第一次尝试失败:
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at common.Crypt.decrypt(Crypt.java:122)
at bootstrap.Main.run(Main.java:427)
at java.lang.Thread.run(Thread.java:680)
有成功的在每个线程上约20次尝试(大概在不安全调用不相交的地方),然后抛出异常。这种模式似乎还在继续。
我在OS X 10.7.2上运行这个如果有帮助。
如果我理解正确,这可能只是一个供应商问题,因为它使用Sun JDK,我可以轻松地更换,但我认为最好是在此方面获得一些更有经验的意见,并将其用于某些情况下有同样的问题在它之间绊倒。
如果有人可以指出我的线程安全加密+解密方案的方向,实现相同的结果,我会很感激。
感谢, 马库斯
你有一个错误(虽然不相关):'new String(output)'应该是'new String(output,“UTF-8”)'。我不会在我的Windows 7盒子JDK 1.6.0_26上重现它,而md5只做key.getBytes(“UTF-8)”和base64“commons-codec”,可能问题来自于你的md5或Base64实现(我使用“passwordpassword”作为键) –
在我的Crypt类中javax.crypto.Cipher.doFinal行引发了异常,它的确是一个比我的代码更低级别的问题。如果我插入一个有效的加密字符串,而不是使用encrypt()创建一个带有随机IV的字符串(这可能是问题),问题仍然会间歇性地发生,这就排除了一个流氓Base64字符串或md5问题的可能性 我试过了在一台Ubuntu机器上运行它,我已经躺在那里,发生同样的问题。 – Marcus
事实证明,我的md5()方法随机破坏导致错误。谢谢指出问题可能已经一直躺在那里。 – Marcus