MySQL与Java AES-256-CBC加解密互操作问题咨询
解密失败核心原因
你解密不成功是两个参数对齐问题导致的:
- 密钥格式不匹配:你当前Java代码用
toString()获取的是SHA-256哈希的十六进制字符串(长度64字节),但MySQL的SHA2()函数直接返回32字节长度的原始二进制哈希值,刚好是AES-256要求的256位密钥长度,二者字节级完全不一致,必然解密失败。 - 加密配置未对齐:没有严格匹配MySQL使用的IV、填充规则。
实现方案
不需要依赖Bouncy Castle,JDK自带的加密API就可以实现,只要严格对齐以下规则即可:
- 密钥生成:调用Guava哈希工具的
asBytes()方法,直接获取32字节的原始SHA-256哈希值作为密钥,不要用toString()转十六进制字符串。 - IV配置:MySQL
aes_encrypt的第三个参数就是CBC模式的初始化向量,直接将你传入的字符串ssshhhhhhhhhhh!!以UTF-8编码转成字节数组作为IV即可,长度刚好为AES要求的16字节。 - 算法与填充:算法模式指定为
AES/CBC/PKCS5Padding,MySQL的aes-256-cbc默认使用PKCS7填充,Java中块大小为16字节时PKCS5Padding与PKCS7完全兼容,可以直接使用。 - 密文处理:MySQL侧加密结果是二进制,通过
to_base64()转成了Base64字符串,Java端解密前先对Base64串解码得到原始密文字节数组,解密后再转成UTF-8字符串即可得到明文。
可直接运行的代码示例
import com.google.common.hash.Hashing; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Base64; public class MysqlAesUtil { public static void main(String[] args) throws Exception { // 生成和MySQL字节级一致的AES-256密钥 byte[] keyBytes = Hashing.sha256() .hashString("ssshhhhhhhhhhh!!ENCRYPTION_KEY$&", StandardCharsets.UTF_8) .asBytes(); SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES"); // 构造和MySQL一致的IV byte[] ivBytes = "ssshhhhhhhhhhh!!".getBytes(StandardCharsets.UTF_8); IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); // 初始化解密器 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec); // 测试解密你给出的示例密文 String cipherTextBase64 = "StThdNXA+CWvlg+of/heJQ=="; byte[] cipherBytes = Base64.getDecoder().decode(cipherTextBase64); byte[] plainBytes = cipher.doFinal(cipherBytes); System.out.println(new String(plainBytes, StandardCharsets.UTF_8)); // 输出结果为 test_value } }
注意事项
- JDK8u161及以上版本默认支持AES-256加密,不需要修改加密策略文件;低版本JDK如果报密钥长度非法,需要替换JRE目录下的无限制加密策略文件。
- 不要对密钥、IV做任何额外的哈希、补位转换,保证和MySQL侧传入值的字节序列完全一致即可。
- 加密操作和上述逻辑一致,只要把Cipher初始化模式改成
ENCRYPT_MODE,最后对加密结果做Base64编码,就能得到和MySQLto_base64(aes_encrypt(...))完全一致的输出。
内容的提问来源于stack exchange,提问作者Barath
相关产品推荐
相关产品推荐

