代码之家  ›  专栏  ›  技术社区  ›  Adrian

如何将Bouncy Castle轻量级API与AES和PBE结合使用

  •  9
  • Adrian  · 技术社区  · 16 年前

    我有一个使用JCE算法创建的密文块“pbewithsha256和256bitaes cbc bc”。提供程序是BouncyCastle。我想做的是使用bouncycastle轻量级API来解密这个密文。我不想使用JCE,因为这需要安装无限制强度的辖区策略文件。

    当涉及到使用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;
    }
    
    4 回复  |  直到 14 年前
        1
  •  10
  •   President James K. Polk    16 年前

    我试过了,它似乎起作用了。大量从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;
    }
    
        2
  •  8
  •   laz    16 年前

    您的解密方法有一些问题:

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

    主要的问题是你在不使用分组密码的情况下进行解密的方式,以及 generateDerivedParameters 方法。我很快就看到了第一个问题,第二个问题就不那么明显了。我只是通过观察一个叫 PBETest .

        3
  •  1
  •   ZZ Coder    16 年前

    生成与JCE对应的密钥并不容易。我只是浏览了一下你的代码。发现至少一个差异。JCE使用pkcs12生成器,但您使用pkcs5s1。

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

        4
  •  0
  •   paradoxpenguin    14 年前

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