- 對(duì)稱加密算法,即加密和解密使用一樣的密鑰的加解密算法播掷。
- 分組密碼(block cipher)些阅,是每次只能處理特定長(zhǎng)度的一塊(block)數(shù)據(jù)的一類加解密算法檩咱。
- 目前常見(jiàn)的對(duì)稱加密算法DES拒啰、3DES驯绎、AES都是屬于分組密碼。
DES
- DES谋旦,全稱Data Encryption Standard条篷,是上一代標(biāo)準(zhǔn)對(duì)稱加密算法骗随,現(xiàn)已不推薦使用。
- 密鑰:DES是一種將64bit的明文加密成64bit的密文的對(duì)稱密碼算法赴叹,它的密鑰長(zhǎng)度是64bit(每隔7bit會(huì)設(shè)置一個(gè)用于錯(cuò)誤檢查的bit,因此實(shí)際使用密鑰長(zhǎng)度56bit)指蚜。
- 分組:DES是以64bit的明文作為一個(gè)單位來(lái)進(jìn)行加密的乞巧,這64bit的單位稱為分組。一般來(lái)說(shuō)摊鸡,以分組為單位進(jìn)行處理的密碼算法稱為分組密碼(block cipher)绽媒,DES就是分組密碼中的一種。DES每次只能加密64比特的數(shù)據(jù)免猾,如果要加密的明文比較長(zhǎng)是辕,就需要對(duì)DES加密進(jìn)行迭代。
DES加密
DES解密
3DES
- 3DES猎提,即triple-DES获三,簡(jiǎn)單地說(shuō)就是3次DES加解密的組合。現(xiàn)已不推薦使用锨苏。
- 加密:cipthertext = E(k3, D(k2, E(k1, plaintext)))
- 解密:plaintext = D(k1, E(k2, D(k3, ciphertext)))
- 特點(diǎn):如果三個(gè)密鑰都一樣疙教,拿剛好和DES一樣。
注:E表示Encrypt伞租,D表示Decrypt贞谓。
3DES加密
3DES解密
AES
- AES, Advanced Encryption Standard,是現(xiàn)行的對(duì)稱加密標(biāo)準(zhǔn)葵诈。目前(2017)如果使用對(duì)稱加密裸弦,應(yīng)該使用AES。當(dāng)然作喘,只能說(shuō)當(dāng)前AES算法是安全的理疙,不能保證AES永遠(yuǎn)都是安全的。
- 分組:128bit徊都。
- 密鑰:128bit沪斟、192bit、256bit暇矫。
分組密碼的模式
分組密碼簡(jiǎn)介
- 分組密碼(block cipher)主之,是每次只能處理特定長(zhǎng)度的一塊數(shù)據(jù)的一類密碼算法,這里的“一塊”就稱為分組(block)李根。一個(gè)分組的比特?cái)?shù)就稱為分組長(zhǎng)度(block length)槽奕。
- 流密碼(stream cipher),是對(duì)數(shù)據(jù)流進(jìn)行連續(xù)處理的一類密碼算法房轿。
- DES粤攒、3DES所森、AES等大多數(shù)對(duì)稱密碼算法都屬于分組密碼。
ECB模式
- 全稱Electronic CodeBook mode夯接,電子密碼本模式焕济。
- 分組方式:將明文分組加密之后的結(jié)果直接稱為密文分組。
- 優(yōu)點(diǎn):
- 一個(gè)分組損壞不影響其它分組盔几。
- 可以并行加解密晴弃。
- 缺點(diǎn):
- 相同的明文分組會(huì)轉(zhuǎn)換為相同的密文分組。
- 無(wú)需破譯密碼就能操縱明文(每個(gè)分組獨(dú)立且前后文無(wú)關(guān)逊拍,直接增加或刪除一個(gè)分組不影響其它分組解密過(guò)程的正確性)上鞠。
ECB加密
ECB解密
CBC模式
- 全稱Cipher Block Chaining mode,密碼分組鏈接模式芯丧。
- 分組方式:將明文分組與前一個(gè)密文分組進(jìn)行XOR運(yùn)算芍阎,然后再進(jìn)行加密。每個(gè)分組的加解密都依賴于前一個(gè)分組缨恒。而第一個(gè)分組沒(méi)有前一個(gè)分組谴咸,因此需要一個(gè)初始化向量(initialization vector)。
- 優(yōu)點(diǎn):
- 加密結(jié)果與前文相關(guān)肿轨,有利于提高加密結(jié)果的隨機(jī)性寿冕。
- 可并行解密。
- 缺點(diǎn)
- 無(wú)法并行加密椒袍。
- 一個(gè)分組損壞驼唱,如果密文長(zhǎng)度不變,則兩個(gè)分組受影響驹暑。
- 一個(gè)分組損壞玫恳,如果密文長(zhǎng)度改變,則后面所有分組受影響优俘。
CBC加密
CBC解密
CFB模式
- 全稱Cipher FeedBack mode京办,密文反饋模式。
- 分組方式:前一個(gè)密文分組會(huì)被送回到密碼算法的輸入端(具體見(jiàn)下圖)帆焕。
- 在CBC和EBC模式中惭婿,明文分組都是通過(guò)密碼算法進(jìn)行加密的。而在CFB模式中叶雹,明文分組并沒(méi)有通過(guò)加密算法直接進(jìn)行加密财饥,明文分組和密文分組之間只有一個(gè)XOR。
- CFB模式是通過(guò)將“明文分組”與“密碼算法的輸出”進(jìn)行XOR運(yùn)行生成“密文分組”折晦。CFB模式中由密碼算法生成的比特序列稱為密鑰流(key stream)钥星。密碼算法相當(dāng)于密鑰流的偽隨機(jī)數(shù)生成器,而初始化向量相當(dāng)于偽隨機(jī)數(shù)生成器的種子满着。(CFB模式有點(diǎn)類似一次性密碼本谦炒。)
- 優(yōu)點(diǎn):
- 支持并行解密贯莺。
- 不需要填充(padding)。
- 缺點(diǎn):
- 不能抵御重放攻擊(replay attack)宁改。
- 不支持并行加密缕探。
CFB加密
CFB解密
OFB模式
- Output FeedBack mode 輸出反饋模式
- 密碼算法的輸出會(huì)反饋到密碼算法的輸入中(具體見(jiàn)下圖)。
- OFB模式中还蹲,XOR所需的比特序列(密鑰流)可以事先通過(guò)密碼算法生成撕蔼,和明文分組無(wú)關(guān)。只需要提前準(zhǔn)備好所需的密鑰流秽誊,然后進(jìn)行XOR運(yùn)算就可以了。
OFB加密
OFB解密
分組模式小結(jié)
推薦使用CBC模式琳骡。
填充
為什么要填充锅论?
ECB和CBC模式要求明文數(shù)據(jù)必須填充至長(zhǎng)度為分組長(zhǎng)度的整數(shù)倍。-
填充的兩個(gè)問(wèn)題楣号。
- 填充多少字節(jié)最易?
- 填充什么內(nèi)容?
填充多少字節(jié)炫狱?
需要填充的字節(jié)數(shù)為:paddingSize = blockSize - textLength % blockSize
-
填充什么內(nèi)容藻懒?(這里列舉的三種方式本質(zhì)上是一致的)
- ANSI X.923:填充序列的最后一個(gè)字節(jié)填
paddingSize
,其它填0视译。 - ISO 10126:填充序列的最后一個(gè)字節(jié)填
paddingSize
嬉荆, 其它填隨機(jī)數(shù)。 - PKCS7:填充序列的每個(gè)字節(jié)都填
paddingSize
酷含。
- ANSI X.923:填充序列的最后一個(gè)字節(jié)填
示例
這里用golang寫一個(gè)AES加密的例子鄙早。
由于加密出來(lái)的數(shù)據(jù)很可能有很多不可見(jiàn)字符,因此這里會(huì)將加密后的結(jié)果進(jìn)行一次Base64Encode椅亚。
這里采用CBC模式+PKCS7填充方式限番。
package main
import (
"bytes"
"crypto/cipher"
"crypto/aes"
"encoding/base64"
"fmt"
)
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext) % blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
func AesEncrypt(origData, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
origData = PKCS7Padding(origData, blockSize)
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
func AesDecrypt(crypted, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
origData := make([]byte, len(crypted))
blockMode.CryptBlocks(origData, crypted)
origData = PKCS7UnPadding(origData)
return origData, nil
}
func main() {
key := []byte("0123456789abcdef")
result, err := AesEncrypt([]byte("hello world"), key)
if err != nil {
panic(err)
}
fmt.Println(base64.StdEncoding.EncodeToString(result))
origData, err := AesDecrypt(result, key)
if err != nil {
panic(err)
}
fmt.Println(string(origData))
}
參考文檔
- 《圖解密碼學(xué)》
- 維基百科