2010-06-02 101 views
9

我有一块使用JCE算法“PBEWithSHA256And256BitAES-CBC-BC”创建的密文。提供商是BouncyCastle。我想要做的是使用BouncyCastle轻量级API来解密这个密文。我不想使用JCE,因为这需要安装无限强度管辖权策略文件。如何在AES和PBE中使用Bouncy Castle轻量级API

当涉及到使用BC与PBE和AES时,文档似乎很薄弱。

这是我到目前为止。解密代码无一例外地运行,但返回垃圾。

加密代码,

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()); 
} 

解密代码,

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; 
} 

回答

10

我试过了,它似乎工作。从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; 
} 
+0

谢谢格雷格。很棒。 – Adrian 2010-06-03 07:11:27

+0

行pGen.generateDerivedParameters(256,128);是设置密钥长度吗? – 2014-01-15 09:21:58

+1

@george_h:256是关键字长度; 128是IV长度。 – 2014-01-15 23:51:22

1

这是不平凡的完全一样的JCE同行生成密钥。我只是简要地浏览了你的代码。发现至少有一个差异。 JCE使用PKCS12生成器,但使用PKCS5S1。

如果还有其他差异,我不会感到惊讶。您需要将您的代码与BC源进行比较。

+0

谢谢你的ZZ。我也尝试使用PKCS12,但它没有任何区别。 – Adrian 2010-06-02 13:46:42

8

有你的解密方法的几个问题:

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; 
} 

的主要问题是你不使用分组密码是在执行解密的方式和缺少IV尺寸到generateDerivedParameters方法。我很快就看到了第一个问题,第二个问题不太明显。我只通过查看名为PBETest的Bouncy Castle测试发现了一个。

+0

谢谢拉兹。您的解决方案完美无缺,但是,自Greg首先回答以后,我才接受他的回答。 – Adrian 2010-06-03 07:15:00

+0

感谢您的反馈。我不知何故错过了GregS提供的答案。我很想知道为什么初始化向量的大小需要为128,以及某人应该如何知道这是必需的。这是让我挂断电话的部分。 – laz 2010-06-03 12:47:55

+1

伟大的思想家都认为:)我知道AES是128位块密码,因此AES的IV将始终为128位。我可以使用BlockCipher.getBlockSize()* 8更通用。 – 2010-06-03 12:51:18

0

我注意到您的加密方法接受密码作为字符数组,但解密接受密码为字节。在Java中,chars是16位,而字节是8位。这可能会导致加密/解密不同的密钥,并可能解释乱码解密结果的问题?

相关问题