遇到一個(gè)需求是這樣的:
需要在使用AES_ENCRYPT()函數(shù)將明文加密,存儲(chǔ)在MySQL中,但是遇到了一些問(wèn)題……
說(shuō)將加密后的密文,
解密取出來(lái)是NULL。看了一下,她發(fā)過(guò)來(lái)的表結(jié)構(gòu):

再看了她通過(guò)AES_DECRYPT()函數(shù)加密了一個(gè)字符串,然后insert進(jìn)去了,執(zhí)行成功后,顯示了一個(gè)warning:
Query OK, 1 row affected, 1 warning (0.00 sec)
(沒(méi)有報(bào)錯(cuò)而是warning,大概是sql_mode的緣故)
此時(shí)她忽略了這個(gè)warning,再通過(guò)AES_DECRYPT()解密后,發(fā)現(xiàn)取出來(lái)的明文為NULL。
再回看表結(jié)構(gòu),發(fā)現(xiàn)其
字段屬性為“varchar”&&
字符集是ut8,檢查warning為下:
-
mysql> show warnings;
-
+---------+------+------------------------------------------------------------------------+
-
| Level | Code| Message |
-
+---------+------+------------------------------------------------------------------------+
-
| Warning| 1366| Incorrect string value:'\xE3f767\x12...' for column'passwd' at row 1|
-
+---------+------+------------------------------------------------------------------------+
-
1 rowin set (0.00 sec)
查了一下文檔,看一下這兩個(gè)函數(shù)的使用:
-
-- 將'hello world'加密,密鑰為'key',加密后的串存在@pass中
-
mysql> SET @pass=AES_ENCRYPT('hello world', 'key');
-
Query OK, 0 rows affected(0.00 sec)
-
-
-- 看一下加密后串的長(zhǎng)度(都為2的整數(shù)次方)
-
mysql> SELECT CHAR_LENGTH(@pass);
-
+--------------------+
-
| CHAR_LENGTH(@pass) |
-
+--------------------+
-
| 16 |
-
+--------------------+
-
1 rowin set(0.00 sec)
-
-
-- 使用AES_DECRYPT()解密
-
mysql> SELECT AES_DECRYPT(@pass, 'key');
-
+---------------------------+
-
| AES_DECRYPT(@pass, 'key') |
-
+---------------------------+
-
| hello world |
-
+---------------------------+
-
1 rowin set(0.00 sec)
那么到底該如何存呢?
方法①: 將字段屬性設(shè)置為varbinary/binary/四個(gè)blob類型,等二進(jìn)制字段屬性。
創(chuàng)建三個(gè)字段,屬性分別為varbinary、binary、blob。
并將'明文1','text2','明文_text3'加密,密鑰為key,存入表中。
最后取出。
-
mysql> CREATE TABLE t_passwd(pass1varbinary(16), pass2binary(16), pass3 blob);
-
Query OK, 0 rows affected(0.00 sec)
-
-
mysql> INSERT INTO t_passwdVALUES (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 rowin set (0.00 sec)
當(dāng)然,屬性括號(hào)內(nèi)的長(zhǎng)度要取決于明文的長(zhǎng)度,此處明文較短,故只給了16。
方法②:將密文十六進(jìn)制化,再存入varchar/char列。
此處需要用到
HEX()來(lái)存入,
用UNHEX()取出。
創(chuàng)建一個(gè)字符串屬性的字段。
將'hello world'先用密鑰'key2'進(jìn)行AES加密,再將加密后的串通過(guò)HEX函數(shù)十六進(jìn)制化。
最后先將加密后的串通過(guò)UNHEX取出,再通過(guò)AES據(jù)密鑰'key2'解密:
-
mysql>CREATE TABLE t_passwd_2(pass1char(32));
-
Query OK, 0 rows affected(0.01 sec)
-
-
mysql>INSERT INTO t_passwd_2VALUES (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 rowin set (0.00 sec)
同樣,根據(jù)明文的長(zhǎng)度不同,AES_ENCRYPT加密后的串長(zhǎng)度也會(huì)有所變化,所以HEX后的字符串長(zhǎng)度也會(huì)有所變化。
實(shí)際使用時(shí),需要據(jù)業(yè)務(wù)評(píng)估出一個(gè)合理值即可。
方法③:直接存入varchar中,不做十六進(jìn)制化。
回溯到問(wèn)題的一開(kāi)始,將加密后的串,存到utf8字符集并且屬性為varchar中,是不行的。
實(shí)際上,將字符集改成latin1就可以了:
在insert的時(shí)候也不會(huì)報(bào)warning了。
-
mysql> CREATE TABLE t_passwd_3(passvarchar(32)) CHARSET latin1;
-
Query OK, 0 rows affected(0.00 sec)
-
-
mysql> INSERT INTO t_passwd_3SELECT 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 rowin set (0.00 sec)
這樣的方法雖然美,只需將字段字符集設(shè)置為latin1就可以了,但可能會(huì)帶來(lái)隱患:
文檔上寫(xiě)了這樣的一句:
-
Many encryptionand compression functions return stringsfor which the result might contain arbitrarybyte values. If you want to store these results, use a column with a VARBINARYor BLOB binary string datatype. This will avoid potential problems with trailing space removalor character set conversion that would change data values, such as may occurif you use a nonbinary string datatype (CHAR, VARCHAR, TEXT).
大意是,如果用方法③那樣,直接將加密后的串存入char/varchar/text類型中,在做字符轉(zhuǎn)換的時(shí)或空格被刪除時(shí),可能會(huì)帶來(lái)潛在的影響。
所以如果一定要存在char/varchar/text中,那么還是參考方法②,十六進(jìn)制化一下吧。
或者如同方法①,直接存在二進(jìn)制字段中。
參考文檔:Chapter 12 Functions and Operators -12.13 Encryption and Compression Functions
本文題目:MySQL使用AES_ENCRYPT()/AES_DECRYPT()加解密的正確姿勢(shì)
網(wǎng)頁(yè)路徑:http://sd-ha.com/article4/iecdoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、搜索引擎優(yōu)化、手機(jī)網(wǎng)站建設(shè)、虛擬主機(jī)、用戶體驗(yàn)、定制網(wǎng)站
廣告
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源:
創(chuàng)新互聯(lián)