2012-01-24 55 views
1

我注意到我運行的應用程序在同時解密時拋出異常。我寫了下面對此進行測試: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,我可以輕鬆地更換,但我認爲最好是在此方面獲得一些更有經驗的意見,並將其用於某些情況下有同樣的問題在它之間絆倒。

如果有人可以指出我的線程安全加密+解密方案的方向,實現相同的結果,我會很感激。

感謝, 馬庫斯

+1

你有一個錯誤(雖然不相關):'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」作爲鍵) –

+0

在我的Crypt類中javax.crypto.Cipher.doFinal行引發了異常,它的確是一個比我的代碼更低級別的問題。如果我插入一個有效的加密字符串,而不是使用encrypt()創建一個帶有隨機IV的字符串(這可能是問題),問題仍然會間歇性地發生,這就排除了一個流氓Base64字符串或md5問題的可能性 我試過了在一臺Ubuntu機器上運行它,我已經躺在那裏,發生同樣的問題。 – Marcus

+0

事實證明,我的md5()方法隨機破壞導致錯誤。謝謝指出問題可能已經一直躺在那裏。 – Marcus

回答

2

這件事是通過這條線這是被用來生成密碼的關鍵所致。

byte[] keybytes = md5(key); 

使用MessageDigest類的md5函數容易返回垃圾,然後被送入進行失敗的解密。

1
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/NoPadding"); //Change here 
     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(); 
    } 
} 
+1

嗨SparX,感謝您的回答,但一些解釋本來不錯... –

+0

如何改變填充會影響穩定性?這個問題最終成爲我無論如何正在使用的錯誤的MD5功能。 – Marcus