MySQL AES_ENCRYPT返回BLOB或NULL问题求助
问题与解决方案
问题背景
我有一套实现AES加解密的Java代码,现在需要用MySQL的AES_ENCRYPT函数加密数据库现有数据,但遇到两个问题:
- 执行
select AES_encrypt('0121234566', 'mySecretKey')返回BLOB格式; - 尝试用
SELECT CAST(AES_encrypt('0121234566', 'mySecretKey') AS CHAR(10000) CHARACTER SET utf8);转换时返回NULL。
Java AES加解密代码
private static SecretKeySpec secretKeySpec; private static byte[] key; private static final String ALGORITHM = "AES"; private final static String secretKey = "mySecretKey"; public void prepareSecreteKey(String theKey) { MessageDigest sha = null; try { key = theKey.getBytes(StandardCharsets.UTF_8); sha = MessageDigest.getInstance("SHA-1"); key = sha.digest(key); key = Arrays.copyOf(key, 16); System.out.println(key.toString()); secretKeySpec = new SecretKeySpec(key, ALGORITHM); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } public String doEncrypt(String strToEncrypt) { try { prepareSecreteKey(secretKey); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8"))); } catch (Exception e) { throw new SecurityException("Wrong Secret key to do cipher!" + e.toString()); } } public String doDecrypt(String strToDecrypt) { try { prepareSecreteKey(secretKey); String test = secretKeySpec.getFormat().toString(); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt))); } catch (Exception e) { throw new SecurityException("Wrong Secret key to do cipher!" + e.toString()); } }
问题原因
- 返回BLOB的原因:
AES_ENCRYPT的设计就是返回二进制加密结果,BLOB是MySQL存储二进制数据的标准类型,属于正常现象。 - CAST转CHAR返回NULL的原因:加密后的二进制数据包含大量非UTF-8编码兼容的字节,直接强制转换为UTF-8字符会因为编码无效返回NULL。
解决方案
1. 正确查看/转换加密结果
不要用CAST转UTF-8,改用TO_BASE64将二进制加密结果转换为可打印的Base64字符串(和Java代码输出格式一致):
SELECT TO_BASE64(AES_ENCRYPT('0121234566', @processed_key)) AS encrypted_str;
解密时则先用FROM_BASE64还原为二进制,再解密:
SELECT AES_DECRYPT(FROM_BASE64(encrypted_str), @processed_key) AS decrypted_str;
2. 确保MySQL与Java密钥兼容
你的Java代码对密钥做了特殊处理:将原始密钥转UTF-8字节→SHA-1哈希→截取前16字节作为AES密钥。MySQL默认直接使用原始密钥的字节(长度不符时补0/截断),因此需要在MySQL中生成完全一致的密钥:
-- 生成与Java代码兼容的16字节AES密钥 SET @processed_key = SUBSTRING(SHA1('mySecretKey'), 1, 16);
使用这个处理后的密钥执行加密,得到的Base64结果可以直接用Java的doDecrypt方法解密,反之Java加密的结果也能在MySQL中正确解密。
3. 数据库存储建议
如果要持久化加密数据,推荐直接用BLOB类型存储二进制加密结果,比存储Base64字符串更节省存储空间。需要查看时再用TO_BASE64转换即可。
内容的提问来源于stack exchange,提问作者Teong
相关产品推荐
相关产品推荐

