如何使用MySQL AES_DECRYPT解密使用BouncyCastles PBEWITHSHA256AND256BITAES-CBC-BC算法加密的数据

问题描述

我们使用BouncyCastle PBEWITHSHA256AND256BITAES-CBC-BC通过我们的Java应用程序对数据进行加密,并将加密后的结果存储在MysqL数据库中。

示例代码

        StandardPBEStringEncryptor configurationEncryptor = new StandardPBEStringEncryptor();
        configurationEncryptor.setAlgorithm("PBEWITHSHA256AND256BITAES-CBC-BC");
        configurationEncryptor.setProviderName("BC");
        configurationEncryptor.setSaltGenerator(new RandomSaltGenerator());
        configurationEncryptor.setKeyObtentionIterations(1000);
        configurationEncryptor.setPassword("aTestPassword");

        String input = "A Test String!";
        String cypherText = configurationEncryptor.encrypt(input);
        String plainText = configurationEncryptor.decrypt(cypherText);
        System.out.println("Input:" + input + " cypher:" + cypherText + " plain:" + plainText);

输出

        Input:A Test String! cypher:DhCSPbCWcZ76TUD/dDeGczlHbI9dQJyB2lKAiL7dDEk= plain:A Test String!

上面的密码字符串是我们存储在数据库中的base64编码的字符串。

我现在想尝试使用MysqL提供的AES实用程序解密存储在我们数据库中的密码字符串。

我试图了解BC提供程序如何连接加密的数据,以便可以将其拆分并重新创建所需的参数,以使我能够使用其他工具(在本例中为MysqL的AES_DECRYPT函数)解密数据。

检查代码,我可以看到密文的前16个字节(解码基数为64时是盐),我不确定初始化向量(IV)在其余的密文数据中的存储位置。

如果我们可以从字符串中解析出IV,盐和加密值,那么应该可以使用外部工具来解密数据。

一个示例MysqL AES用法如下:

        SET block_encryption_mode = 'aes-256-cbc';
        SET @key_str = SHA2('aTestPassword',256);
        SET @init_vector = RANDOM_BYTES(16);
        SET @crypt_str = AES_ENCRYPT('A Test String!',@key_str,@init_vector);
        SELECT AES_DECRYPT(@crypt_str,@init_vector);

输出

        A Test String!

我想知道如何解析BouncyCastle密码文本以获取其组成部分,以及如何使用salt以指定的迭代次数生成正确的密钥哈希,供MysqL用于解密数据。

任何帮助,不胜感激!

解决方法

此答案不是代码中的解决方案,但可以帮助您找到代码。

首先:您不是在使用Bouncy Castle直接加密/解密-当然,密码被用作加密/解密的提供者。

进行完整加密/解密的库为 JASYPT ,我们可以在此处找到您问题的答案。

我研究的基础是GitHub https://github.com/jboss-fuse/jasypt/tree/master/jasypt/src/main/java/org/jasypt/encryption/pbe,我从“ StandardPBEStringEncryptor.java”开始:

当我们试图了解我发现的使用中的加密方式

// The StandardPBEByteEncryptor that will be internally used.
private final StandardPBEByteEncryptor byteEncryptor;

,然后是加密方法:

...
// The StandardPBEByteEncryptor does its job.
byte[] encryptedMessage = this.byteEncryptor.encrypt(messageBytes);
...
if (this.stringOutputTypeBase64) {
   encryptedMessage = this.base64.encode(encryptedMessage);
   result = new String(encryptedMessage,ENCRYPTED_MESSAGE_CHARSET);
} else {
   result = CommonUtils.toHexadecimal(encryptedMessage);
}

当您获得Base64编码的字符串时,该类将仅以Base64编码返回加密消息。

让我们看一下基类“ StandardPBEByteEncryptor.java”:

搜索 iv 使用中:

// Initialization Vector to be used for encryption and decryption.
private byte[] ivInUse = null;
...
// Initialize Initialization Vector
this.ivInUse = new byte[algorithmBlockSize];

这意味着我们确实具有 16字节长的静态IV (AES的块长度),填充有“ x00”

盐:

DefaultSaltLength设置为8,但是当使用分组密码时,盐长度等于密码块大小(对于AES 16):

// The salt size for the chosen algorithm is set to be equal 
// to the algorithm's block size (if it is a block algorithm).
final int algorithmBlockSize = this.encryptCipher.getBlockSize();
if (algorithmBlockSize > 0) {
   this.saltSizeBytes = algorithmBlockSize;
}

是由saltGenerator生成的,加密后将其与密文并置,格式为salt|encryptedMessage

加密:

...
// Finally we build an array containing both the unencrypted salt
// and the result of the encryption. This is done only
// if the salt generator we are using specifies to do so.
if (this.saltGenerator.includePlainSaltInEncryptionResults()) {
   // Insert unhashed salt before the encryption result
   return CommonUtils.appendArrays(salt,encryptedMessage);
}

迭代次数是通过初始化(1000)给出的。

最后要解决的是cipher-init的算法,使用OpenJava 11时,我发现:

PBEWithHmacSHA256AndAES_256

(希望)在CBC模式下工作。