当前位置: 首页 > news >正文

Java与MySQL AES加密解密实战指南

Java 与 MySQL 中的 AES 加密解密实践

本指南提供了两种在 MySQL 数据库中处理敏感数据 AES 加密的核心方法:

  • 数据库层:直接在 MySQL 中使用原生 SQL 函数进行加解密。
  • 应用层:在 Java 应用程序中完成加解密,数据库仅负责存储。

一、MySQL 原生 AES 加解密 (SQL 实现)

这种方法利用 MySQL 内置的 AES_ENCRYPT()AES_DECRYPT() 函数,直接在数据库层面完成加解密操作。我们使用 dual 虚表进行演示,它不需要实际创建表。

核心函数

  • AES_ENCRYPT(str, key_str): 使用密钥 key_str 加密字符串 str,返回二进制结果。
  • AES_DECRYPT(crypt_str, key_str): 使用密钥 key_str 解密二进制密文 crypt_str
  • HEX(binary_str): 将二进制字符串转换为十六进制格式,方便存储和查看。
  • UNHEX(hex_str): HEX() 的逆操作,将十六进制字符串转回二进制。

SQL 操作示例

-- 1. 加密: 将字符串 'data' 用密钥 'myKey' 加密,并转换为十六进制字符串
SELECT HEX(AES_ENCRYPT('data', 'myKey')) FROM dual;-- 2. 解密: 直接解密 AES_ENCRYPT 的结果。
-- 注意:AES_DECRYPT 返回的是二进制,需要 CAST 转换为可读字符。
SELECT CAST(AES_DECRYPT(AES_ENCRYPT('data', 'myKey'), 'myKey') AS CHAR) FROM dual;-- 3. 解密存储的十六进制字符串:
-- 假设 '4E4632...' 是从数据库字段中读取的加密后的十六进制值
-- 需要先用 UNHEX 转回二进制,再进行解密。
-- SELECT CAST(AES_DECRYPT(UNHEX('your_encrypted_hex_string'), 'myKey') AS CHAR) FROM dual;

二、Java 中实现

方式一:在 Java 中调用 SQL 加解密函数

这种方式下,Java 代码负责构建和执行带有 AES_ENCRYPT/AES_DECRYPT 函数的 SQL 语句,将加解密工作委托给 MySQL 数据库处理。

  • 加密:Java 程序执行 SELECT HEX(AES_ENCRYPT(?, ?)),将明文和密钥作为参数传入,从数据库获取加密后的十六进制字符串。
  • 解密:Java 程序执行 SELECT CAST(AES_DECRYPT(UNHEX(?), ?) AS CHAR),将密文和密钥作为参数传入,从数据库获取解密后的明文。

方式二:使用 Java 工具类进行加解密

这种方式将加解密逻辑完全封装在 Java 应用中,与数据库解耦。数据库仅作为加密字符串的存储介质。

  • 加密:在 Java 代码中调用工具类方法(如 MySqlAesUtils.encrypt)将明文加密成 Base64 或十六进制字符串,然后通过标准的 INSERT/UPDATE 语句存入数据库。
  • 解密:先从数据库查出加密字符串,然后在 Java 代码中调用工具类方法(如 MySqlAesUtils.decrypt)将其解密为明文。
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;public class MySqlAesUtils {private static final String ALGORITHM = "AES";private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";private static Key secretKey;/*** 加密,对应 MySQL 的 SELECT hex(AES_ENCRYPT(data, key))** @param data 待加密的数据* @return 加密后的十六进制字符串*/public static String encrypt(String data) {if (data == null || data.isEmpty()) {return data;}try {Cipher cipher = Cipher.getInstance(TRANSFORMATION);cipher.init(Cipher.ENCRYPT_MODE, secretKey);byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));return bytesToHex(encryptedBytes);} catch (Exception e) {// 在实际项目中,这里应该记录日志并抛出自定义异常throw new RuntimeException("AES 加密失败", e);}}/*** 解密,对应 MySQL 的 SELECT AES_DECRYPT(UNHEX(data), key)** @param hexData 十六进制表示的加密数据* @return 解密后的原始字符串*/public static String decrypt(String hexData) {if (hexData == null || hexData.isEmpty()) {return hexData;}try {Cipher cipher = Cipher.getInstance(TRANSFORMATION);cipher.init(Cipher.DECRYPT_MODE, secretKey);byte[] decryptedBytes = cipher.doFinal(hexToBytes(hexData));return new String(decryptedBytes, StandardCharsets.UTF_8);} catch (Exception e) {// 在实际项目中,这里应该记录日志并抛出自定义异常throw new RuntimeException("AES 解密失败", e);}}/*** 生成与 MySQL 兼容的 AES 密钥。*/private static Key generateMySQLKey(String key) {final byte[] keyBytes = new byte[16];final byte[] providedKeyBytes = key.getBytes(StandardCharsets.UTF_8);System.arraycopy(providedKeyBytes, 0, keyBytes, 0, Math.min(providedKeyBytes.length, keyBytes.length));if (providedKeyBytes.length > 16) {for (int i = 16; i < providedKeyBytes.length; i++) {keyBytes[i % 16] ^= providedKeyBytes[i];}}return new SecretKeySpec(keyBytes, ALGORITHM);}/*** 字节数组转十六进制字符串*/private static String bytesToHex(byte[] bytes) {StringBuilder sb = new StringBuilder();for (byte b : bytes) {sb.append(String.format("%02X", b));}return sb.toString();}/*** 十六进制字符串转字节数组*/private static byte[] hexToBytes(String hex) {int len = hex.length();byte[] data = new byte[len / 2];for (int i = 0; i < len; i += 2) {data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)+ Character.digit(hex.charAt(i + 1), 16));}return data;}public static void main(String[] args) {// 设置密钥secretKey = generateMySQLKey("mySecretKey");// 测试数据String originalData = "Hello, World!";System.out.println("原始数据: " + originalData);// 加密String encryptedData = encrypt(originalData);System.out.println("加密后数据: " + encryptedData);// 解密String decryptedData = decrypt(encryptedData);System.out.println("解密后数据: " + decryptedData);// 验证if (originalData.equals(decryptedData)) {System.out.println("测试通过:原始数据与解密后数据一致。");} else {System.out.println("测试失败:原始数据与解密后数据不一致。");}}
}

三、关键注意事项:密钥管理

无论使用哪种方法,密钥的安全都是最重要的。

绝对不要将密钥硬编码在代码或 SQL 中!

推荐的密钥管理方式

  • 配置文件: 将密钥存储在项目外部的配置文件中(如 .properties, .yml)。
  • 环境变量: 将密钥存储在服务器的环境变量中,程序启动时读取。
  • 密钥管理服务 (KMS): 使用云服务商提供的专业密钥管理服务。
http://www.dtcms.com/a/308534.html

相关文章:

  • pytest vs unittest: 区别与优缺点比较
  • #C语言——学习攻略:深挖指针路线(五)--回调函数,qsort函数,qsort函数的模拟实现
  • ACOSRAR改进连续蚁群算法用于优化复杂环境下无人机路径规划,Matlab代码实现
  • 中烟创新参编的《软件和信息技术服务行业企业环境社会治理信息披露指南》标准正式发布
  • 树形DP-核心基础
  • 《质光相济:Three.js中3D视觉的底层交互逻辑》
  • 直击WAIC | 百度袁佛玉:加速具身智能技术及产品研发,助力场景应用多样化落地
  • 虚幻基础:模型穿模
  • 产品型号:PCD231B101产品类型:信号隔离转换模块
  • Redis学习14-认识哨兵机制
  • cesium视锥体
  • 【C#】基于SharpCompress实现压缩包解压功能
  • TDengine 中 TDgp 中添加算法模型(预测分析)
  • Spring Security之初体验
  • 智慧社区项目开发(四)——前后端登录认证相关功能实现解析
  • QT Word模板 + QuaZIP + LibreOffice,跨平台方案实现导出.docx文件后再转为.pdf文件
  • 安全月报 | 傲盾DDoS攻击防御2025年7月简报
  • 功能强大编辑器
  • [Agent开发平台] 可观测性(追踪与指标) | 依赖注入模式 | Wire声明式配置
  • 量子安全:微算法科技(MLGO)基于比特币的非对称共识链算法引领数字经济未来
  • Linux安装AnythingLLM
  • 【ad-hoc构造】P10033 「Cfz Round 3」Sum of Permutation|普及+
  • langchain--1--prompt、output格式、LCEL示例
  • 2025年7月最新一区SCI-基尔霍夫定律优化算法Kirchhoff’s law algorithm-附Matlab免费代码
  • FastGPT + Kymo AI生态创新平台,搭建企业智能化知识管理
  • XPATH选择器常用语法
  • langchain从入门到精通(四十二)——全面剖析之Memory
  • 机器学习①【机器学习的定义以及核心思想、数据集:机器学习的“燃料”(组成和获取)】
  • 深度学习基础—2
  • [人工智能-综述-17]:AI革命:重塑职业版图,开启文明新篇