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

MySQL与Java实现AES-128-CBC无盐加密一致性问题求助

MySQL与Java AES-CBC加密一致性问题

我正在分别在MySQL和Java中实现AES加密,MySQL的加密脚本如下,其中AES_ENCRYPT函数不需要盐字节,密钥和IV是通过SHA2哈希后截取16位得到的:

SET session block_encryption_mode = 'aes-128-cbc';
SET @key_str = LEFT(UNHEX(SHA2('My secret passphrase',256)),16);
AES_ENCRYPT(COLUMN_NAME,@key_str,LEFT(UNHEX(SHA2(IV,256)),16)) 

但用Java实现时,一开始用了PBEKeySpec(要求必须传盐),导致两边密文不一致,我的初始Java代码如下:

byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
IvParameterSpec ivspec = new IvParameterSpec(iv);

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(SECRET_KEY.toCharArray(), SALT.getBytes(), 2, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);

解决方案

要让Java和MySQL生成相同密文,必须完全对齐两者的密钥、IV生成逻辑,以及加密规则,具体修改如下:

  1. 替换密钥生成逻辑
    MySQL中密钥是直接对密码做SHA2-256哈希后取前16字节,不需要PBKDF2这种带盐的密钥派生算法,Java要按同样方式生成密钥:
// 生成和MySQL一致的AES-128密钥
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
byte[] keyHash = sha256.digest("My secret passphrase".getBytes(StandardCharsets.UTF_8));
byte[] keyBytes = Arrays.copyOf(keyHash, 16); // 截取前16字节
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
  1. 对齐IV生成逻辑
    MySQL的IV是对指定字符串做SHA2-256哈希后取前16字节,Java也要遵循这个逻辑,不能用固定的全0数组:
// 生成和MySQL一致的IV
byte[] ivHash = sha256.digest("你的IV字符串".getBytes(StandardCharsets.UTF_8));
byte[] ivBytes = Arrays.copyOf(ivHash, 16);
IvParameterSpec ivspec = new IvParameterSpec(ivBytes);
  1. 确认加密模式与填充
    MySQL的aes-128-cbc默认使用PKCS#7填充,这和Java的PKCS5Padding兼容(PKCS5是PKCS7的子集,针对8字节块),所以原代码中Cipher.getInstance("AES/CBC/PKCS5Padding")无需修改。

  2. 完整可运行Java代码

import java.security.MessageDigest;
import java.security.spec.IvParameterSpec;
import java.security.spec.SecretKeySpec;
import javax.crypto.Cipher;
import java.util.Arrays;
import java.nio.charset.StandardCharsets;

public class AESEncryption {
    public static void main(String[] args) throws Exception {
        String plaintext = "需要加密的内容";
        String passphrase = "My secret passphrase";
        String ivInput = "你的IV字符串";

        // 生成密钥
        MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
        byte[] keyHash = sha256.digest(passphrase.getBytes(StandardCharsets.UTF_8));
        byte[] keyBytes = Arrays.copyOf(keyHash, 16);
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");

        // 生成IV
        byte[] ivHash = sha256.digest(ivInput.getBytes(StandardCharsets.UTF_8));
        byte[] ivBytes = Arrays.copyOf(ivHash, 16);
        IvParameterSpec ivspec = new IvParameterSpec(ivBytes);

        // 执行加密
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
        byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

        // 转成MySQL兼容的十六进制字符串(可选)
        String hexCiphertext = bytesToHex(ciphertext);
        System.out.println(hexCiphertext);
    }

    // 辅助方法:字节数组转十六进制
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
}

内容的提问来源于stack exchange,提问作者Muddassir Rahman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:12:23