本文示例代碼詳見:https://github.com/52fhy/cryp...php
DES全稱爲Data Encryption Standard,即數據加密標準,是一種使用密鑰加密的塊算法,1977年被美國聯邦政府的國家標準局肯定爲聯邦資料處理標準(FIPS),並受權在非密級政府通訊中使用,隨後該算法在國際上普遍流傳開來。html
使用DES須要設置加密內容、加密key、加密混淆向量iv、分組密碼模式、填充模式。前端
加密內容:
給定的加密的數據。若是數據長度不是 n*分組大小,則在其後使用 '0' 補齊。java
加密Key:
加密密鑰。 若是密鑰長度不是該算法所可以支持的有效長度,須要填充。若是密鑰長度過長,須要截取。python
加密iv:
用於CBC, CFB, OFB模式,在ECB模式裏不是必須的。git
分組密碼模式:
常見的分組密碼模式有:CBC, OFB,CFB 和 ECB。github
填充模式:
Pkcs五、Pkcs7。算法
PKCS5Padding與PKCS7Padding基本上是能夠通用的。在PKCS5Padding中,明肯定義Block的大小是8位,而在PKCS7Padding定義中,對於塊的大小是不肯定的,能夠在1-255之間(塊長度超出255的尚待研究),填充值的算法都是同樣的:app
pad = k - (l mod k) //k=塊大小,l=數據長度,若是k=8, l=9,則須要填充額外的7個byte的7
能夠得出:Pkcs5是Pkcs7的特例(Block的大小始終是8位)。當Block的大小始終是8位的時候,Pkcs5和Pkcs7是同樣的。(參考)dom
填充算法實現:
function pkcs5_pad($text) { $pad = 8 - (strlen($text) % 8); //$pad = 8 - (strlen($text) & 7); //也可使用這種方法 return $text . str_repeat(chr($pad), $pad); } function pkcs7_pad ($text, $blocksize) { $pad = $blocksize - (strlen($text) % $blocksize); return $text . str_repeat(chr($pad), $pad); }
反填充(去掉填充的字符)只須要根據解密後內容最後一個字符,就知道填充了什麼、填充了幾個,而後截取掉便可:
function _unpad($text){ $pad = ord(substr($text, -1));//取最後一個字符的ASCII 碼值 if ($pad < 1 || $pad > strlen($text)) { $pad = 0; } return substr($text, 0, (strlen($text) - $pad)); }
from Crypto.Cipher import AES def pkcs7_pad(str): x = AES.block_size - (len(str) % AES.block_size) if x != 0: str = str + chr(x)*x return str def _unpad(msg): paddingLen = ord(msg[len(msg)-1]) return msg[0:-paddingLen]
加密步驟(以PHP的擴展mcrypt爲例):
一、得到加密算法的分組大小(mcrypt_get_block_size);
二、被加密的明文使用Pkcs5或Pkcs7填充;
三、加密密鑰key截取或填充至8位;
四、加密向量iv設置;
五、打開指定算法和模式對應的模塊,返回加密描述符td(mcrypt_module_open);
六、使用td、key、iv初始化加密所需的緩衝區 (mcrypt_generic_init);
七、加密數據(mcrypt_generic);
八、清理的加密描述符td的緩衝區(mcrypt_generic_deinit);
九、釋放加密描述符td(mcrypt_module_close);
十、返回base64_encode的加密結果,可選。
解密步驟(以PHP的擴展mcrypt爲例):
一、base64_decode解碼,若是加密使用了base64_encode;
二、加密密鑰key截取或填充至8位;
三、加密向量iv設置;
四、打開指定算法和模式對應的模塊,返回加密描述符td(mcrypt_module_open);
五、使用td、key、iv初始化加密所需的緩衝區 (mcrypt_generic_init);
六、解密數據(mdecrypt_generic);
七、清理的加密描述符td的緩衝區(mcrypt_generic_deinit);
八、釋放加密描述符td(mcrypt_module_close);
九、使用Pkcs5去掉填充的內容,返回解密後的結果。
使用DES須要注意下面幾點:
1) 確保都使用DES
+ ECB
;
2) 確保明文填充都使用的是Pkcs5
或者Pkcs7
,此時二者效果一致;
3) 加密key在DES長度必須是8字節(bytes);若是不夠長必須填充,過長必須截取;
4) 加密向量iv與加密key有一樣的約定;
5) 注意加密結果建議都使用base64編碼。
只有以上都保持同樣,各個語言裏最終加密的密文才能保持一致,不然會出現:
1) 每次加密的密文不同,可是能解密;(iv隨機生成致使的)
2) 不一樣語言加密出來的密文不一致。
示例:
<?php include('Crypt_DES.php'); $des = new Crypt_DES();//默認是CBC模式 $plaintext = '123456'; $des->setKey('pwd'); //$des->setIV("\0\0\0\0\0\0\0\0");//默認填0,注意是雙引號 $encode = base64_encode($des->encrypt($plaintext)); echo $encode. PHP_EOL; echo $des->decrypt(base64_decode($encode));
注意:Crypt_DES類裏默認是MCRYPT_MODE_CBC
模式,且默認會把加密向量截取或填充至8位:
str_pad(substr($key, 0, 8), 8, chr(0))
也就是若是加密向量大於8位,只會截取前8位;少於則補0。
另外加密向量iv
會被設置成\0\0\0\0\0\0\0\0
,CRYPT_DES_MODE_ECB
模式該變量則不是必須的。因此,若是使用了其它語言須要注意到這點。加密結果請務必base64_decode
。
輸出:
pQSWMWLBGQg= 123456
/** * DES/AES加密封裝 * * 一、默認使用Pkcs7填充加密內容。 * 二、默認加密向量是"\0\0\0\0\0\0\0\0" * 三、默認狀況下key作了處理:過長截取,太短填充 * * @author 52fhy * @github https://github.com/52fhy/ * @date 2017-5-13 17:08:57 * Class Crypt */ class Crypt { private $key;//加密key:若是密鑰長度不是加解密算法可以支持的有效長度,會自動填充"\0"。過長則會截取 private $iv;//加密向量:這裏默認填充"\0"。假設爲空,程序會隨機產生,致使加密的結果是不肯定的。ECB模式下會忽略該變量 private $mode; //分組密碼模式:MCRYPT_MODE_modename 常量中的一個,或如下字符串中的一個:"ecb","cbc","cfb","ofb","nofb" 和 "stream"。 private $cipher; //算法名稱:MCRYPT_ciphername 常量中的一個,或者是字符串值的算法名稱。 public function __construct($key, $cipher = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_ECB, $iv = "\0\0\0\0\0\0\0"){ $this->key = $key; $this->iv = $iv; $this->mode = $mode; $this->cipher = $cipher; } public function encrypt($input){ $block_size = mcrypt_get_block_size($this->cipher, $this->mode); $key = $this->_pad0($this->key, $block_size);//將key填充至block大小 $td = mcrypt_module_open($this->cipher, '', $this->mode, ''); $iv = $this->iv ? $this->_pad0($this->iv, $block_size) : @mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND); $input = $this->pkcs7_pad($input, $block_size); //加密方法一: // @mcrypt_generic_init($td, $key, $iv);//ECB模式下,初始向量iv會被忽略 // $data = mcrypt_generic($td, $input); // mcrypt_generic_deinit($td); // mcrypt_module_close($td); //加密方法二: $data = mcrypt_encrypt( $this->cipher, $key, $input, $this->mode, $iv //ECB模式下,向量iv會被忽略 ); $data = base64_encode($data);//如需轉換二進制可改爲 bin2hex 轉換 return $data; } public function decrypt($encrypted){ $block_size = mcrypt_get_block_size($this->cipher, $this->mode); $key = $this->_pad0($this->key, $block_size); $td = mcrypt_module_open($this->cipher, '', $this->mode, ''); $iv = $this->iv ? $this->_pad0($this->iv, $block_size) : @mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND); //解密方法一: // $encrypted = base64_decode($encrypted); //如需轉換二進制可改爲 bin2hex 轉換 // @mcrypt_generic_init($td, $key, $iv); // $decrypted = mdecrypt_generic($td, $encrypted); // mcrypt_generic_deinit($td); // mcrypt_module_close($td); //解密方法二: $decrypted = mcrypt_decrypt( $this->cipher, $key, base64_decode($encrypted), $this->mode, $iv //ECB模式下,向量iv會被忽略 ); return $this->_unpad($decrypted); } /** * 當使用「PKCS#5」或「PKCS5Padding」別名引用該算法時,不該該假定支持8字節之外的塊大小。 * @url http://www.users.zetnet.co.uk/hopwood/crypto/scan/cs.html#pad_PKCSPadding * @param $text * @return string */ public function pkcs5_pad($text) { $pad = 8 - (strlen($text) % 8); //$pad = 8 - (strlen($text) & 7); //也可使用這種方法 return $text . str_repeat(chr($pad), $pad); } public function pkcs7_pad ($text, $blocksize) { $pad = $blocksize - (strlen($text) % $blocksize); return $text . str_repeat(chr($pad), $pad); } public function _unpad($text){ $pad = ord(substr($text, -1));//取最後一個字符的ASCII 碼值 if ($pad < 1 || $pad > strlen($text)) { $pad = 0; } return substr($text, 0, (strlen($text) - $pad)); } /** * 祕鑰key和向量iv填充算法:大於block_size則截取,小於則填充"\0" * @param $str * @param $block_size * @return string */ private function _pad0($str, $block_size) { return str_pad(substr($str, 0, $block_size), $block_size, chr(0)); //chr(0) 與 "\0" 等效,由於\0轉義後表示空字符,與ASCII表裏的0表明的字符同樣 } } $key = 'pwd'; $des = new Crypt($key, MCRYPT_DES, MCRYPT_MODE_CBC);//DES echo $ret = $des->encrypt("123456").PHP_EOL;//加密字符串,結果默認已經base64了 echo $ret = $des->decrypt($ret);//解密結果
使用MCRYPT_MODE_CBC
+ Pkcs7
。注意和其它語言聯調的時候須要注意加密key已通過處理、加密向量默認值的設置。
輸出:
pQSWMWLBGQg= 123456
//字符串重複 function str_repeat(target, n) {return (new Array(n + 1)).join(target);} //使用"\0"填充祕鑰或向量 function _pad0(str, block_size) { if(str.length >= block_size){ return str.substr(0, block_size); }else{ return str + str_repeat("\0", block_size - (str.length % block_size)); } } function des_encrypt(data,key,iv){//加密 var key = CryptoJS.enc.Utf8.parse(key); var iv = CryptoJS.enc.Utf8.parse(iv); var encrypted = CryptoJS.DES.encrypt(data,key, { iv:iv, mode:CryptoJS.mode.CBC, padding:CryptoJS.pad.Pkcs7 }); return encrypted.toString(); } function des_decrypt(encrypted,key,iv){//解密 var key = CryptoJS.enc.Utf8.parse(key); var iv = CryptoJS.enc.Utf8.parse(iv); var decrypted = CryptoJS.DES.decrypt(encrypted,key, { iv:iv, mode:CryptoJS.mode.CBC, padding:CryptoJS.pad.Pkcs7 }); return decrypted.toString(CryptoJS.enc.Utf8); } var key = _pad0("pwd", 8); var iv = _pad0("\0", 8); encrypted = des_encrypt("123456",key,iv);//pQSWMWLBGQg= decryptedStr = des_decrypt(encrypted,key,iv);//123456
環境:Python 2.7.5,Linux CentOS7
須要先安裝:
pip install pycrypto pip install Crypto
# -*- coding=utf-8-*- from Crypto.Cipher import DES import base64 """ des cbc加密算法 padding : PKCS5 """ class DESUtil: __BLOCK_SIZE_8 = BLOCK_SIZE_8 = DES.block_size __IV = "\0\0\0\0\0\0\0\0" # __IV = chr(0)*8 @staticmethod def encryt(str, key): cipher = DES.new(key, DES.MODE_CBC, DESUtil.__IV) x = DESUtil.__BLOCK_SIZE_8 - (len(str) % DESUtil.__BLOCK_SIZE_8) if x != 0: str = str + chr(x)*x msg = cipher.encrypt(str) # msg = base64.urlsafe_b64encode(msg).replace('=', '') msg = base64.b64encode(msg) return msg @staticmethod def decrypt(enStr, key): cipher = DES.new(key, DES.MODE_CBC,DESUtil.__IV) # enStr += (len(enStr) % 4)*"=" # decryptByts = base64.urlsafe_b64decode(enStr) decryptByts = base64.b64decode(enStr) msg = cipher.decrypt(decryptByts) paddingLen = ord(msg[len(msg)-1]) return msg[0:-paddingLen] if __name__ == "__main__": key = "12345678" res = DESUtil.encryt("123456", key) print res print DESUtil.decrypt(res, key)
輸出:
ED5wLgc3Mnw= 123456
若是加密密鑰小於8位,須要填充"\0"
,示例:
key = "pwd" + chr(0)*5
修改運行後輸出:
pQSWMWLBGQg= 123456
AES(Advanced Encryption Standard),在密碼學中又稱Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣爲全世界所使用。通過五年的甄選流程,高級加密標準由美國國家標準與技術研究院(NIST)於2001年11月26日發佈於FIPS PUB 197,並在2002年5月26日成爲有效的標準。2006年,高級加密標準已然成爲對稱密鑰加密中最流行的算法之一。
ECB模式是將明文按照固定大小的塊進行加密的,塊大小不足則進行填充。ECB模式沒有用到向量。
使用AES須要注意下面幾點:
1) 確保都使用AES_128
+ ECB
;
2) 確保明文填充都使用的是Pkcs7
;
3) 加密key在AES_128長度必須是16, 24, 或者 32 字節(bytes);若是不夠長必須填充,過長必須截取,建議直接md5;
4) 加密向量iv與加密key有一樣的約定,但在ECB
能夠忽略該值(用不到)。
5) 注意加密結果建議都使用base64編碼。
只有以上都保持同樣,各個語言裏最終加密的密文才能保持一致,不然會出現:
1) 每次加密的密文不同,可是能解密;(iv隨機生成致使的)
2) 不一樣語言加密出來的密文不一致。
示例:
這裏仍是使用上文的Crypt類。
$key = 'pwd'; $des = new Crypt($key);//AES,默認是MCRYPT_RIJNDAEL_128+MCRYPT_MODE_ECB echo $ret = $des->encrypt("123456").PHP_EOL;//加密字符串,結果默認已經base64了 echo $ret = $des->decrypt($ret);//解密結果 echo PHP_EOL.'--------------'.PHP_EOL; $key = '1234567812345678'; $des = new Crypt($key);//AES,默認是MCRYPT_RIJNDAEL_128+MCRYPT_MODE_ECB echo $ret = $des->encrypt("123456").PHP_EOL;//加密字符串,結果默認已經base64了 echo $ret = $des->decrypt($ret);//解密結果
使用ECB
+ Pkcs7
。和其它語言聯調的時候須要注意加密key已通過處理、加密向量默認值的設置。
輸出結果:
3+WQyhMavuxzPzy40PZhJg== 123456 -------------- mdSm0RmB+xAKrTah3DG31A== 123456
本例裏當key長度不夠時,封裝的類已經自動幫咱們填充好了足夠長度;當key長度等於16時,key的值不會改變。
和DES代碼基本同樣,只要把DES改成AES便可,CBC改成ECB,塊大小改成16。
//字符串重複 function str_repeat(target, n) {return (new Array(n + 1)).join(target);} //使用"\0"填充祕鑰或向量 function _pad0(str, block_size) { if(str.length >= block_size){ return str.substr(0, block_size); }else{ return str + str_repeat("\0", block_size - (str.length % block_size)); } } function aes_encrypt(data,key,iv){//加密 var key = CryptoJS.enc.Utf8.parse(key); var iv = CryptoJS.enc.Utf8.parse(iv); var encrypted = CryptoJS.AES.encrypt(data,key, { iv:iv, mode:CryptoJS.mode.ECB, padding:CryptoJS.pad.Pkcs7 }); return encrypted.toString(); } function aes_decrypt(encrypted,key,iv){//解密 var key = CryptoJS.enc.Utf8.parse(key); var iv = CryptoJS.enc.Utf8.parse(iv); var decrypted = CryptoJS.AES.decrypt(encrypted,key, { iv:iv, mode:CryptoJS.mode.ECB, padding:CryptoJS.pad.Pkcs7 }); return decrypted.toString(CryptoJS.enc.Utf8); } var key = _pad0("pwd", 16); var iv = _pad0("\0", 16); encrypted = aes_encrypt("123456",key,iv);//3+WQyhMavuxzPzy40PZhJg== decryptedStr = aes_decrypt(encrypted,key,iv);//123456
ECB模式沒有用到向量。本例若是改成CBC,只須要把ECB改成CBC便可,加密結果仍是:3+WQyhMavuxzPzy40PZhJg==
。換了加密向量則不同了。
環境:Python 2.7.5,Linux CentOS7
須要先安裝:
pip install pycrypto pip install Crypto
# -*- coding=utf-8-*- from Crypto.Cipher import AES import os from Crypto import Random import base64 """ aes加密算法 padding : PKCS7 """ class AESUtil: __BLOCK_SIZE_16 = BLOCK_SIZE_16 = AES.block_size @staticmethod def encryt(str, key): #cipher = AES.new(key, AES.MODE_ECB,b'0000000000000000') #第三個參數是加密向量iv,ECB模式不須要 cipher = AES.new(key, AES.MODE_ECB) x = AESUtil.__BLOCK_SIZE_16 - (len(str) % AESUtil.__BLOCK_SIZE_16) if x != 0: str = str + chr(x)*x msg = cipher.encrypt(str) # msg = base64.urlsafe_b64encode(msg).replace('=', '') msg = base64.b64encode(msg) return msg @staticmethod def decrypt(enStr, key): cipher = AES.new(key, AES.MODE_ECB) # enStr += (len(enStr) % 4)*"=" # decryptByts = base64.urlsafe_b64decode(enStr) decryptByts = base64.b64decode(enStr) msg = cipher.decrypt(decryptByts) paddingLen = ord(msg[len(msg)-1]) return msg[0:-paddingLen] if __name__ == "__main__": key = "1234567812345678" res = AESUtil.encryt("123456", key) print(res) print(AESUtil.decrypt(res, key))
輸出:
mdSm0RmB+xAKrTah3DG31A== 123456
這裏使用了AES
+ECB
+PKCS7Padding
方法。加密結果和PHP是一致的。
此時加密塊大小都是8字節,PKCS5和PKCS7效果同樣。各端實現的時候須要注意:
1) 使用相同的加密key,注意長度必須是8字節;
2) 使用相同的向量iv,建議設置成"\0\0\0\0\0\0\0"
;
3) 必須實現相同的PKCS7填充算法和反填充算法;
4) 加密結果都使用base64編碼。
使用AES_128
加密塊大小都是16字節,PKCS5沒法使用,請使用PKCS7。各端實現的時候須要注意:
1) 使用相同的加密key,注意長度必須是16, 24, 或者 32 字節(bytes);若是不夠長必須填充,過長必須截取,建議直接md5;
2) 使用相同的向量iv,建議設置成"\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
;能夠和加密key同樣使用md5後的值;ECB
模式下能夠忽略該項;
3) 必須實現相同的PKCS7填充算法和反填充算法;
4) 加密結果都使用base64編碼。
和AES/ECB/PKCS7Padding
基本一致,但因爲CBC模式用到向量,注意向量長度最少16字節。若是長度不夠,請填充"0"。建議隨機生成,而後base64後傳給前端。
Mcrypt 是一個功能強大的加密算法擴展庫。
Mcrypt 庫提供了對多種塊算法的支持, 包括:DES,TripleDES,Blowfish (默認), 3-WAY,SAFER-SK64,SAFER-SK128,TWOFISH,TEA,RC2 以及 GOST,而且支持 CBC,OFB,CFB 和 ECB 密碼模式。
PHP裏經過啓用 Mcrypt 擴展便可使用(mcrypt_
開頭的系列函數)。注意的是,要使用該擴展,必須首先安裝mcrypt標準類庫,而 mcrypt 標準類庫依賴 libmcrypt 和 mhash 兩個庫。從 PHP 5.0.0 開始,須要使用 libcrypt 2.5.6 或更高版本。
https://github.com/brix/crypt...
CryptoJS (crypto.js) 爲 JavaScript 提供了各類各樣的加密算法。目前已支持的算法包括:
HMAC
https://github.com/dlitz/pycr...
PyCrypto是使用Python編寫的加密工具包。支持全部主流算法。
Python的hashlib提供了常見的摘要算法,如MD5,SHA1等等。
https://my.oschina.net/u/9956...
經過純PHP實現的DES加密。示例:
<?php include('Crypt_DES.php'); $des = new Crypt_DES(); $des->setKey('abcdefgh'); $plaintext = 'test'; echo $des->decrypt($des->encrypt($plaintext));
一、在線加密解密
http://tool.oschina.net/encry...
一、Java 加解密技術系列之 DES - 紫羽風的博客 - 博客頻道 - CSDN.NET
http://blog.csdn.net/happylee...
二、一個很好的PHP加密算法 DES加密類_PHP基礎_UncleToo - 專一PHP技術推廣
http://www.uncletoo.com/html/...
三、關於CryptoJS中md5加密以及aes加密的隨筆 - 李盈盈的小博客 - 博客園
http://www.cnblogs.com/liying...
四、關於PKCS5Padding與PKCS7Padding的區別 - 在路上... - 博客園
http://www.cnblogs.com/midea0...
五、AES ECB加密實現(java/php/python) - sevenlater的博客 - 博客頻道 - CSDN.NET
http://blog.csdn.net/sevenlat...
歡迎關注公衆號及時獲取最新文章推送!
推薦!每個月僅需$2.5,便可擁有配置SSD的VPS!