本文主要為大家介紹了關於MySQL利用AES_ENCRYPT()與AES_DECRYPT()加解密的正確方法,MySQL中AES_ENCRYPT('密碼','鑰匙')函數可以對字段值做加密處理,AES_DECRYPT(表的字段名字,'鑰匙')函數解密處理,文中給了詳細的範例程式碼,需要的朋友可以參考下,希望能幫助大家。
前言
最近在工作中遇到需求是這樣的:需要在使用AES_ENCRYPT()
函數將明文加密,儲存在MySQL中,但遇到了一些問題…以下就來詳細介紹下。
說將加密後的密文,解密取出是NULL。
看了一下,她發過來的表結構:
#再看了她透過AES_DECRYPT()函數加密了一個字串,然後insert進去了,執行成功後,顯示了一個warning:<br>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 VARBIRYRY or OB bin em. 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中,那就還是參考方法②,十六進位化一下吧。以上是MySQL如何正確地利用AES_ENCRYPT()與AES_DECRYPT()加解密的詳細內容。更多資訊請關注PHP中文網其他相關文章!