中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

密碼學之DES/AES算法

發布時間:2020-07-15 16:06:45 來源:網絡 閱讀:395 作者:sshpp 欄目:網絡安全

DES

DES全稱為Data Encryption Standard,即數據加密標準,是一種使用密鑰加密的塊算法,1977年被美國聯邦政府的國家標準局確定為聯邦資料處理標準(FIPS),并授權在非密級政府通信中使用,隨后該算法在國際上廣泛流傳開來。

DES使用簡介

使用DES需要設置加密內容、加密key、加密混淆向量iv、分組密碼模式、填充模式。

加密內容:
給定的加密的數據。如果數據長度不是 n*分組大小,則在其后使用 '\0' 補齊。

加密Key:
加密密鑰。 如果密鑰長度不是該算法所能夠支持的有效長度,需要填充。如果密鑰長度過長,需要截取。

加密iv:
用于CBC, CFB, OFB模式,在ECB模式里不是必須的。

分組密碼模式:
常見的分組密碼模式有:CBC, OFB,CFB 和 ECB。

填充模式:
Pkcs5、Pkcs7。

填充算法(Pkcs5、Pkcs7)

PKCS5Padding與PKCS7Padding基本上是可以通用的。在PKCS5Padding中,明確定義Block的大小是8位,而在PKCS7Padding定義中,對于塊的大小是不確定的,可以在1-255之間(塊長度超出255的尚待研究),填充值的算法都是一樣的:

pad = k - (l mod k)  //k=塊大小,l=數據長度,如果k=8, l=9,則需要填充額外的7個byte的7

可以得出:Pkcs5是Pkcs7的特例(Block的大小始終是8位)。當Block的大小始終是8位的時候,Pkcs5和Pkcs7是一樣的。(參考)

填充算法實現:

  • PHP

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);}

反填充(去掉填充的字符)只需要根據解密后內容最后一個字符,就知道填充了什么、填充了幾個,然后截取掉即可:A

function _unpad($text){    $pad = ord(substr($text, -1));//取最后一個字符的ASCII 碼值 
    if ($pad < 1 || $pad > strlen($text)) {        $pad = 0;
    }    return substr($text, 0, (strlen($text) - $pad));}
  • Python

from Crypto.Cipher import AESdef 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為例):
1、獲得加密算法的分組大小(mcrypt_get_block_size);
2、被加密的明文使用Pkcs5或Pkcs7填充;
3、加密密鑰key截取或填充至8位;
4、加密向量iv設置;
5、打開指定算法和模式對應的模塊,返回加密描述符td(mcrypt_module_open);
6、使用td、key、iv初始化加密所需的緩沖區 (mcrypt_generic_init);
7、加密數據(mcrypt_generic);
8、清理的加密描述符td的緩沖區(mcrypt_generic_deinit);
9、釋放加密描述符td(mcrypt_module_close);
10、返回base64_encode的加密結果,可選。

解密步驟(以PHP的擴展mcrypt為例):
1、base64_decode解碼,如果加密使用了base64_encode;
2、加密密鑰key截取或填充至8位;
3、加密向量iv設置;
4、打開指定算法和模式對應的模塊,返回加密描述符td(mcrypt_module_open);
5、使用td、key、iv初始化加密所需的緩沖區 (mcrypt_generic_init);
6、解密數據(mdecrypt_generic);
7、清理的加密描述符td的緩沖區(mcrypt_generic_deinit);
8、釋放加密描述符td(mcrypt_module_close);
9、使用Pkcs5去掉填充的內容,返回解密后的結果。

使用DES需要注意下面幾點:
1) 確保都使用DES + ECB;
2) 確保明文填充都使用的是Pkcs5或者Pkcs7,此時兩者效果一致;
3) 加密key在DES長度必須是8字節(bytes);如果不夠長必須填充,過長必須截取;
4) 加密向量iv與加密key有同樣的約定;
5) 注意加密結果建議都使用base64編碼。

只有以上都保持一樣,各個語言里最終加密的密文才能保持一致,否則會出現:
1) 每次加密的密文不一樣,但是能解密;(iv隨機生成導致的)
2) 不同語言加密出來的密文不一致。

各種語言實現示例

PHP

示例:

  • Crypt_DES.php

<?phpinclude('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
  • PHP使用Mcrypt擴展

/** * DES/AES加密封裝 * * 1、默認使用Pkcs7填充加密內容。 * 2、默認加密向量是"\0\0\0\0\0\0\0\0" * 3、默認情況下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);//DESecho $ret = $des->encrypt("123456").PHP_EOL;//加密字符串,結果默認已經base64了echo $ret = $des->decrypt($ret);//解密結果

使用MCRYPT_MODE_CBC + Pkcs7。注意和其它語言聯調的時候需要注意加密key已經過處理、加密向量默認值的設置。

輸出:

pQSWMWLBGQg=
123456
JS
  • CryptoJS

//字符串重復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

環境:Python 2.7.5,Linux CentOS7

需要先安裝:

pip install pycrypto
pip install Crypto
# -*- coding=utf-8-*-from Crypto.Cipher import DESimport 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

AES簡介

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) 不同語言加密出來的密文不一致。

各種語言實現示例

PHP

示例:

  • PHP使用Mcrypt擴展

這里還是使用上文的Crypt類。

$key = 'pwd';$des = new Crypt($key);//AES,默認是MCRYPT_RIJNDAEL_128+MCRYPT_MODE_ECBecho $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_ECBecho $ret = $des->encrypt("123456").PHP_EOL;//加密字符串,結果默認已經base64了echo $ret = $des->decrypt($ret);//解密結果

使用ECB + Pkcs7。和其它語言聯調的時候需要注意加密key已經過處理、加密向量默認值的設置。

輸出結果:

3+WQyhMavuxzPzy40PZhJg==123456
--------------mdSm0RmB+xAKrTah4DG31A==
123456

本例里當key長度不夠時,封裝的類已經自動幫我們填充好了足夠長度;當key長度等于16時,key的值不會改變。

JS
  • CryptoJS

和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

環境:Python 2.7.5,Linux CentOS7

需要先安裝:

pip install pycrypto
pip install Crypto
# -*- coding=utf-8-*-from Crypto.Cipher import AESimport osfrom Crypto import Randomimport 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+xAKrTah4DG31A==
123456

這里使用了AES+ECB+PKCS7Padding方法。加密結果和PHP是一致的。

服務端/客戶端加密選型

DES/CBC/PKCS7Padding

此時加密塊大小都是8字節,PKCS5和PKCS7效果一樣。各端實現的時候需要注意:
1) 使用相同的加密key,注意長度必須是8字節;
2) 使用相同的向量iv,建議設置成"\0\0\0\0\0\0\0";
3) 必須實現相同的PKCS7填充算法和反填充算法;
4) 加密結果都使用base64編碼。

AES/ECB/PKCS7Padding

使用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/CBC/PKCS7Padding

和AES/ECB/PKCS7Padding基本一致,但由于CBC模式用到向量,注意向量長度最少16字節。如果長度不夠,請填充"\0"。建議隨機生成,然后base64后傳給前端。

常用庫介紹

Mcrypt

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 或更高版本。

Crypto-JS

https://github.com/brix/crypto-js

CryptoJS (crypto.js) 為 JavaScript 提供了各種各樣的加密算法。目前已支持的算法包括:

  • MD5

  • SHA-1

  • SHA-256

  • AES

  • Rabbit

  • MARC4

  • HMAC

    • HMAC-MD5

    • HMAC-SHA1

    • HMAC-SHA256

  • PBKDF2

PyCrypto

https://github.com/dlitz/pycrypto

PyCrypto是使用Python編寫的加密工具包。支持所有主流算法。

hashlib

Python的hashlib提供了常見的摘要算法,如MD5,SHA1等等。

Crypt_DES.php

https://my.oschina.net/u/995648/blog/113390

通過純PHP實現的DES加密。示例:

<?phpinclude('Crypt_DES.php');$des = new Crypt_DES();$des->setKey('abcdefgh');$plaintext = 'test';echo $des->decrypt($des->encrypt($plaintext));


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阳东县| 达孜县| 曲靖市| 旬阳县| 勐海县| 新宁县| 烟台市| 井冈山市| 深泽县| 德钦县| 抚远县| 县级市| 醴陵市| 庆城县| 庄河市| 平阳县| 盐城市| 长岛县| 韶关市| 遂溪县| 铜山县| 临安市| 高尔夫| 花莲市| 晴隆县| 蓬安县| 蒙阴县| 闸北区| 玉溪市| 通辽市| 祁连县| 老河口市| 无为县| 阿合奇县| 江安县| 巴彦淖尔市| 怀来县| 双桥区| 呼图壁县| 阳信县| 纳雍县|