暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL AES 加密/解密简单实践

00后DBA实录 2025-12-01
89

Wallpaper Engine:山田凉(山田 リョウ)



前言

前不久遇到有人问我 M 怎么做加密处理,简单聊聊

加密解密函数

首先简单说说加密和解密函数。

AES_ENCRYPT(str,key_str[,init_vector][,kdf_name][,salt][,info | iterations])

具体参考:https://dev.mysql.com/doc/refman/8.4/en/encryption-functions.html#function_aes-encrypt

  • str:需要加密的内容
  • key_str:加密密钥

其他我们这里没用到不详细描述,都是 KDF 相关的

AES_DECRYPT 类似

AES_DECRYPT(crypt_str,key_str[,init_vector][,kdf_name][,salt][,info | iterations])

  • crypt_str 是加密后的加密串
  • key_str:加密密钥

具体参考:https://dev.mysql.com/doc/refman/8.4/en/encryption-functions.html#function_aes-decrypt

字段为 VARCHAR 类型

测试表

root@localhost [aes] 18:52:41 > create table encode_1(id int auto_increment primary key,text varchar(200));
Query OK, 0 rows affected (0.25 sec)

插入带密钥的加密数据

root@localhost [aes] 18:53:29 > insert into encode_1 values(2, TO_BASE64(AES_ENCRYPT('需要加密的内容','My KEY')));
Query OK, 1 row affected (0.08 sec)

注意:细心的小伙伴应该看到多了一个 TO_BASE64 函数,这个后面解释

查询时解密

root@localhost [aes] 18:53:37 >  select CAST(AES_DECRYPT(FROM_BASE64(text),'My KEY') AS CHAR) from encode_1 where id = 2;
+-------------------------------------------------------+
| CAST(AES_DECRYPT(FROM_BASE64(text),'My KEY') AS CHAR) |
+-------------------------------------------------------+
| 需要加密的内容                                        |
+-------------------------------------------------------+
1 row in set (0.01 sec)

直接查是加密状态:

root@localhost [aes] 18:53:44 > select * from encode_1;
+----+----------------------------------------------+
| id | text                                         |
+----+----------------------------------------------+
|  2 | WUYLkCqcxHGmlvPoH8xh/MORGcHWTbjcqxhnhi1BOaI= |
+----+----------------------------------------------+
1 row in set (0.00 sec)

给错密钥返回 NULL

root@localhost [aes] 18:53:52 > select CAST(AES_DECRYPT(FROM_BASE64(text),'Other KEY') AS CHAR) from encode_1 where id = 2;
+----------------------------------------------------------+
| CAST(AES_DECRYPT(FROM_BASE64(text),'Other KEY') AS CHAR) |
+----------------------------------------------------------+
| NULL                                                     |
+----------------------------------------------------------+
1 row in set (0.00 sec)

ERROR 1366 (HY000): Incorrect string value 解释

如果不用 TO_BASE64 函数会使插入报错以下内容:

root@localhost [aes] 19:09:25 > insert into encode_1 values(3, AES_ENCRYPT('需要加密的内容','My KEY'));
ERROR 1366 (HY000): Incorrect string value: '\x90*\x9C\xC4q\xA6...' for column 'text' at row 1

因为 AES_ENCRYPT()
 返回的是二进制数据(VARBINARY),如果字段定义为 VARCHAR
 或 CHAR
,MySQL 会尝试将二进制数据转换为字符串,导致字符集冲突产生警告。

我们这里将内容转为 BASE64 就可以存进去了,当然查的时候也要先解开 BASE64 再解密

字段为 VARBINARY 类型

测试表

root@localhost [aes] 19:09:26 > create table encode_2(id int auto_increment primary key,text VARBINARY(200));
Query OK, 0 rows affected (0.12 sec)

VARBINARY 类型就不需要转 BASE64 了,直接插入就可以了,BINARY 表示插入的是 BINARY 字符集串,当然用 CAST(xx as BINARY )
 也是一样的

root@localhost [aes] 19:13:34 > insert into encode_2 values(1, BINARY AES_ENCRYPT('需要加密的内容','My KEY'));
Query OK, 1 row affected, 1 warning (0.03 sec)

查询:

root@localhost [aes] 19:13:47 > select CAST(AES_DECRYPT(text,'My KEY') AS CHAR) from encode_2 where id = 1;
+------------------------------------------+
| CAST(AES_DECRYPT(text,'My KEY') AS CHAR) |
+------------------------------------------+
| 需要加密的内容                           |
+------------------------------------------+
1 row in set (0.00 sec)

使用其他密钥

root@localhost [aes] 19:14:09 > select CAST(AES_DECRYPT(text,'Other KEY') AS CHAR) from encode_2 where id = 1;
+---------------------------------------------+
| CAST(AES_DECRYPT(text,'Other KEY') AS CHAR) |
+---------------------------------------------+
| NULL                                        |
+---------------------------------------------+
1 row in set (0.00 sec)

直接查询是加密串

root@localhost [aes] 19:14:04 > select text from encode_2 where id = 1;
+--------------------------------------------------------------------+
| text                                                               |
+--------------------------------------------------------------------+
| 0x59460B902A9CC471A696F3E81FCC61FCC39119C1D64DB8DCAB1867862D4139A2 |
+--------------------------------------------------------------------+
1 row in set (0.00 sec)

看到字段有个 0x ,一般 0x 是十六进制,用 UNHEX 试一下:

root@localhost [aes] 19:14:13 >  select UNHEX(text) from encode_2 where id = 1;
+--------------------------+
| UNHEX(text)              |
+--------------------------+
| NULL                     |
+--------------------------+
1 row in set, 1 warning (0.00 sec)

root@localhost [aes] 19:14:29 > show warnings;
+---------+------+----------------------------------------------------------------------+
| Level   | Code | Message                                                              |
+---------+------+----------------------------------------------------------------------+
| Warning | 1411 | Incorrect string value: '`aes`.`encode_2`.`text`' for function unhex |
+---------+------+----------------------------------------------------------------------+
1 row in set (0.00 sec)

当然不行了

参考

https://dev.mysql.com/doc/refman/8.4/en/encryption-functions.html#function_aes-encrypt

https://dev.mysql.com/doc/refman/8.4/en/encryption-functions.html#function_aes-decrypt


文章转载自00后DBA实录,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论