MySQL利用AES_ENCRYPT()与AES_DECRYPT()加解密的正确方法示例

前言

最近在工作中遇到一个需求是这样的:需要在使用AES_ENCRYPT()函数将明文加密,存储在MySQL中,但是遇到了一些问题……下面就来详细介绍下。

说将加密后的密文,解密取出来是NULL。

看了一下,她发过来的表结构:

再看了她通过AES_DECRYPT()函数加密了一个字符串,然后insert进去了,执行成功后,显示了一个warning:
Query OK, 1 row affected, 1 warning (0.00 sec)

(没有报错而是warning,大概是sql_mode的缘故)

此时她忽略了这个warning,再通过AES_DECRYPT()解密后,发现取出来的明文为NULL。

再回看表结构,发现其字段属性为“varchar” && 字符集是ut8,检查warning为下:

mysql> show warnings;
+---------+------+------------------------------------------------------------------------+
| Level | Code | Message        |
+---------+------+------------------------------------------------------------------------+
| Warning | 1366 | Incorrect string value: '\xE3f767\x12...' for column 'passwd' at row 1 |
+---------+------+------------------------------------------------------------------------+
1 row in set (0.00 sec)

查了一下文档,看一下这两个函数的使用:

-- 将'hello world'加密,密钥为'key',加密后的串存在@pass中
mysql> SET @pass=AES_ENCRYPT('hello world', 'key');
Query OK, 0 rows affected (0.00 sec)

-- 看一下加密后串的长度(都为2的整数次方)
mysql> SELECT CHAR_LENGTH(@pass);
+--------------------+
| CHAR_LENGTH(@pass) |
+--------------------+
| 16   |
+--------------------+
1 row in set (0.00 sec)

-- 使用AES_DECRYPT()解密
mysql> SELECT AES_DECRYPT(@pass, 'key');
+---------------------------+
| AES_DECRYPT(@pass, 'key') |
+---------------------------+
| hello world  |
+---------------------------+
1 row in set (0.00 sec)

那么到底该如何存呢?

方法①:

将字段属性设置为varbinary/binary/四个blob类型,等二进制字段属性。

创建三个字段,属性分别为varbinary、binary、blob。

并将'明文1','text2','明文_text3'加密,密钥为key,存入表中。

最后取出。

mysql> CREATE TABLE t_passwd (pass1 varbinary(16), pass2 binary(16), pass3 blob);
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t_passwd VALUES (AES_ENCRYPT('明文1', 'key'), AES_ENCRYPT('text2', 'key'), AES_ENCRYPT('明文_text3', 'key'));
Query OK, 1 row affected (0.01 sec)

mysql> SELECT AES_DECRYPT(pass1, 'key'), AES_DECRYPT(pass2, 'key'), AES_DECRYPT(pass3, 'key') FROM t_passwd;
+---------------------------+---------------------------+---------------------------+
| AES_DECRYPT(pass1, 'key') | AES_DECRYPT(pass2, 'key') | AES_DECRYPT(pass3, 'key') |
+---------------------------+---------------------------+---------------------------+
| 明文1   | text2   | 明文_text3   |
+---------------------------+---------------------------+---------------------------+
1 row in set (0.00 sec)

当然,属性括号内的长度要取决于明文的长度,此处明文较短,故只给了16。

方法②:

将密文十六进制化,再存入varchar/char列。

此处需要用到HEX()来存入,用UNHEX()取出。

创建一个字符串属性的字段。

将'hello world'先用密钥'key2'进行AES加密,再将加密后的串通过HEX函数十六进制化。

最后先将加密后的串通过UNHEX取出,再通过AES据密钥'key2'解密:

mysql> CREATE TABLE t_passwd_2(pass1 char(32));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO t_passwd_2 VALUES (HEX(AES_ENCRYPT('hello world', 'key2')));
Query OK, 1 row affected (0.00 sec)

mysql> SELECT AES_DECRYPT(UNHEX(pass1), 'key2') FROM t_passwd_2;
+-----------------------------------+
| AES_DECRYPT(UNHEX(pass1), 'key2') |
+-----------------------------------+
| hello world   |
+-----------------------------------+
1 row in set (0.00 sec)

同样,根据明文的长度不同,AES_ENCRYPT加密后的串长度也会有所变化,所以HEX后的字符串长度也会有所变化。
实际使用时,需要据业务评估出一个合理值即可。

方法③:

直接存入varchar中,不做十六进制化。

回溯到问题的一开始,将加密后的串,存到utf8字符集并且属性为varchar中,是不行的。

实际上,将字符集改成latin1就可以了:

在insert的时候也不会报warning了。

mysql> CREATE TABLE t_passwd_3(pass varchar(32)) CHARSET latin1;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t_passwd_3 SELECT AES_ENCRYPT('text', 'key3');
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0

mysql> SELECT AES_DECRYPT(pass, 'key3') FROM t_passwd_3;
+---------------------------+
| AES_DECRYPT(pass, 'key3') |
+---------------------------+
| text   |
+---------------------------+
1 row in set (0.00 sec)

这样的方法虽然美,只需将字段字符集设置为latin1就可以了,但可能会带来隐患:

文档上写了这样的一句:

Many encryption and compression functions return strings for which the result might contain arbitrary byte values. If you want to store these results, use a column with a VARBINARY or BLOB binary string data type. This will avoid potential problems with trailing space removal or character set conversion that would change data values, such as may occur if you use a nonbinary string data type (CHAR, VARCHAR, TEXT).

大意是,如果用方法③那样,直接将加密后的串存入char/varchar/text类型中,在做字符转换的时或空格被删除时,可能会带来潜在的影响。

所以如果一定要存在char/varchar/text中,那么还是参考方法②,十六进制化一下吧。

或者如同方法①,直接存在二进制字段中。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

参考文档:

Chapter 12 Functions and Operators - 12.13 Encryption and Compression Functions

(0)

相关推荐

  • MySQL加密和解密实例详解

    MySQL加密和解密实例详解 数据加密.解密在安全领域非常重要.对程序员而言,在数据库中以密文方式存储用户密码对入侵者剽窃用户隐私意义重大. 有多种前端加密算法可用于数据加密.解密,下面我向您推荐一种简单的数据库级别的数据加密.解密解决方案.以MySQL数据库为例,它内建了相应的加密函数(AES_ENCRYPT() )和解密函数(AES_DECRYPT()). 在建表的时候,要注意字段的类型.如下图所示: 在表中插入加密数据 上面的插入语句有三个字段,"用户名"."密码&qu

  • MySQL 加密/压缩函数

    这些问题可能导致数据值的改变.一般而言,上述问题可能在你使用非二进制串数据类型(如char,varchar,text等数据类型)的情况下发生. AES_ENCRYPT()和AES_DECRYPT() AES_ENCRYPT()和AES_DECRYPT()可以加密/解密使用官方AES算法的数据.该算法使用128位密钥来编码,但用户可以将其扩展到256位.MySQL选用128位密钥,因为这样算法实现更快,而且对大多数用户而言它也足够安全了. AES_ENCRYPT(str,key_str)函数加密一

  • mysql双向加密解密方式用法详解

    如果你使用的正是mysql数据库,那么你把密码或者其他敏感重要信息保存在应用程序里的机会就很大.保护这些数据免受黑客或者窥探者的获取是一个令人关注的重要问题,因为您既不能让未经授权的人员使用或者破坏应用程序,同时还要保证您的竞争优势.幸运的是,MySQL带有很多设计用来提供这 种类型安全的加密函数.本文概述了其中的一些函数,并说明了如何使用它们,以及它们能够提供的不同级别的安全. 双向加密 就让我们从最简单的加密开始:双向加密.在这里,一段数据通过一个密钥被加密,只能够由知道这个密钥的人来解密.

  • MySQL利用AES_ENCRYPT()与AES_DECRYPT()加解密的正确方法示例

    前言 最近在工作中遇到一个需求是这样的:需要在使用AES_ENCRYPT()函数将明文加密,存储在MySQL中,但是遇到了一些问题--下面就来详细介绍下. 说将加密后的密文,解密取出来是NULL. 看了一下,她发过来的表结构: 再看了她通过AES_DECRYPT()函数加密了一个字符串,然后insert进去了,执行成功后,显示了一个warning: Query OK, 1 row affected, 1 warning (0.00 sec) (没有报错而是warning,大概是sql_mode的

  • java加解密RSA使用方法代码示例

    最近为了分析一段请求流,不得不去研究一下RSA加密. 首先,强调一点:密钥的"钥"读"yue",不是"yao",额... 网上关于RSA的原理一抓一大把的,这里只是简单说说我的理解: 1. 两个足够大的互质数p, q: 2. 用于模运算的模 n=p*q: 3. 公钥KU(e, n)中的e满足 1<e< (p-1)(q-1),且与(p-1)(q-1)互质: 4. 密钥KR(d, n)中的d满足  d*e % (p-1)(q-1)= 1,

  • Android框架Volley之利用Imageloader和NetWorkImageView加载图片的方法

    首先我们在项目中导入这个框架: implementation 'com.mcxiaoke.volley:library:1.0.19' 在AndroidManifest文件当中添加网络权限: <uses-permission android:name="android.permission.INTERNET"/> 下面是我们的首页布局: 在这个布局当中我们将Volley框架的所有功能都做成了一个按钮,按下按钮之后就会在"显示结果"下面显示结果,显示结果下

  • MySQL利用索引优化ORDER BY排序语句的方法

    创建表&创建索引 create table tbl1 ( id int unique, sname varchar(50), index tbl1_index_sname(sname desc) ); 在已有的表创建索引语法 create [unique|fulltext|spatial] index 索引名 on 表名(字段名 [长度] [asc|desc]); MySQL也能利用索引来快速地执行ORDER BY和GROUP BY语句的排序和分组操作. 通过索引优化来实现MySQL的ORDER

  • PHP 7.1中利用OpenSSL代替Mcrypt加解密的方法详解

    概要: php7.1发布后新特性吸引了不少PHPer,大家都在讨论新特性带来的好处与便利.但是从php7.0 升级到 php7.1 废弃(过时)了一个在过去普遍应用的扩展(mcrypt扩展).官方提供了相应的解决提示,却没有提供更详细的解决办法.于是坑来了: 今天在使用微信开放平台对接一个内容管理系统的时候,在绑定公众号的时候一直失败 原因: 调试的时候发现,直接原因是因为开放平台里面填写的授权事件(该授权事件每十分钟会通送一次事件来更新ticket),即: 这个地方填写的url,调试发现,这个

  • android中AES加解密的使用方法

    今天在android项目中使用AES对数据进行加解密,遇到了很多问题,网上也找了很多资料,也不行.不过最后还是让我给搞出来了,这里把这个记录下来,不要让别人走我的弯路,因为网上绝大多数的例子都是行不通的.好了,接下来开始讲解 1.Aes工具类 package com.example.cheng.aesencrypt; import android.text.TextUtils; import java.security.NoSuchAlgorithmException; import java.

  • jQuery实现滚动到底部时自动加载更多的方法示例

    本文实例讲述了jQuery实现滚动到底部时自动加载更多的方法.分享给大家供大家参考,具体如下: 这里利用AJAX,实现滚动到底加载数据功能: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/

  • 利用Java如何获取IP与机器名方法示例

    前言 本文详细给大家介绍了关于利用Java如何获取IP与机器名的方法示例,分享出来供大家参考学习,下面话不多说,来一起看看详细的介绍: 一.通过IP获取机器名 or 通过机器名获取ip host :主机        hostAddress :ip       hostName:机器名 import java.net.InetAddress; import java.net.UnknownHostException; public class Test01 { public static voi

  • JS简单实现滑动加载数据的方法示例

    本文实例讲述了JS简单实现滑动加载数据的方法.分享给大家供大家参考,具体如下: //滑动 function getScrollTop() { var scrollTop = 0; if (document.documentElement && document.documentElement.scrollTop) { scrollTop = document.documentElement.scrollTop; }else if (document.body) { scrollTop =

  • Android开发中Listview动态加载数据的方法示例

    本文实例讲述了Android开发中Listview动态加载数据的方法.分享给大家供大家参考,具体如下: 最近在研究网络数据加载的问题,比如我有几百,甚至上千条数据,这些数据如果一次性全部加载到arraylist,然后再加载到Listview中.我们必然会去单独开线程来做,这样造成的结果就是会出现等待时间很长,用户体验非常不好.我的想法是动态加载数据,第一次加载十条,然后往下面滑动的时候再追加十条,再往下面滑动的时候再去追加,这样大大减少了用户等待的时间,同时给处理数据留下了时间.网上看到了这样一

随机推荐