2013-06-18 60 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密钥的源代码吗?如果不是,那么您对密钥加密的最佳描述是什么? –