Java RSA解密后AES密钥大小无效

Java RSA解密后AES密钥大小无效,java,cryptography,aes,encryption,private-key,Java,Cryptography,Aes,Encryption,Private Key,我正在尝试解密一条已使用AES-128对称加密加密的消息,然后对生成的对称密钥使用RSA-1024非对称加密。我收到加密的AES密钥和加密的消息,从pfx文件中提取私钥,然后继续解密对称密钥。之后,我尝试使用解密的AES密钥解密加密的消息 以下是我的代码: // Get the private key PrivateKey privateKey = (PrivateKey) keyStore.getKey(selectedAlias, "password".toCharArray());

我正在尝试解密一条已使用AES-128对称加密加密的消息,然后对生成的对称密钥使用RSA-1024非对称加密。我收到加密的AES密钥和加密的消息,从pfx文件中提取私钥,然后继续解密对称密钥。之后,我尝试使用解密的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_模式而不是UNWRAP_模式),但我得到了相同的错误。任何帮助都将不胜感激


编辑: 加密消息的客户端代码如下所示:

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:
AES采用128位密钥,长度为16字节,因为一个字节适合八位

1024位RSA加密1024位(或128字节)的数据。您应该始终在RSA中使用填充,因为这样可以提高安全性并允许您加密任意数量的数据

还要注意,1024位RSA对暴力攻击的抵抗力非常弱。2048位被视为最小值


此外,带有静态IV的CBC模式只是自找麻烦。

与许多其他提供程序不同,BouncyCastle提供程序在指定
“RSA”
算法时默认不使用填充,BC提供程序将
“RSA”
映射到
“RSA/NONE/NoPadding”

因此,解密后的数据仍然附加了填充,因此长度为128字节。您需要确定在密钥加密中使用了哪些填充,并确保在创建
密码
实例时明确指定。例如:

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

作为OWLSTED,如果您愿意,也可以考虑使用标准的Oracle提供程序——它不显示BouncyCastle是必要的。

< P>在一些研究之后,我通过反转<代码> AESISEXCEDKEY/<代码>:

的字节来解决这个问题。
org.apache.commons.lang.ArrayUtils.reverse(encryptedSessionKey);
显然,CryptoAPI结构通常以小端顺序表示数据,但Java(和.NET)使用大端顺序。以下是我找到解决方案的一些链接:


是否可以尝试使用
Cipher.getInstance(“RSA/ECB/PKCS1Padding”,“BC”)
而不是使用
的默认值“RSA”
?对于这种功能,您还可以顺便尝试默认的Oracle提供程序(因此请尝试删除
“BC”
参数。同时打印返回密钥的类型。使用安全填充,最好是OAEP,而不是PKCS#1v1.5,这对RSA的安全性至关重要。您确实应该修复填充。这个答案只是关于AES密钥和RSA加密的一组语句。这如何解决原始问题?我认为第一段退出e清楚地说明了问题所在。第二段解释了如何解决问题。最后两段指出了代码中的其他加密问题。不确定您试图说什么@ntoskrnl。我知道我解密的AES密钥需要128位长(16字节)但是我得到的是一个128字节长的。我理解你关于RSA-1024很弱的观点。你得到128字节是因为1024位RSA加密的数据量。如果你想加密不同数量的数据,你必须使用填充。我尝试使用
Cipher rsaciper=Cipher.getInstance(“RSA/ECB/PKCS1Padding”,“BC”)
但是我在
rsaciper.doFinal
上得到了以下异常:
密钥信息RSA-PKCS#8 javax.crypto.BadPaddingException:org.bouncycastle.jce.provider.JCERSACipher.engineDoFinal(未知源代码)上的未知块类型,javax.crypto.Cipher.doFinal(Cipher.java:1978)上的com.simarks.services.PKCS12.run(PKCS12.java:73)在com.simarks.services.PKCS12.main(PKCS12.java:33)
上,我也尝试了标准的Oracle提供程序,我得到了一个异常:
密钥信息RSA-PKCS#8 javax.crypto.badpadingexception:sun.security.RSA.RSAPadding.unpadding15(RSAPadding.java:325)上sun.security.RSA.RSAPadding.unpadding(RSAPadding.java:272)上的数据必须以零开头com.sun.crypto.provider.rsaciper.doFinal(rsaciper.java:357)com.sun.crypto.provider.rsaciper.engineDoFinal(rsaciper.java:383)javax.crypto.Cipher.doFinal(Cipher.java:1978)com.simarks.services.PKCS12.run(PKCS12.java:71)com.simarks.services.PKCS12.main(PKCS12.java:31)
@spaniard听起来像PKCS#1填充在原始加密中没有使用。您有加密AES密钥的源代码吗?如果没有,您对密钥加密方式的最佳描述是什么?只是在问题中添加了客户端代码。我希望这有助于解决问题