2016-02-22 55 views
-1

我已經實現了在服務器(PHP)和客戶端(Android應用程序)之間傳輸的數據加密/解密的兩個函數 。 雖然兩個鍵都是一樣的,但是我從功能上得到了完全不同的結果 。問題是什麼?不同的AES加密結果在PHP和JAVA

JAVA(Android Studio中的功能):

public static String encryptString(String string, String key){ 
    try { 
     SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES"); 
     Cipher cipher = Cipher.getInstance("AES"); 
     cipher.init(Cipher.ENCRYPT_MODE, skeySpec); 
     byte[] encrypted = cipher.doFinal(string.getBytes()); 
     return Base64.encodeToString(encrypted, Base64.URL_SAFE); 
    } catch(Exception e){ 
     return e.getMessage(); 
    } 
} 

private static String decryptString(String string, String key){ 
    try { 
     SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES"); 
     Cipher cipher = Cipher.getInstance("AES"); 
     cipher.init(Cipher.DECRYPT_MODE, skeySpec); 
     byte[] decrypted = cipher.doFinal(string.getBytes()); 
     return Base64.decode(decrypted, Base64.DEFAULT).toString(); 

    } catch(Exception e){ 
     return null; 
    } 
} 

和PHP函數:

function fnEncrypt($sValue, $sSecretKey){ 
return rtrim(
    base64_encode(
     mcrypt_encrypt(
      MCRYPT_RIJNDAEL_128, 
      $sSecretKey, $sValue, 
      MCRYPT_MODE_ECB, 
      mcrypt_create_iv(
       mcrypt_get_iv_size(
        MCRYPT_RIJNDAEL_256, 
        MCRYPT_MODE_ECB 
      ), 
      MCRYPT_RAND) 
     ) 
    ), "\0" 
); 
} 

function fnDecrypt($sValue, $sSecretKey){ 
return rtrim(
    mcrypt_decrypt(
     MCRYPT_RIJNDAEL_128, 
     $sSecretKey, 
     base64_decode($sValue), 
     MCRYPT_MODE_ECB, 
     mcrypt_create_iv(
      mcrypt_get_iv_size(
       MCRYPT_RIJNDAEL_256, 
       MCRYPT_MODE_ECB 
      ), 
      MCRYPT_RAND 
     ) 
    ), "\0" 
); 
} 
+1

ECB不安全。不要使用它。 – SLaks

+0

文字字符沒有足夠的熵來創建有用的密鑰。使用安全的隨機字節,或至少一個KDF。 – SLaks

+0

簡而言之,安全地使用原始密碼原語是_hard_。 http://blog.slaks.net/2015-11-18/common-crypto-pitfalls/不要這樣做。使用libsodium或keyczar等庫。 – SLaks

回答

2

這是很難說的默認選項(填充,模式)時,他們沒有明確指定的在初始化字符串中:Cipher.getInstance("AES")

AES的塊大小爲128.bits,因此您需要指定mcrypt:MCRYPT_RIJNDAEL_128。 MCRYPT_RIJNDAEL_256不是AES。

一個可重複的假設是Java正在使用PKCS#5(實際上是用於AES的PKCS#7)填充。然而,mcrypt不支持PKCS#5(或PKCS#7)填充,只有null填充和null填充不能用於二進制數據。

最好的解決方案是明確指定Java填充和模式,php代碼指定ECB(這是不安全的)。 Java字符串可能應該是:「AES/ECB/PKCS5Padding(128)」see Cipher docs。然後,對於mcrypt,將PKCS#7填充添加到要加密的數據,並在解密後刪除。見PKCS padding

爲什麼不使用:ECB mode,向下滾動到企鵝。