You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL AES_ENCRYPT返回BLOB或NULL问题求助

问题与解决方案

问题背景

我有一套实现AES加解密的Java代码,现在需要用MySQL的AES_ENCRYPT函数加密数据库现有数据,但遇到两个问题:

  1. 执行select AES_encrypt('0121234566', 'mySecretKey')返回BLOB格式;
  2. 尝试用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());
    }
}

问题原因

  1. 返回BLOB的原因:AES_ENCRYPT的设计就是返回二进制加密结果,BLOB是MySQL存储二进制数据的标准类型,属于正常现象。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 07:58:03