我想编写一个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);
答案 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的问题。