AES加密方法相当于MySQL aes_encrypt()函数

时间:2013-10-22 12:53:17

标签: java mysql encryption aes

我想编写一个AES加密方法,该方法应该等同于mysql aes_encrypt

我尝试写但是它不正确,因为mysql也没有给出正确的数据。

我该怎么做才能弄清楚?

Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec); 
byte[] encryptedTextBytes = cipher.doFinal(message .getBytes("UTF-8")); 
String k = new String(encryptedTextBytes); 
System.out.println("KKKKK"+k);

4 个答案:

答案 0 :(得分:7)

MySQL的AES实现给很多人带来了麻烦。这主要是因为MySQL如何处理加密密钥。加密密钥被分成16字节块,MySQL将从一个块中对前一个块中的字节进行异或。如果用户提供的密钥长度小于16个字节,那么密钥基本上用空字节填充以获得最多16个字节。这就是MySQL的aes_encrypt()处理密钥的方式。

通过使用PKCS7填充数据,也可以处理要加密的值。您可以了解PKCS7 @ http://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS7的所有内容,但它所做的只是填充输入数据,因此它是16字节块。数据被填充的字节等于将要添加的填充字节数。

长话短说,您需要按照MySQL的方式处理加密密钥,并使用PKCS7填充输入数据。

请参阅Michael Simmons的以下帖子,了解Java中的示例代码: http://info.michael-simons.eu/2011/07/18/mysql-compatible-aes-encryption-decryption-in-java/

答案 1 :(得分:1)

几年前我不得不使用BouncyCastle这样做。正如Alen Puzic的回答所述,两个问题是mysql密钥生成和PKCS7填充。 BouncyCastle将使用PaddedBufferedBlockCipher为您处理填充,但您需要自己生成密钥。以下是执行此操作的代码:

/**
 * Use password to generate a MySQL AES symmetric key
 * @param passwd Password String to use.
 * @param keyLength Must be evenly divisible by 8.
 * @return Key for use with MySQL AES encrypt/decrypt fuctions.
 */
public static KeyParameter getMySqlAESPasswdKey(String passwd, int keyLength) {
    byte[] pword = passwd.getBytes();
    byte[] rawKey = new byte[keyLength/8];
    int j = 0;
    for (int i = 0; i < pword.length; i++, j++) {

        if(j==rawKey.length) {
            j = 0;
        }
        rawKey[j] = pword[i];
    }

    return new KeyParameter(rawKey);
}

请注意,mysql的默认keyLength为128。

使用上述方法生成KeyParameter,您可以使用以下方法完成加密/解密。

/**
 * Password based encryption using AES with MySql style key generation.
 * @param toEncrypt Unencrypted byte array.
 * @param key A KeyParameter generated with the getMySqlAESPasswdKey() method.
 * @return Encrypted byte array.
 * @throws InvalidCipherTextException If provided key cannot be used with this method on the provided data.
 */
public static byte[] mysqlAesPasswdEncrypt (byte [] toEncrypt, KeyParameter key) throws InvalidCipherTextException {
    BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new AESFastEngine());

    cipher.init(true, key);
    byte[] result = new byte[cipher.getOutputSize(toEncrypt.length)];
    int len = cipher.processBytes(toEncrypt, 0, toEncrypt.length, result, 0);
    cipher.doFinal(result, len);
    return result;
}

/**
 * Password based decryption using AES with MySql style key generation.
 * @param toDecrypt Encrypted byte array.
 * @param key A KeyParameter generated with the getMySqlAESPasswdKey() method.
 * @return Unencrypted byte array.
 * @throws InvalidCipherTextException If provided key cannot be used with this method on the provided data.
 */
public static byte[] mysqlAesPasswdDecrypt (byte [] toDecrypt, KeyParameter key) throws InvalidCipherTextException {
    BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new AESFastEngine());

    cipher.init(false, key);
    byte[] result = new byte[cipher.getOutputSize(toDecrypt.length)];
    int len = cipher.processBytes(toDecrypt, 0, toDecrypt.length, result, 0);
    cipher.doFinal(result, len);
    return stripTrailingZeros(result);
}

/**
 * Strip trailling zeros from the end of decrypted byte arrays.
 * @param data Data to strip.
 * @return Stripped data.
 */
public static byte[] stripTrailingZeros(byte[] data) {
    int lastData = data.length-1;
    for (int i = data.length-1; i >= 0; i--) {
        if(data[i]!=(byte)0) {
            lastData = i;
            break;
        }
    }

    byte[] data2 = new byte[lastData+1];
    System.arraycopy(data, 0, data2, 0, lastData+1);
    return data2;
}

答案 2 :(得分:0)

感谢您的洞察力,最后做对了,这是一个简单的python版本:

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding
import codecs


def encrypt(data, key):
    key = key + b"\0" * (16 - len(key) % 16)
    padder = padding.PKCS7(128).padder()
    data = padder.update(data) + padder.finalize()
    alg = algorithms.AES(key)
    cipher = Cipher(alg, modes.ECB(), default_backend())
    encryptor = cipher.encryptor()
    ct = encryptor.update(data) + encryptor.finalize()
    return ct


if __name__ == '__main__':
    enc = encrypt(b'123456', b'1234567890')
    print(codecs.encode(enc, 'hex'))

答案 3 :(得分:-1)

我建议使用the Bouncy Castle Java加密API。 BC被广泛认为是一个很好的加密工具包,如果你愿意,它可以作为加密提供程序插入Java API。我知道这并没有直接回答你的问题,但我从未见过有人遇到过Bouncy Castle的问题。