2011-04-12 50 views
11

我有麻煩了以下JDK JCE加密代碼映射到充氣城堡重量輕API:256bit的AES/CBC/PKCS5Padding與充氣城堡

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,但未獲成功。

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:最後的塊在解密中不完整的。

我在網上搜索了一些例子,但是沒有太多例子提供你自己的IV數據用於256位AES與CBC使用PKCS5/PKCS7作爲填充。

注意:toByte函數使用base64或類似方法將字符串轉換爲字節數組。

回答

21

這應該爲你工作:

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()因爲你的代碼使用32個字符的IV(它提供了必要的16個字節)。雖然我沒有用於執行加密的代碼,但我確實驗證了此代碼將提供與您的代碼相同的解密輸出。

+0

你確定假設IV是第32個字符是正確的嗎?如果是這樣,這是基於什麼? – 2012-09-17 04:43:56

+1

'SecretKeyFactory keyFactory = SecretKeyFactory .getInstance(「PBEWithSHA256And256BitAES-CBC-BC」);'和其他行不是輕量級API,是嗎? – alphakermit 2014-10-09 12:58:58