2013-06-18 57 views
0

我試圖解密使用AES-128對稱加密,然後使用RSA-1024對生成的對稱密鑰進行非對稱加密的消息。我收到加密的AES密鑰和加密的消息,從pfx文件中提取私鑰,然後繼續解密對稱密鑰。之後,我嘗試使用解密的AES密鑰來解密加密的消息。RSA解密後AES密鑰大小無效

以下是我的代碼:

// Get the private key 
    PrivateKey privateKey = (PrivateKey) keyStore.getKey(selectedAlias, "password".toCharArray()); 
    System.out.println("Key information " + privateKey.getAlgorithm() + " " + privateKey.getFormat()); 

    // Load aesSessionKey and encryptedMessage 
    byte[] aesSessionKey = ... 
    byte[] encryptedMessage = ... 

    // RSA Decryption of Encrypted Symmetric AES key - 128 bits 
    Cipher rsaCipher = Cipher.getInstance("RSA", "BC"); 
    rsaCipher.init(Cipher.UNWRAP_MODE, privateKey); 
    Key decryptedKey = rsaCipher.unwrap(aesSessionKey, "AES", Cipher.SECRET_KEY); 
    System.out.println("Decrypted Key Length: " + decryptedKey.getEncoded().length); 

    SecretKeySpec decrypskeySpec = new SecretKeySpec(decryptedKey.getEncoded(), "AES"); 
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING", "BC"); 
    cipher.init(Cipher.DECRYPT_MODE, decryptedKey, new IvParameterSpec(new byte[16])); 
    byte[] message = cipher.doFinal(encryptedMessage); 
    System.out.println(new String(message, "UTF-8")); 

的問題是,解密的AES密鑰的大小爲128個字節,而不是16個字節爲我所期待的。我收到以下例外情況:

Key information RSA PKCS#8 
Decrypted Key Length: 128 
java.security.InvalidKeyException: Key length not 128/192/256 bits. 
at org.bouncycastle.jce.provider.JCEBlockCipher.engineInit(Unknown Source) 
at javax.crypto.Cipher.init(DashoA13*..) 
at javax.crypto.Cipher.init(DashoA13*..) 
at com.simarks.services.PKCS12.run(PKCS12.java:74) 
at com.simarks.services.PKCS12.main(PKCS12.java:34) 

我是Java密碼學新手。我檢查了很多其他問題,並嘗試了幾種不同的方法(例如使用DECRYPT_MODE而不是UNWRAP_MODE),但我得到相同的錯誤。任何幫助都感激不盡。


編輯: 客戶代碼加密消息是這樣的:

PBYTE   pInputData = NULL; 
DWORD   dwInputSize = 0; 
PBYTE   pCertData = NULL; 
DWORD   dwCertSize = 0; 
PCCERT_CONTEXT pCertContext = NULL; 
HCRYPTPROV  hCryptProv = NULL; 
HCRYPTKEY  hPublicKey = NULL; 
HCRYPTKEY  hSessionKey = NULL; 
BYTE   InitializationVector[ 32 ] = { 0 }; 
DWORD   PKCS5Padding = PKCS5_PADDING; 
DWORD   CBCMode = CRYPT_MODE_CBC; 
PSIMPLEBLOB pKeyBlob = NULL; 
DWORD   dwBlobSize = 0; 
DWORD   dwKeySize = 0; 
PBYTE   pEncryptedData = NULL; 
DWORD   dwEncryptedDataSize = 0; 
HRESULT  hr = S_FALSE; 

if(FAILED(hr = ReadBinaryFile(InputFile, &pInputData, &dwInputSize))) goto EncryptExit; 
if(FAILED(hr = ReadBinaryFile(CertFile, &pCertData, &dwCertSize))) goto EncryptExit; 
if((pCertContext = CertCreateCertificateContext(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, pCertData, dwCertSize)) == NULL) goto EncryptExit; 
if(!CryptAcquireContext(&hCryptProv, NULL, GetMsAesProviderName(), PROV_RSA_AES, 0)) goto EncryptExit; 
if(!CryptImportPublicKeyInfo(hCryptProv, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, &pCertContext->pCertInfo->SubjectPublicKeyInfo, &hPublicKey)) goto EncryptExit; 

if(!CryptGenKey(hCryptProv, AlgId, CRYPT_EXPORTABLE, &hSessionKey)) goto EncryptExit; 
if(!CryptSetKeyParam(hSessionKey, KP_IV, InitializationVector, 0)) goto EncryptExit; 
if(!CryptSetKeyParam(hSessionKey, KP_PADDING, (PBYTE)&PKCS5Padding, 0)) goto EncryptExit; 
if(!CryptSetKeyParam(hSessionKey, KP_MODE, (PBYTE)&CBCMode, 0)) goto EncryptExit; 

if(!CryptExportKey(hSessionKey, hPublicKey, SIMPLEBLOB, 0, NULL, &dwBlobSize)) goto EncryptExit; 
if((pKeyBlob = (PSIMPLEBLOB)malloc(dwBlobSize)) == NULL) { hr = E_OUTOFMEMORY; goto EncryptExit; } 
if(!CryptExportKey(hSessionKey, hPublicKey, SIMPLEBLOB, 0, (PBYTE)pKeyBlob, &dwBlobSize)) goto EncryptExit; 
dwKeySize = dwBlobSize - sizeof(BLOBHEADER) - sizeof(ALG_ID); 

dwEncryptedDataSize = dwInputSize; 
if(!CryptEncrypt(hSessionKey, NULL, TRUE, 0, NULL, &dwEncryptedDataSize, 0)) goto EncryptExit; 
if((pEncryptedData = (PBYTE)malloc(dwEncryptedDataSize)) == NULL) { hr = E_OUTOFMEMORY; goto EncryptExit; } 
CopyMemory(pEncryptedData, pInputData, dwInputSize); 
if(!CryptEncrypt(hSessionKey, NULL, TRUE, 0, pEncryptedData, &dwInputSize, dwEncryptedDataSize)) goto EncryptExit; 

if(FAILED(hr = WriteBinaryFile(OutputFile, pEncryptedData, dwInputSize))) goto EncryptExit; 

hr = WriteBinaryFile(KeyFile, pKeyBlob->Key, dwKeySize); 

EncryptExit: 
+0

你能嘗試解密使用'Cipher.getInstance( 「RSA/ECB/PKCS1Padding」 「BC」)'而不是使用'「RSA」'的默認值?對於這種功能,您也可以嘗試使用默認的Oracle提供程序(因此請嘗試刪除「BC」參數。同時打印返回的鍵的類型。 –

+1

使用安全填充,最好使用OAEP而不使用PKCS #1v1.5對於RSA的安全至關重要,你真的應該修復填充 – CodesInChaos

回答

0

經過一番研究,我通過顛倒aesSessionKey字節解決這個問題:

org.apache.commons.lang.ArrayUtils.reverse(encryptedSessionKey); 

顯然CryptoAPI的結構通常在little-endian順序表示數據,但Java語言(.NET)使用大端。下面是一些在那裏我找到了解決方案的鏈接:

1

AES需要128位密鑰,這是16個字節,作爲一個字節配合八位。

1024位RSA加密1024 (或128 字節)的數據。您應該始終使用填充RSA,因爲這可以提高安全性並允許您加密任意數量的數據。

另請注意,1024位RSA對於強力攻擊非常弱。 2048位被認爲是最小的。

此外,具有靜態IV的CBC模式只是要求麻煩。

+0

這個答案只是關於AES密鑰和RSA加密的陳述的集合,這怎麼解決原來的問題? –

+0

我覺得第一段很安靜明確指出問題所在,第二段說明如何解決問題,最後兩段指出代碼中的其他加密問題 – ntoskrnl

+0

不知道你在說什麼@ntoskrnl。我知道AES密鑰I解密需要128位長(16字節),但我得到一個128字節長的一個,而我認爲你的觀點是關於RSA-1024很弱。 –

1

與許多其他提供者不同,默認情況下,BouncyCastle提供程序在您指定"RSA"算法時不使用填充。 According to the FAQ,BC提供者將將"RSA"映射到"RSA/NONE/NoPadding"

因此,您的解密數據仍然具有附加的填充,因此長度爲128個字節。您需要確定在加密密鑰時使用了哪個填充,並確保在創建Cipher實例時明確指定。例如:

Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC") 

作爲owlstead mentioned in the comments,你也可以考慮使用標準的Oracle提供者的代碼,如果你想 - 它不會出現BouncyCastle的是必要的。

+0

我嘗試過使用'cipher rsaCipher = Cipher.getInstance(「RSA/ECB/PKCS1Padding」,「BC」)',但我在'rsaCipher.doFinal'上得到以下例外:'關鍵信息RSA PKCS#8 javax.crypto。 BadPaddingException:未知塊類型 \t在org.bouncycastle.jce.provider.JCERSACipher.engineDoFinal(未知來源) \t在javax.crypto.Cipher.doFinal(Cipher.java:1978) \t在com.simarks.services.PKCS12 .run(PKCS12.java:73) \t at com.simarks.services.PKCS12.main(PKCS12.java:33)' –

+0

另外我嘗試過使用標準的Oracle提供程序,我得到以下異常:'關鍵信息RSA PKCS# 8 javax.crypto.BadPaddingException:數據必須以零開頭 \t在sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:325) \t在sun.security.rsa.RSAPadding.unpad(RSAPadding.java:272) \t在com.sun.crypto.provider.RSACipher .doFinal在(RSACipher.java:357) \t在com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:383) \t在javax.crypto.Cipher.doFinal(Cipher.java:1978) \t com.simarks.services.PKCS12.run(PKCS12.java:71) \t at com.simarks.services.PKCS12.main(PKCS12.java:31)' –

+0

@spaniard聲音像PKCS#1填充未用於原始的加密。你有加密AES密鑰的源代碼嗎?如果不是,那麼您對密鑰加密的最佳描述是什麼? –