2011-11-22 144 views
2

我使用AES-128/ecb/PKCS5Padding + base64來隱藏數據時遇到問題。我使用下面的代碼來加密我的數據:在Java中使用AES-128加密

String input = "{\"action\":\"getQuestion\"}"; 
String key = "4288f0b8060ca1b682bf795f2617cfdc"; 
byte[] data = input.getBytes(); 
byte[] encrypted = null; 
byte[] keyBytes = new BigInteger(key, 16).toByteArray(); 
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); 
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
cipher.init(Cipher.ENCRYPT_MODE, keySpec); 
encrypted = cipher.doFinal(data); 
System.out.println(Base64.encodeBytes(encrypted)); 

我收到加密後6GuKXA6FFR+yMmO8ksAEOLL5e574a5tLob7tt5IG+jk=但我不能使用PHP函數在服務器上解密。

當我使用PHP函數這個數據加密:

function encrypt($encrypt, $key=null) 
{ 
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND); 
    $encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $encrypt, MCRYPT_MODE_ECB, $iv)); 
    return $encrypted; 
} 

我收到6Wc3LPWvfJ7T86iG0igmdQaeZ8xs9qY419mAVWfNH+M=,我可以使用下面的PHP函數做成功解密:

function decrypt($decrypt, $key=null) 
{ 
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND); 
    $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($decrypt), MCRYPT_MODE_ECB, $iv); 
    return $decrypted; 
} 

使用Base64加密和解密有沒有問題;我只在使用AES-128進行加密時遇到此問題。

+0

的$ IV值你可能不使用兩個相同的密鑰兩側。發佈所有填充'$ key'的PHP代碼,包括當前發佈代碼中常量的聲明。 –

+0

不,我使用相同的密鑰 – silentnuke

+1

有幾件事情:1)刪除IV,我不知道它會對PHP函數做什麼,但如果它做了什麼,它會弄糟加密/解密2)從不使用String.getBytes()而不指定要使用的編碼3)根據密鑰值,BigInteger.toByteArray()可能返回1到17個字節的任何內容4)ECB絕對是這種加密的錯誤類型。在嘗試其他事情之前修復這些問題我認爲你可以安全地使用ASCII與PHP通信和使用代碼<128的字符。 –

回答

1

問題不在於IV或填充,因爲我最初認爲。這與您如何處理PHP代碼中的密鑰有關。如果您使用實際字符串4288f0b8060ca1b682bf795f2617cfdc作爲傳入mcrypt_encryptmcrypt_decrypt的密鑰,那麼您沒有使用與Java代碼中相同的密鑰。您將需要將該十六進制字符串轉換爲字節。您可以通過以下方式做到這一點:

$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, pack("H*", $key), base64_decode($decrypt), MCRYPT_MODE_ECB, $iv); 

注意添加pack("H*", $key)將值轉換。我發現here在PHP bin2hex函數的註釋中。這將解決當前的問題。使用不同長度的數據時,可能會遇到填充問題,因爲PHP不會執行PKCS5填充。請參閱this有關實現該缺失函數的評論。另外,由於歐洲央行對數據加密的不適宜性和弱點,我建議考慮CBC而不是ECB。

+0

我嘗試在沒有初始化向量的PHP,但這些分別完全相同,並且不能解密在java上生成的數據。 – silentnuke

+0

是的,歐洲央行不使用初始化向量。這是什麼使它比其他模式更安全。一旦你把所有的東西都搞清楚了,你可能會想用C代替CBC。 – laz

+0

@silentnuke:不能保證默認的Java IV與默認的PHP IV相同。您需要明確指定雙方的IV。至少,將加密IV複製到解密函數。另外,避免ECB模式,這是不安全的。改用CBC或CTR模式。 – rossum

1

您可以使用openssl在命令行驗證Java方法的輸出。如果未指定,Java會將您的IV默認爲0。

The file "enc.txt" contains "6GuKXA6FFR+yMmO8ksAEOLL5e574a5tLob7tt5IG+jk=" [corrected] 

運行

openssl aes-128-ecb -in enc.txt -a -K 4288f0b8060ca1b682bf795f2617cfdc -iv 0 -d 

結果是:

{"action":"getQuestion"} 

試試你mcrypt_decrypt與0

+0

如果java的functiob返回6Wc3LPWvfJ7T86iG0igmdQaeZ8xs9qY419mAVWfNH + M =問題不會是,但返回6GuKXA6FFR + yMmO8ksAEOLL5e574a5tLob7tt5IG + JK = – silentnuke

+0

哎呦。當我在這裏寫下筆記時錯別字 - 不是當我測試時。文件「enc.txt」實際上是「6Gu ...」字符串。 – phatfingers