問題描述
我在將以下 JDK JCE 加密代碼映射到 Bouncy Castles 輕量級 API 時遇到問題:
I am having trouble mapping the following JDK JCE encryption code to Bouncy Castles Light-weight API:
public String dec(String password, String salt, String encString) throws Throwable {
// AES algorithm with CBC cipher and PKCS5 padding
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
// Construct AES key from salt and 50 iterations
PBEKeySpec pbeEKeySpec = new PBEKeySpec(password.toCharArray(), toByte(salt), 50, 256);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC");
SecretKeySpec secretKey = new SecretKeySpec(keyFactory.generateSecret(pbeEKeySpec).getEncoded(), "AES");
// IV seed for first block taken from first 32 bytes
byte[] ivData = toByte(encString.substring(0, 32));
// AES encrypted data
byte[] encData = toByte(encString.substring(32));
cipher.init( Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec( ivData ) );
return new String( cipher.doFinal( encData ) );
}
上述方法效果很好,但由于 Oracle 對加密強度的限制,移植性不太好.我曾多次嘗試移植到 Bouncy Castles 輕量級 API,但均未成功.
The above works great, but is not very portable due to Oracle's restriction on encryption strengths. I've made several attempts at porting to Bouncy Castles Light-weight API but without success.
public String decrypt1(String password, String salt, String encString) throws Exception {
byte[] ivData = toByte(encString.substring(0, 32));
byte[] encData = toByte(encString.substring(32));
PKCS12ParametersGenerator gen = new PKCS12ParametersGenerator(new SHA256Digest());
gen.init(password.getBytes(), toByte(salt), 50);
CBCBlockCipher cbcBlockcipher = new CBCBlockCipher(new RijndaelEngine(256));
CipherParameters params = gen.generateDerivedParameters(256, 256);
cbcBlockcipher.init(false, params);
PaddedBufferedBlockCipher aesCipher = new PaddedBufferedBlockCipher(cbcBlockcipher, new PKCS7Padding());
byte[] plainTemp = new byte[aesCipher.getOutputSize(encData.length)];
int offset = aesCipher.processBytes(encData, 0, encData.length, plainTemp, 0);
int last = aesCipher.doFinal(plainTemp, offset);
byte[] plain = new byte[offset + last];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
return new String(plain);
}
上述嘗試導致 org.bouncycastle.crypto.DataLengthException: last block complete in decryption.
The above attempt results in a org.bouncycastle.crypto.DataLengthException: last block incomplete in decryption.
我已經在網上搜索了示例,但是沒有很多示例可以使用 PKCS5/PKCS7 作為填充,為 256 位 AES 和 CBC 提供您自己的 IV 數據.
I have searched for examples online, but there isn't many examples of providing your own IV data for 256bit AES with CBC using PKCS5/PKCS7 as padding.
注意:toByte 函數使用 base64 或類似方法將字符串轉換為字節數組.
NB: The toByte function converts a String into a byte array using base64 or similar.
推薦答案
這應該適合你:
public String dec(String password, String salt, String encString)
throws Exception {
byte[] ivData = toByte(encString.substring(0, 32));
byte[] encData = toByte(encString.substring(32));
// get raw key from password and salt
PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(),
toByte(salt), 50, 256);
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBEWithSHA256And256BitAES-CBC-BC");
SecretKeySpec secretKey = new SecretKeySpec(keyFactory.generateSecret(
pbeKeySpec).getEncoded(), "AES");
byte[] key = secretKey.getEncoded();
// setup cipher parameters with key and IV
KeyParameter keyParam = new KeyParameter(key);
CipherParameters params = new ParametersWithIV(keyParam, ivData);
// setup AES cipher in CBC mode with PKCS7 padding
BlockCipherPadding padding = new PKCS7Padding();
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESEngine()), padding);
cipher.reset();
cipher.init(false, params);
// create a temporary buffer to decode into (it'll include padding)
byte[] buf = new byte[cipher.getOutputSize(encData.length)];
int len = cipher.processBytes(encData, 0, encData.length, buf, 0);
len += cipher.doFinal(buf, len);
// remove padding
byte[] out = new byte[len];
System.arraycopy(buf, 0, out, 0, len);
// return string representation of decoded bytes
return new String(out, "UTF-8");
}
我假設您實際上是在為 toByte()
進行十六進制編碼,因為您的代碼為 IV 使用了 32 個字符(它提供了必要的 16 個字節).雖然我沒有您用來進行加密的代碼,但我確實驗證了此代碼將提供與您的代碼相同的解密輸出.
I assume that you're actually doing hex encoding for toByte()
since your code uses 32 characters for the IV (which provides the necessary 16 bytes). While I don't have the code you used to do the encryption, I did verify that this code will give the same decrypted output as your code.
這篇關于帶充氣城堡的 256 位 AES/CBC/PKCS5Padding的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!