java 如何在 AES 和 PBE 中使用 Bouncy Castle 轻量级 API
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2957513/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use Bouncy Castle lightweight API with AES and PBE
提问by Adrian
I have a block of ciphertext that was created using the JCE algorithim "PBEWithSHA256And256BitAES-CBC-BC". The provider is BouncyCastle. What I'd like to do it decrypt this ciphertext using the BouncyCastle lightweight API. I don't want to use JCE because that requires installing the Unlimited Strength Jurisdiction Policy Files.
我有一个使用 JCE 算法“PBEWithSHA256And256BitAES-CBC-BC”创建的密文块。提供者是 BouncyCastle。我想做的是使用 BouncyCastle 轻量级 API 解密这个密文。我不想使用 JCE,因为这需要安装 Unlimited Strength Jurisdiction Policy Files。
Documentation seems to be thin on the ground when it comes to using BC with PBE and AES.
在将 BC 与 PBE 和 AES 结合使用时,文档似乎很少。
Here's what I have so far. The decryption code runs without exception but returns rubbish.
这是我到目前为止所拥有的。解密代码无一例外地运行,但返回垃圾。
The encryption code,
加密代码,
String password = "qwerty";
String plainText = "hello world";
byte[] salt = generateSalt();
byte[] cipherText = encrypt(plainText, password.toCharArray(), salt);
private static byte[] generateSalt() throws NoSuchAlgorithmException {
byte salt[] = new byte[8];
SecureRandom saltGen = SecureRandom.getInstance("SHA1PRNG");
saltGen.nextBytes(salt);
return salt;
}
private static byte[] encrypt(String plainText, char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
Security.addProvider(new BouncyCastleProvider());
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 20);
PBEKeySpec pbeKeySpec = new PBEKeySpec(password);
SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC");
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
Cipher encryptionCipher = Cipher.getInstance("PBEWithSHA256And256BitAES-CBC-BC");
encryptionCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
return encryptionCipher.doFinal(plainText.getBytes());
}
The decryption code,
解密代码,
byte[] decryptedText = decrypt(cipherText, password.getBytes(), salt);
private static byte[] decrypt(byte[] cipherText, byte[] password, byte[] salt) throws DataLengthException, IllegalStateException, InvalidCipherTextException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
BlockCipher engine = new AESEngine();
CBCBlockCipher cipher = new CBCBlockCipher(engine);
PKCS5S1ParametersGenerator keyGenerator = new PKCS5S1ParametersGenerator(new SHA256Digest());
keyGenerator.init(password, salt, 20);
CipherParameters keyParams = keyGenerator.generateDerivedParameters(256);
cipher.init(false, keyParams);
byte[] decryptedBytes = new byte[cipherText.length];
int numBytesCopied = cipher.processBlock(cipherText, 0, decryptedBytes, 0);
return decryptedBytes;
}
回答by President James K. Polk
I tried this and it seemed to work. Borrowed heavily from the BC class org.bouncycastle.jce.provider.test.PBETest
我试过这个,它似乎有效。大量借用 BC 班级org.bouncycastle.jce.provider.test.PBETest
private byte[] decryptWithLWCrypto(byte[] cipher, String password, byte[] salt, final int iterationCount)
throws Exception
{
PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(new SHA256Digest());
char[] passwordChars = password.toCharArray();
final byte[] pkcs12PasswordBytes = PBEParametersGenerator
.PKCS12PasswordToBytes(passwordChars);
pGen.init(pkcs12PasswordBytes, salt, iterationCount);
CBCBlockCipher aesCBC = new CBCBlockCipher(new AESEngine());
ParametersWithIV aesCBCParams = (ParametersWithIV) pGen.generateDerivedParameters(256, 128);
aesCBC.init(false, aesCBCParams);
PaddedBufferedBlockCipher aesCipher = new PaddedBufferedBlockCipher(aesCBC,
new PKCS7Padding());
byte[] plainTemp = new byte[aesCipher.getOutputSize(cipher.length)];
int offset = aesCipher.processBytes(cipher, 0, cipher.length, plainTemp, 0);
int last = aesCipher.doFinal(plainTemp, offset);
final byte[] plain = new byte[offset + last];
System.arraycopy(plainTemp, 0, plain, 0, plain.length);
return plain;
}
回答by laz
There were a few problems with your decrypt method:
您的解密方法存在一些问题:
private static byte[] decrypt(final byte[] bytes, final char[] password, final byte[] salt) throws DataLengthException, IllegalStateException, InvalidCipherTextException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
final PBEParametersGenerator keyGenerator = new PKCS12ParametersGenerator(new SHA256Digest());
keyGenerator.init(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password), salt, 20);
final CipherParameters keyParams = keyGenerator.generateDerivedParameters(256, 128);
final BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), new PKCS7Padding());
cipher.init(false, keyParams);
final byte[] processed = new byte[cipher.getOutputSize(bytes.length)];
int outputLength = cipher.processBytes(bytes, 0, bytes.length, processed, 0);
outputLength += cipher.doFinal(processed, outputLength);
final byte[] results = new byte[outputLength];
System.arraycopy(processed, 0, results, 0, outputLength);
return results;
}
The main problems were the way you were carrying out the decryption without using a block cipher and the missing IV size to the generateDerivedParametersmethod. I saw the first problem pretty quickly, the 2nd one was much less obvious. I only discovered that one through looking at a Bouncy Castle test called PBETest.
主要问题是您在不使用分组密码的情况下执行解密的方式以及该方法缺少的 IV 大小generateDerivedParameters。我很快就看到了第一个问题,第二个问题就不那么明显了。我只是通过查看名为PBETest的 Bouncy Castle 测试才发现的。
回答by ZZ Coder
It's not trivial to generate the key exactly as the JCE counterparts. I just briefly browsed your code. Found at least one discrepancy. JCE uses PKCS12 generator but you use PKCS5S1.
完全按照 JCE 对应项生成密钥并非易事。我只是简单地浏览了你的代码。发现至少一处差异。JCE 使用 PKCS12 生成器,但您使用 PKCS5S1。
I am not surprised if there are other differences. You need to compare your code against BC source.
如果有其他差异,我并不感到惊讶。您需要将您的代码与 BC 源代码进行比较。
回答by paradoxpenguin
I noticed that your encryption method accepts a password as a char array but the decrypt accepts password as bytes. In Java chars are 16-bit while bytes are 8-bit. This could result in different keys for encrypt/decrypt and perhaps explain the issues with gibberish decrypted results?
我注意到您的加密方法接受密码作为字符数组,但解密接受密码作为字节。在 Java 中,字符是 16 位,而字节是 8 位。这可能会导致加密/解密的密钥不同,也许可以解释乱码解密结果的问题?

