2010-06-02 98 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位。這可能會導致加密/解密不同的密鑰,並可能解釋亂碼解密結果的問題?

相關問題