AES 加密方案的深入學(xué)習(xí)

之前通過重新學(xué)習(xí)各種常見 web 密碼的加密方案丑婿,對各種方案的加密原理和應(yīng)用場景有了更深入的理解妆够,接下來就是再學(xué)習(xí)下數(shù)據(jù)加密方案商玫,數(shù)據(jù)加密方案常見的其實(shí)就是對稱加密(AES)和非對稱加密(RSA)狂打。

AES

AES(Advanced Encryption Standard)高級加密標(biāo)準(zhǔn),基于 Rijndael 算法诬辈,該算法為比利時(shí)密碼學(xué)家 Joan Daemen 和 Vincent Rijmen 所設(shè)計(jì)酵使,結(jié)合兩位作者的名字,以 Rijndael 為名投稿高級加密標(biāo)準(zhǔn)的甄選流程焙糟,經(jīng)過五年的甄選流程口渔,在 2001 年由美國國家標(biāo)準(zhǔn)與技術(shù)研究院(NIST)發(fā)布,并在 2002 年成為有效的標(biāo)準(zhǔn)穿撮,目前已經(jīng)成為最流行的對稱加密算法之一缺脉。

對稱加密算法是在加密和解密時(shí)使用相同的密鑰。舉個(gè)極簡的例子悦穿,假如 A 端和 B 端使用對稱加密的方案進(jìn)行數(shù)據(jù)通訊攻礼,他們共同的密鑰為數(shù)字 3,A 向 B 傳輸?shù)臄?shù)字在發(fā)送前都會乘以密鑰數(shù)字 3栗柒,當(dāng) B 端接收到 A 端的數(shù)字后礁扮,除以密鑰數(shù)字 3 就能得到真實(shí)的數(shù)字。

AES 的實(shí)現(xiàn)原理

AES 是一種區(qū)塊加密標(biāo)準(zhǔn)瞬沦,概括來說是將明文數(shù)據(jù)按每 128 位的大小切塊太伊,再用密鑰將每個(gè)塊的數(shù)據(jù)進(jìn)行加密,密鑰長度可以選擇 128 位逛钻,192位僚焦,256位。因?yàn)?AES 算法基于 Rijndael 算法曙痘,并不完全等同叠赐,所以這兩者在使用上是有區(qū)別的, Rijndael 算法允許明文數(shù)據(jù)可以按照 128位屡江、192位、256位 來切塊赛不,支持的切分范圍更廣惩嘉,但是當(dāng) Rijndael 算法 被選為 AES 時(shí),NIST 限制了 AES 的參數(shù)范圍踢故,只允許明文按照 128 位切塊文黎。

AES 的加密過程是在一個(gè) 4×4 的字節(jié)矩陣上運(yùn)作的,其初值就是一個(gè)明文區(qū)塊殿较,128 位對應(yīng)的就是 16 字節(jié)耸峭,剛好構(gòu)成一個(gè) 4×4 的明文區(qū)塊。


明文矩陣區(qū)塊.png

AES 根據(jù)密鑰長度來確定加密輪數(shù)淋纲,加密輪數(shù)是指劳闹,將當(dāng)前計(jì)算出來的密文按照相同的計(jì)算方式帶入下一輪進(jìn)行計(jì)算,輪數(shù)就是控制循環(huán)的次數(shù),密鑰長度和加密輪數(shù)的關(guān)系為:

密鑰長度 加密輪數(shù)
128 10
192 12
256 14
AES 加密步驟

1本涕、輪密鑰加(AddRoundKey)
將回合密鑰和數(shù)據(jù)矩陣中值做異或運(yùn)算(XOR)得到新的數(shù)據(jù)矩陣贿条,回合密鑰是每輪循環(huán)都會由密碼生成方案通過主密鑰生成的一個(gè)子密鑰窖铡,子密鑰也是一個(gè) 4×4 的字節(jié)矩陣。


異或運(yùn)算.png

2、字節(jié)代換(SubBytes)
將數(shù)據(jù)矩陣中的每個(gè)字節(jié)與 S 盒(S-BOX)中的對應(yīng)元素進(jìn)行置換人断,S 盒是密碼學(xué)中用于對輸入數(shù)據(jù)進(jìn)行非線性替代的基本組件,其主要目的是引入混淆(confusion)痢站,從而使得輸出與輸入之間的關(guān)系更加復(fù)雜吻贿,增強(qiáng)密碼系統(tǒng)的抗分析能力。AES 的 S 盒作為標(biāo)準(zhǔn)的一部分是固定不變的呻右,所有人用到的 S 盒是一樣的跪妥。


s 盒.png

3、行移位(ShiftRows)
數(shù)據(jù)矩陣的第一行保持列位置不變窿冯,其他每一行都向左循環(huán)移動特定的偏移量骗奖,第二行移動1個(gè)偏移量,第三行移動2個(gè)偏移量醒串,第四行移動3個(gè)偏移量执桌。假如源數(shù)據(jù)為以下所示:


行移位.png

4、列混合(MixColumns)
使用固定矩陣對每一列進(jìn)行轉(zhuǎn)換芜赌,替換得到新的列仰挣。


固定矩陣.png

在每次加密輪次中重復(fù)上述 1-4 的步驟,只有在最后一次加密輪中省略第四步列混合缠沈,將每個(gè)塊加密后的密文進(jìn)行拼接膘壶,最后就得到了最終的密文數(shù)據(jù)。

分組密碼工作模式

分組密碼工作模式是指在使用分組密碼(如 AES洲愤、DES)進(jìn)行加密時(shí)颓芭,處理明文數(shù)據(jù)的方法。分組密碼通常將數(shù)據(jù)分成固定長度的塊來加密柬赐,而分組密碼工作模式?jīng)Q定了如何處理這些塊亡问,以及如何將它們組合起來生成密文,工作模式有 ECB肛宋、CBC州藕、OFB、CFB酝陈、GCM床玻、CTR,其中最常用的是 CBC 模式沉帮。

  • CBC 密碼分組鏈接模式(Cipher Block Chaining Mode)
    每個(gè)明文塊在加密前會與前一個(gè)密文塊進(jìn)行異或(XOR)運(yùn)算锈死,首個(gè)塊與初始化向量(IV)異或贫堰,初始化向量是隨機(jī)化的。因?yàn)槊總€(gè)塊的加密需要依賴上一個(gè)塊馅精,所有并行處理能力不強(qiáng)严嗜。

塊數(shù)據(jù)補(bǔ)全

因?yàn)榉纸M密碼自身只能加密長度等于密碼分組長度的單塊數(shù)據(jù),所以當(dāng)明文塊數(shù)據(jù)長度不夠時(shí)洲敢,需要使用填充方式將明文塊大小填充到指定長度漫玄,填充模式現(xiàn)在普遍使用的是 pkcs7 標(biāo)準(zhǔn),pkcs7 填充方式為压彭,先計(jì)算最后塊需要補(bǔ)齊的字節(jié)數(shù)睦优,然后每個(gè)字節(jié)填充的數(shù)據(jù)就是這個(gè)需要補(bǔ)齊的字節(jié)數(shù)。這里需要注意的是壮不,pkcs7 要求即使塊的字節(jié)數(shù)和塊大小取余不為0汗盘,也要填充一個(gè)16字節(jié)的塊,方便之后的塊數(shù)據(jù)去除 pkcs7 填充字節(jié)询一。

代碼實(shí)踐

  • php
    php 想要實(shí)現(xiàn) AES 加解密需要安裝 OpenSSL 擴(kuò)展
<?php
// 加密數(shù)據(jù)
function aesEncrypt($plaintext, $key, $iv) {
    // Ensure the key is 32 bytes (256 bits) for AES-256
    $key = substr(hash('sha256', $key, true), 0, 32);

    // Encrypt the plaintext
    $ciphertext = openssl_encrypt($plaintext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);

    // Return the base64 encoded ciphertext
    return base64_encode($ciphertext);
}

// 解密數(shù)據(jù)
function aesDecrypt($ciphertext, $key, $iv) {
    // Ensure the key is 32 bytes (256 bits) for AES-256
    $key = substr(hash('sha256', $key, true), 0, 32);

    // Decode the base64 encoded ciphertext
    $ciphertext = base64_decode($ciphertext);

    // Decrypt the ciphertext
    $plaintext = openssl_decrypt($ciphertext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);

    return $plaintext;
}

// 明文
$plaintext = "This is a secret message.";
$key = "your-secret-key";
$iv = openssl_random_pseudo_bytes(16); // IV should be 16 bytes for AES-256-CBC

// 加密數(shù)據(jù)
$ciphertext = aesEncrypt($plaintext, $key, $iv);
echo "Ciphertext: " . $ciphertext . PHP_EOL;

// 解密信息
$decryptedText = aesDecrypt($ciphertext, $key, $iv);
echo "Decrypted text: " . $decryptedText . PHP_EOL;
?>
  • go 代碼實(shí)現(xiàn)
    go 沒有 php 那樣方便的函數(shù)隐孽,需要自己實(shí)現(xiàn)塊填充和塊去除。
package encrypt

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/base64"
    "encoding/hex"
    "errors"
    "io"
)

// AesCbcEncrypt AES CBC模式加密
func AesCbcEncrypt(content, secret string) string {
    //記載密鑰健蕊,并且轉(zhuǎn)16進(jìn)制菱阵,方便對比密鑰字節(jié)長度
    key, _ := hex.DecodeString(secret)
    //明文字符串轉(zhuǎn)字節(jié)切片
    plaintext := []byte(content)

    //采用 pkcs7 標(biāo)準(zhǔn)進(jìn)行塊數(shù)據(jù)填充
    plaintext = pkcs7Pad(plaintext, aes.BlockSize)

    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }

    //CBC 模式的需要加向量值 IV,IV 的字節(jié)數(shù)和塊的字節(jié)長度相等缩功,將IV拼接在明文的前邊
    ciphertext := make([]byte, aes.BlockSize+len(plaintext))
    iv := ciphertext[:aes.BlockSize]
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        panic(err)
    }

    mode := cipher.NewCBCEncrypter(block, iv)
    mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)

    //轉(zhuǎn)base64方便傳輸
    result := base64.StdEncoding.EncodeToString(ciphertext)
    return result
}

// pkcs7 填充標(biāo)準(zhǔn)
func pkcs7Pad(data []byte, blockSize int) []byte {
    padding := blockSize - len(data)%blockSize
    padText := make([]byte, len(data)+padding)
    copy(padText, data)
    for i := len(data); i < len(padText); i++ {
        padText[i] = byte(padding)
    }
    return padText
}

// AesDecrypt AES CBC模式解密
func AesCbcDecrypt(content, secret string) []byte {
    ciphertext, err := base64.StdEncoding.DecodeString(content)
    if err != nil {
        panic(err)
    }

    key, _ := hex.DecodeString(secret)

    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }

    if len(ciphertext) < aes.BlockSize {
        panic("密文長度過短")
    }

    //取前16個(gè)字節(jié)作為 IV 值
    iv := ciphertext[:aes.BlockSize]
    cipherContent := ciphertext[aes.BlockSize:]

    //驗(yàn)證塊的完整性
    if len(cipherContent)%aes.BlockSize != 0 {
        panic("密文格式錯(cuò)誤")
    }

    mode := cipher.NewCBCDecrypter(block, iv)

    paddingText := make([]byte, len(cipherContent))
    mode.CryptBlocks(paddingText, cipherContent)
    result, err := pkcs7UnPad(paddingText, aes.BlockSize)
    if err != nil {
        panic(err)
    }

    return result
}

// pkcs7 塊填充去除
func pkcs7UnPad(plainText []byte, blockSize int) ([]byte, error) {
    length := len(plainText)
    number := int(plainText[length-1])

    if number >= length || number > blockSize {
        return nil, errors.New("byte length is error")
    }
    return plainText[:length-number], nil
}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末晴及,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嫡锌,更是在濱河造成了極大的恐慌虑稼,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件势木,死亡現(xiàn)場離奇詭異蛛倦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)啦桌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門溯壶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人震蒋,你說我怎么就攤上這事《阕” “怎么了查剖?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長噪窘。 經(jīng)常有香客問我笋庄,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任直砂,我火速辦了婚禮菌仁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘静暂。我一直安慰自己济丘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布洽蛀。 她就那樣靜靜地躺著摹迷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪郊供。 梳的紋絲不亂的頭發(fā)上峡碉,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機(jī)與錄音驮审,去河邊找鬼鲫寄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛疯淫,可吹牛的內(nèi)容都是我干的地来。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼峡竣,長吁一口氣:“原來是場噩夢啊……” “哼靠抑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起适掰,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤颂碧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后类浪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體载城,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年费就,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诉瓦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡力细,死狀恐怖睬澡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情眠蚂,我是刑警寧澤煞聪,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站逝慧,受9級特大地震影響昔脯,放射性物質(zhì)發(fā)生泄漏啄糙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一云稚、第九天 我趴在偏房一處隱蔽的房頂上張望隧饼。 院中可真熱鬧,春花似錦静陈、人聲如沸燕雁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贵白。三九已至,卻和暖如春崩泡,著一層夾襖步出監(jiān)牢的瞬間禁荒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工角撞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留呛伴,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓谒所,卻偏偏與公主長得像热康,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子劣领,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容