- 1.密碼學(xué)簡(jiǎn)介
- 2.對(duì)稱(chēng)加密
- 3.分組加密模式
- 4.非對(duì)稱(chēng)加密
- 5.單向散列函數(shù)
- 6.消息認(rèn)證碼
- 7.數(shù)字簽名
- 8.證書(shū)
- 9.SSL/TLS
本文將介紹比特序列運(yùn)算中的異或運(yùn)算,同時(shí)簡(jiǎn)單介紹DES、3DES、AES等對(duì)稱(chēng)加密算法,最后給出對(duì)應(yīng)的Golang加密代碼。
比特序列密碼
首先我們要明白二個(gè)概念,一個(gè)是計(jì)算機(jī)編碼,我們都知道計(jì)算機(jī)操作的對(duì)象并不是文字圖像,而是有0和1排列組成的比特序列;一個(gè)是異或運(yùn)算(XOR), 二個(gè)不同的比特位異或運(yùn)算結(jié)果是1,不同的比特位異或運(yùn)算結(jié)果是0。
假設(shè)我們將01001100這個(gè)比特序列成為A,將10101010這個(gè)比特序列成為B,那么A與B的異或運(yùn)算結(jié)果就如下所示:
由于二個(gè)相同的數(shù)進(jìn)行異或運(yùn)算的結(jié)果是0,因此如果將A與B異或的結(jié)果再與B進(jìn)行異或預(yù)算,則結(jié)果就會(huì)變回A。
可能你已經(jīng)發(fā)現(xiàn)了,上面的計(jì)算和加密、解密的步驟非常相似。
- 將明文A與秘鑰B進(jìn)行加密運(yùn)算,得到密文A⊕B
- 將密文A⊕B用秘鑰B進(jìn)行解密,得到明文A
實(shí)際上,主要選擇一個(gè)合適的B,僅僅使用異或運(yùn)算就可以實(shí)現(xiàn)一個(gè)高強(qiáng)度的密碼。
DES
DES(Data EncryptionStandard) 是1977年美國(guó)聯(lián)邦信息處理標(biāo)準(zhǔn)(FIPS)中所采用的一種對(duì)稱(chēng)密碼(FIPS46.3)。DES一直以來(lái)被美國(guó)以及其他國(guó)家的政府和銀行等廣泛使用。然而,隨著計(jì)算機(jī)的進(jìn)步,現(xiàn)在DES已經(jīng)能夠被暴力破解,強(qiáng)度大不如前了。
RSA公司舉辦過(guò)破解DES密鑰的比賽(DESChallenge),我們可以看一看RSA公司官方公布的比賽結(jié)果:
- 1997年的DES Challenge1中用了96天破譯密鑰
- 1998年的DES ChallengeIl-I中用了41天破譯密鑰
- 1998年的DES ChallengeII-2中用了56小時(shí)破譯密鑰
- 1999年的DES ChallengeIll中只用了22小時(shí)15分鐘破譯密鑰
由于DES的密文可以在短時(shí)間內(nèi)被破譯,因此除了用它來(lái)解密以前的密文以外,現(xiàn)在我們不應(yīng)該再使用DES了。
加密和解密
DES是一種將64比特的明文加密成64比特的密文的對(duì)稱(chēng)密碼算法, 它的密鑰長(zhǎng)度是56比特。盡管<font color="red">從規(guī)格上來(lái)說(shuō),DES的密鑰長(zhǎng)度是64比特,但由于每隔7比特會(huì)設(shè)置一個(gè)用于錯(cuò)誤檢查的比特,因此實(shí)質(zhì)上其密鑰長(zhǎng)度是56比特</font>。
<font color="red">DES是以64比特的明文(比特序列)為一個(gè)單位來(lái)進(jìn)行加密的</font>,這個(gè)64比特的單位稱(chēng)為分組。一般來(lái)說(shuō),以分組為單位進(jìn)行處理的密碼算法稱(chēng)為分組密碼(blockcipher),DES就是分組密碼的一種。
DES每次只能加密64比特的數(shù)據(jù),如果要加密的明文比較長(zhǎng),就需要對(duì)DES加密進(jìn)行迭代(反復(fù)),而迭代的具體方式就稱(chēng)為模式(mode)(后續(xù)文章詳細(xì)講解分組密碼的模式)。
大B -> bit
小b -> byte
秘鑰長(zhǎng)度(56bit + 8bit)/8 = 8byte
- DES的加密與解密 - 圖例
Go中對(duì)DES的操作
加解密實(shí)現(xiàn)思路
-
加密 - CBC分組模式
- 創(chuàng)建并返回一個(gè)使用DES算法的cipher.Block接口
- 秘鑰長(zhǎng)度為64bit, 即 64/8 = 8字節(jié)(byte)
- 對(duì)最后一個(gè)明文分組進(jìn)行數(shù)據(jù)填充
- DES是以64比特的明文(比特序列)為一個(gè)單位來(lái)進(jìn)行加密的
- 最后一組不夠64bit, 則需要進(jìn)行數(shù)據(jù)填充( 參考第三章)
- 創(chuàng)建一個(gè)密碼分組為鏈接模式的, 底層使用DES加密的BlockMode接口
- 加密連續(xù)的數(shù)據(jù)塊
- 創(chuàng)建并返回一個(gè)使用DES算法的cipher.Block接口
-
解密
- 創(chuàng)建并返回一個(gè)使用DES算法的cipher.Block接口
- 創(chuàng)建一個(gè)密碼分組為鏈接模式的, 底層使用DES解密的BlockMode接口
- 數(shù)據(jù)塊解密
- 去掉最后一組的填充數(shù)據(jù)
加解密的代碼實(shí)現(xiàn)
在Go中使用DES需要導(dǎo)入的包:
import (
"crypto/des"
"crypto/cipher"
"fmt"
"bytes"
)
DES加密代碼:
// src -> 要加密的明文
// key -> 秘鑰, 大小為: 8byte
func DesEncrypt_CBC(src, key []byte) []byte{
// 1. 創(chuàng)建并返回一個(gè)使用DES算法的cipher.Block接口
block, err := des.NewCipher(key)
// 2. 判斷是否創(chuàng)建成功
if err != nil{
panic(err)
}
// 3. 對(duì)最后一個(gè)明文分組進(jìn)行數(shù)據(jù)填充
src = PKCS5Padding(src, block.BlockSize())
// 4. 創(chuàng)建一個(gè)密碼分組為鏈接模式的, 底層使用DES加密的BlockMode接口
// 參數(shù)iv的長(zhǎng)度, 必須等于b的塊尺寸
tmp := []byte("helloAAA")
blackMode := cipher.NewCBCEncrypter(block, tmp)
// 5. 加密連續(xù)的數(shù)據(jù)塊
dst := make([]byte, len(src))
blackMode.CryptBlocks(dst, src)
fmt.Println("加密之后的數(shù)據(jù): ", dst)
// 6. 將加密數(shù)據(jù)返回
return dst
}
DES解密代碼
// src -> 要解密的密文
// key -> 秘鑰, 和加密秘鑰相同, 大小為: 8byte
func DesDecrypt_CBC(src, key []byte) []byte {
// 1. 創(chuàng)建并返回一個(gè)使用DES算法的cipher.Block接口
block, err := des.NewCipher(key)
// 2. 判斷是否創(chuàng)建成功
if err != nil{
panic(err)
}
// 3. 創(chuàng)建一個(gè)密碼分組為鏈接模式的, 底層使用DES解密的BlockMode接口
tmp := []byte("helloAAA")
blockMode := cipher.NewCBCDecrypter(block, tmp)
// 4. 解密數(shù)據(jù)
dst := src
blockMode.CryptBlocks(src, dst)
// 5. 去掉最后一組填充的數(shù)據(jù)
dst = PKCS5UnPadding(dst)
// 6. 返回結(jié)果
return dst
}
最后一個(gè)分組添加填充數(shù)據(jù)和移除添加數(shù)據(jù)代碼
// 使用pks5的方式填充
func PKCS5Padding(ciphertext []byte, blockSize int) []byte{
// 1. 計(jì)算最后一個(gè)分組缺多少個(gè)字節(jié)
padding := blockSize - (len(ciphertext)%blockSize)
// 2. 創(chuàng)建一個(gè)大小為padding的切片, 每個(gè)字節(jié)的值為padding
padText := bytes.Repeat([]byte{byte(padding)}, padding)
// 3. 將padText添加到原始數(shù)據(jù)的后邊, 將最后一個(gè)分組缺少的字節(jié)數(shù)補(bǔ)齊
newText := append(ciphertext, padText...)
return newText
}
// 刪除pks5填充的尾部數(shù)據(jù)
func PKCS5UnPadding(origData []byte) []byte{
// 1. 計(jì)算數(shù)據(jù)的總長(zhǎng)度
length := len(origData)
// 2. 根據(jù)填充的字節(jié)值得到填充的次數(shù)
number := int(origData[length-1])
// 3. 將尾部填充的number個(gè)字節(jié)去掉
return origData[:(length-number)]
}
測(cè)試函數(shù)
func DESText() {
// 加密
key := []byte("11111111")
result := DesEncrypt_CBC([]byte("床前明月光, 疑是地上霜. 舉頭望明月, 低頭思故鄉(xiāng)."), key)
fmt.Println(base64.StdEncoding.EncodeToString(result))
// 解密
result = DesDecrypt_CBC(result, key)
fmt.Println("解密之后的數(shù)據(jù): ", string(result))
}
重要的函數(shù)說(shuō)明
-
生成一個(gè)底層使用DES加/解密的Block接口對(duì)象
函數(shù)對(duì)應(yīng)的包: import "crypto/des" func NewCipher(key []byte) (cipher.Block, error) - 參數(shù) key: des對(duì)稱(chēng)加密使用的密碼, 密碼長(zhǎng)度為64bit, 即8byte - 返回值 cipher.Block: 創(chuàng)建出的使用DES加/解密的Block接口對(duì)象
-
創(chuàng)建一個(gè)密碼分組為CBC模式, 底層使用b加密的BlockMode接口對(duì)象
函數(shù)對(duì)應(yīng)的包: import "crypto/cipher" func NewCBCEncrypter(b Block, iv []byte) BlockMode - 參數(shù) b: 使用des.NewCipher函數(shù)創(chuàng)建出的Block接口對(duì)象 - 參數(shù) iv: 事先準(zhǔn)備好的一個(gè)長(zhǎng)度為一個(gè)分組長(zhǎng)度的比特序列, 每個(gè)分組為64bit, 即8byte - 返回值: 得到的BlockMode接口對(duì)象
-
使用cipher包的BlockMode接口對(duì)象對(duì)數(shù)據(jù)進(jìn)行加/解密
接口對(duì)應(yīng)的包: import "crypto/cipher" type BlockMode interface { // 返回加密字節(jié)塊的大小 BlockSize() int // 加密或解密連續(xù)的數(shù)據(jù)塊,src的尺寸必須是塊大小的整數(shù)倍,src和dst可指向同一內(nèi)存地址 CryptBlocks(dst, src []byte) } 接口中的 CryptBlocks(dst, src []byte) 方法: - 參數(shù) dst: 傳出參數(shù), 存儲(chǔ)加密或解密運(yùn)算之后的結(jié)果 - 參數(shù) src: 傳入?yún)?shù), 需要進(jìn)行加密或解密的數(shù)據(jù)切片(字符串)
-
創(chuàng)建一個(gè)密碼分組為CBC模式, 底層使用b解密的BlockMode接口對(duì)象
函數(shù)對(duì)應(yīng)的包: import "crypto/cipher" func NewCBCDecrypter(b Block, iv []byte) BlockMode - 參數(shù) b: 使用des.NewCipher函數(shù)創(chuàng)建出的Block接口對(duì)象 - 參數(shù) iv: 事先準(zhǔn)備好的一個(gè)長(zhǎng)度為一個(gè)分組長(zhǎng)度的比特序列, 每個(gè)分組為64bit, 即8byte, 該序列的值需要和NewCBCEncrypter函數(shù)的第二個(gè)參數(shù)iv值相同 - 返回值: 得到的BlockMode接口對(duì)象
-
自定義函數(shù)介紹
對(duì)稱(chēng)加密加密需要對(duì)數(shù)據(jù)進(jìn)行分組, 保證每個(gè)分組的數(shù)據(jù)長(zhǎng)度相等, 如果最后一個(gè)分組長(zhǎng)度不夠, 需要進(jìn)行填充 func PKCS5Padding(ciphertext []byte, blockSize int) []byte - 參數(shù) ciphertext: 需要加密的原始數(shù)據(jù) - 參數(shù) blockSize: 每個(gè)分組的長(zhǎng)度, 跟使用的加密算法有關(guān)系 * des:64bit, 8byte * 3des:64bit, 8byte * aes: 128bit, 16byte
三重DES
現(xiàn)在DES已經(jīng)可以在現(xiàn)實(shí)的時(shí)間內(nèi)被暴力破解,因此我們需要一種用來(lái)替代DES的分組密碼,三重DES就是出于這個(gè)目的被開(kāi)發(fā)出來(lái)的。
三重DES(triple-DES)是為了增加DES的強(qiáng)度,將DES重復(fù)3次所得到的一種密碼算法,通常縮寫(xiě)為3DES。
三重DES的加密
三重DES的加解密機(jī)制如下圖所示:
加->解->加 -> 目的是為了兼容DES(如果三個(gè)秘鑰都一樣)
3des秘鑰長(zhǎng)度24字節(jié) = 1234567a 1234567b 1234567a
明文: 10
秘鑰1: 2
秘鑰2: 3
秘鑰3: 4
加密算法: 明文+秘鑰
解密算法: 密文-秘鑰
10+2-3+4
)
明文經(jīng)過(guò)三次DES處理才能變成最后的密文,由于DES密鑰的長(zhǎng)度實(shí)質(zhì)上是56比特,因此<font color="red">三重DES的密鑰長(zhǎng)度就是56×3=168比特, 加上用于錯(cuò)誤檢測(cè)的標(biāo)志位8x3, 共192bit</font>。
從上圖我們可以發(fā)現(xiàn),三重DES并不是進(jìn)行三次DES加密(加密-->加密-->加密),而是<font color="red">加密-->解密-->加密</font>的過(guò)程。在加密算法中加人解密操作讓人感覺(jué)很不可思議,實(shí)際上這個(gè)方法是IBM公司設(shè)計(jì)出來(lái)的,目的是為了讓三重DES能夠兼容普通的DES。
<font color="red">當(dāng)三重DES中所有的密鑰都相同時(shí),三重DES也就等同于普通的DES了</font>。這是因?yàn)樵谇皟刹郊用?->解密之后,得到的就是最初的明文。因此,以前用DES加密的密文,就可以通過(guò)這種方式用三重DES來(lái)進(jìn)行解密。也就是說(shuō),三重DES對(duì)DES具備向下兼容性。
如果密鑰1和密鑰3使用相同的密鑰,而密鑰2使用不同的密鑰(也就是只使用兩個(gè)DES密鑰),這種三重DES就稱(chēng)為DES-EDE2。EDE表示的是加密(Encryption) -->解密(Decryption)-->加密(Encryption)這個(gè)流程。
密鑰1、密鑰2、密鑰3全部使用不同的比特序列的三重DES稱(chēng)為DES-EDE3。
盡管三重DES目前還被銀行等機(jī)構(gòu)使用,但其處理速度不高,而且在安全性方面也逐漸顯現(xiàn)出了一些問(wèn)題。
Go中對(duì)3DES的操作
加解密實(shí)現(xiàn)思路
-
加密 - CBC分組模式
- 創(chuàng)建并返回一個(gè)使用3DES算法的cipher.Block接口
- 秘鑰長(zhǎng)度為64bit3=192bit, 即 192/8 = 24字節(jié)(byte)*
- 對(duì)最后一個(gè)明文分組進(jìn)行數(shù)據(jù)填充
- 3DES是以64比特的明文(比特序列)為一個(gè)單位來(lái)進(jìn)行加密的
- 最后一組不夠64bit, 則需要進(jìn)行數(shù)據(jù)填充( 參考第三章)
- 創(chuàng)建一個(gè)密碼分組為鏈接模式的, 底層使用3DES加密的BlockMode接口
- 加密連續(xù)的數(shù)據(jù)塊
- 創(chuàng)建并返回一個(gè)使用3DES算法的cipher.Block接口
-
解密
- 創(chuàng)建并返回一個(gè)使用3DES算法的cipher.Block接口
- 創(chuàng)建一個(gè)密碼分組為鏈接模式的, 底層使用3DES解密的BlockMode接口
- 數(shù)據(jù)塊解密
- 去掉最后一組的填充數(shù)據(jù)
加解密的代碼實(shí)現(xiàn)
3DES加密代碼
// 3DES加密
func TripleDESEncrypt(src, key []byte) []byte {
// 1. 創(chuàng)建并返回一個(gè)使用3DES算法的cipher.Block接口
block, err := des.NewTripleDESCipher(key)
if err != nil{
panic(err)
}
// 2. 對(duì)最后一組明文進(jìn)行填充
src = PKCS5Padding(src, block.BlockSize())
// 3. 創(chuàng)建一個(gè)密碼分組為鏈接模式, 底層使用3DES加密的BlockMode模型
blockMode := cipher.NewCBCEncrypter(block, key[:8])
// 4. 加密數(shù)據(jù)
dst := src
blockMode.CryptBlocks(dst, src)
return dst
}
3DES解密代碼
// 3DES解密
func TripleDESDecrypt(src, key []byte) []byte {
// 1. 創(chuàng)建3DES算法的Block接口對(duì)象
block, err := des.NewTripleDESCipher(key)
if err != nil{
panic(err)
}
// 2. 創(chuàng)建密碼分組為鏈接模式, 底層使用3DES解密的BlockMode模型
blockMode := cipher.NewCBCDecrypter(block, key[:8])
// 3. 解密
dst := src
blockMode.CryptBlocks(dst, src)
// 4. 去掉尾部填充的數(shù)據(jù)
dst = PKCS5UnPadding(dst)
return dst
}
重要的函數(shù)說(shuō)明
-
生成一個(gè)底層使用3DES加/解密的Block接口對(duì)象
函數(shù)對(duì)應(yīng)的包: import "crypto/des" func NewTripleDESCipher(key []byte) (cipher.Block, error) - 參數(shù) key: 3des對(duì)稱(chēng)加密使用的密碼, 密碼長(zhǎng)度為(64*3)bit, 即(8*3)byte - 返回值 cipher.Block: 創(chuàng)建出的使用DES加/解密的Block接口對(duì)象
-
創(chuàng)建一個(gè)密碼分組為CBC模式, 底層使用b加密的BlockMode接口對(duì)象
函數(shù)對(duì)應(yīng)的包: import "crypto/cipher" func NewCBCEncrypter(b Block, iv []byte) BlockMode - 參數(shù) b: 使用des.NewTripleDESCipher 函數(shù)創(chuàng)建出的Block接口對(duì)象 - 參數(shù) iv: 事先準(zhǔn)備好的一個(gè)長(zhǎng)度為一個(gè)分組長(zhǎng)度的比特序列, 每個(gè)分組為64bit, 即8byte - 返回值: 得到的BlockMode接口對(duì)象
-
使用cipher包的BlockMode接口對(duì)象對(duì)數(shù)據(jù)進(jìn)行加/解密
接口對(duì)應(yīng)的包: import "crypto/cipher" type BlockMode interface { // 返回加密字節(jié)塊的大小 BlockSize() int // 加密或解密連續(xù)的數(shù)據(jù)塊,src的尺寸必須是塊大小的整數(shù)倍,src和dst可指向同一內(nèi)存地址 CryptBlocks(dst, src []byte) } 接口中的 CryptBlocks(dst, src []byte) 方法: - 參數(shù) dst: 傳出參數(shù), 存儲(chǔ)加密或解密運(yùn)算之后的結(jié)果 - 參數(shù) src: 傳入?yún)?shù), 需要進(jìn)行加密或解密的數(shù)據(jù)切片(字符串)
-
創(chuàng)建一個(gè)密碼分組為CBC模式, 底層使用b解密的BlockMode接口對(duì)象
函數(shù)對(duì)應(yīng)的包: import "crypto/cipher" func NewCBCDecrypter(b Block, iv []byte) BlockMode - 參數(shù) b: 使用des.NewTripleDESCipher 函數(shù)創(chuàng)建出的Block接口對(duì)象 - 參數(shù) iv: 事先準(zhǔn)備好的一個(gè)長(zhǎng)度為一個(gè)分組長(zhǎng)度的比特序列, 每個(gè)分組為64bit, 即8byte, 該序列的值需要和NewCBCEncrypter函數(shù)的第二個(gè)參數(shù)iv值相同 - 返回值: 得到的BlockMode接口對(duì)象
AES
AES(Advanced Encryption Standard)是取代其前任標(biāo)準(zhǔn)(DES)而成為新標(biāo)準(zhǔn)的一種對(duì)稱(chēng)密碼算法。全世界的企業(yè)和密碼學(xué)家提交了多個(gè)對(duì)稱(chēng)密碼算法作為AES的候選,最終在2000年從這些候選算法中選出了一種名為Rijndael的對(duì)稱(chēng)密碼算法,并將其確定為了AES。
Rijndael的分組長(zhǎng)度為128比特,密鑰長(zhǎng)度可以以32比特為單位在128比特到256比特的范圍內(nèi)進(jìn)行選擇(不過(guò)在AES的規(guī)格中,密鑰長(zhǎng)度只有128、192和256比特三種)。
- 128bit = 16字節(jié)
- 192bit = 24字節(jié)
- 256bit = 32字節(jié)
在go提供的接口中秘鑰長(zhǎng)度只能是16字節(jié)
AES的加密和解密
和DES—樣,AES算法也是由多輪所構(gòu)成的,下圖展示了每一輪的大致計(jì)算步驟。DES使用Feistel網(wǎng)絡(luò)作為其基本結(jié)構(gòu),而AES沒(méi)有使用Feistel網(wǎng)絡(luò),而是使用了SPN Rijndael的輸人分組為128比特,也就是16字節(jié)。首先,需要逐個(gè)字節(jié)地對(duì)16字節(jié)的輸入數(shù)據(jù)進(jìn)行SubBytes處理。所謂SubBytes,就是以每個(gè)字節(jié)的值(0~255中的任意值)為索引,從一張擁有256個(gè)值的替換表(S-Box)中查找出對(duì)應(yīng)值的處理,也是說(shuō),將一個(gè)1字節(jié)的值替換成另一個(gè)1字節(jié)的值。
SubBytes之后需要進(jìn)行ShiftRows處理,即將SubBytes的輸出以字節(jié)為單位進(jìn)行打亂處理。從下圖的線我們可以看出,這種打亂處理是有規(guī)律的。
ShiftRows之后需要進(jìn)行MixCo1umns處理,即對(duì)一個(gè)4字節(jié)的值進(jìn)行比特運(yùn)算,將其變?yōu)榱硗庖粋€(gè)4字節(jié)值。
最后,需要將MixColumns的輸出與輪密鑰進(jìn)行XOR,即進(jìn)行AddRoundKey處理。到這里,AES的一輪就結(jié)東了。實(shí)際上,在AES中需要重復(fù)進(jìn)行10 ~ 14輪計(jì)算。
通過(guò)上面的結(jié)構(gòu)我們可以發(fā)現(xiàn)輸入的所有比特在一輪中都會(huì)被加密。和每一輪都只加密一半輸人的比特的Feistel網(wǎng)絡(luò)相比,這種方式的優(yōu)勢(shì)在于加密所需要的輪數(shù)更少。此外,這種方式還有一個(gè)優(yōu)勢(shì),即SubBytes,ShiftRows和MixColumns可以分別按字節(jié)、行和列為單位進(jìn)行并行計(jì)算。
- SubBytes -- 字節(jié)代換
- ShiftRows -- 行移位代換
- MixColumns -- 列混淆
- AddRoundKey -- 輪密鑰加
下圖展示了AES中一輪的解密過(guò)程。從圖中我們可以看出,SubBytes、ShiftRows、MixColumns分別存在反向運(yùn)算InvSubBytes、InvShiftRows、InvMixColumns,這是因?yàn)锳ES不像Feistel網(wǎng)絡(luò)一樣能夠用同一種結(jié)構(gòu)實(shí)現(xiàn)加密和解密。
- InvSubBytes -- 逆字節(jié)替代
- InvShiftRows -- 逆行移位
- InvMixColumns -- 逆列混淆
Go中對(duì)AES的使用
加解密實(shí)現(xiàn)思路
-
加密 - CBC分組模式
- 創(chuàng)建并返回一個(gè)使用AES算法的cipher.Block接口
- 秘鑰長(zhǎng)度為128bit, 即 128/8 = 16字節(jié)(byte)
- 對(duì)最后一個(gè)明文分組進(jìn)行數(shù)據(jù)填充
- AES是以128比特的明文(比特序列)為一個(gè)單位來(lái)進(jìn)行加密的
- 最后一組不夠128bit, 則需要進(jìn)行數(shù)據(jù)填充( 參考第三章)
- 創(chuàng)建一個(gè)密碼分組為鏈接模式的, 底層使用AES加密的BlockMode接口
- 加密連續(xù)的數(shù)據(jù)塊
- 創(chuàng)建并返回一個(gè)使用AES算法的cipher.Block接口
-
解密
- 創(chuàng)建并返回一個(gè)使用AES算法的cipher.Block接口
- 創(chuàng)建一個(gè)密碼分組為鏈接模式的, 底層使用AES解密的BlockMode接口
- 數(shù)據(jù)塊解密
- 去掉最后一組的填充數(shù)據(jù)
加解密的代碼實(shí)現(xiàn)
AES加密代碼
// AES加密
func AESEncrypt(src, key []byte) []byte{
// 1. 創(chuàng)建一個(gè)使用AES加密的塊對(duì)象
block, err := aes.NewCipher(key)
if err != nil{
panic(err)
}
// 2. 最后一個(gè)分組進(jìn)行數(shù)據(jù)填充
src = PKCS5Padding(src, block.BlockSize())
// 3. 創(chuàng)建一個(gè)分組為鏈接模式, 底層使用AES加密的塊模型對(duì)象
blockMode := cipher.NewCBCEncrypter(block, key[:block.BlockSize()])
// 4. 加密
dst := src
blockMode.CryptBlocks(dst, src)
return dst
}
AES解密
// AES解密
func AESDecrypt(src, key []byte) []byte{
// 1. 創(chuàng)建一個(gè)使用AES解密的塊對(duì)象
block, err := aes.NewCipher(key)
if err != nil{
panic(err)
}
// 2. 創(chuàng)建分組為鏈接模式, 底層使用AES的解密模型對(duì)象
blockMode := cipher.NewCBCDecrypter(block, key[:block.BlockSize()])
// 3. 解密
dst := src
blockMode.CryptBlocks(dst, src)
// 4. 去掉尾部填充的字
dst = PKCS5UnPadding(dst)
return dst
}
重要的函數(shù)說(shuō)明
-
生成一個(gè)底層使用AES加/解密的Block接口對(duì)象
函數(shù)對(duì)應(yīng)的包: import "crypto/aes" func NewCipher(key []byte) (cipher.Block, error) - 參數(shù) key: aes對(duì)稱(chēng)加密使用的密碼, 密碼長(zhǎng)度為128bit, 即16byte - 返回值 cipher.Block: 創(chuàng)建出的使用AES加/解密的Block接口對(duì)象
-
創(chuàng)建一個(gè)密碼分組為CBC模式, 底層使用b加密的BlockMode接口對(duì)象
函數(shù)對(duì)應(yīng)的包: import "crypto/cipher" func NewCBCEncrypter(b Block, iv []byte) BlockMode - 參數(shù) b: 使用aes.NewCipher函數(shù)創(chuàng)建出的Block接口對(duì)象 - 參數(shù) iv: 事先準(zhǔn)備好的一個(gè)長(zhǎng)度為一個(gè)分組長(zhǎng)度的比特序列, 每個(gè)分組為64bit, 即8byte - 返回值: 得到的BlockMode接口對(duì)象
-
使用cipher包的BlockMode接口對(duì)象對(duì)數(shù)據(jù)進(jìn)行加/解密
接口對(duì)應(yīng)的包: import "crypto/cipher" type BlockMode interface { // 返回加密字節(jié)塊的大小 BlockSize() int // 加密或解密連續(xù)的數(shù)據(jù)塊,src的尺寸必須是塊大小的整數(shù)倍,src和dst可指向同一內(nèi)存地址 CryptBlocks(dst, src []byte) } 接口中的 CryptBlocks(dst, src []byte) 方法: - 參數(shù) dst: 傳出參數(shù), 存儲(chǔ)加密或解密運(yùn)算之后的結(jié)果 - 參數(shù) src: 傳入?yún)?shù), 需要進(jìn)行加密或解密的數(shù)據(jù)切片(字符串)
-
創(chuàng)建一個(gè)密碼分組為CBC模式, 底層使用b解密的BlockMode接口對(duì)象
函數(shù)對(duì)應(yīng)的包: import "crypto/cipher" func NewCBCDecrypter(b Block, iv []byte) BlockMode - 參數(shù) b: 使用des.NewCipher函數(shù)創(chuàng)建出的Block接口對(duì)象 - 參數(shù) iv: 事先準(zhǔn)備好的一個(gè)長(zhǎng)度為一個(gè)分組長(zhǎng)度的比特序列, 每個(gè)分組為128bit, 即16byte, 該序列的值需要和NewCBCEncrypter函數(shù)的第二個(gè)參數(shù)iv值相同 - 返回值: 得到的BlockMode接口對(duì)象
應(yīng)選擇哪種對(duì)稱(chēng)加密
前面介紹了DES、三重DES和AES等對(duì)稱(chēng)密碼,那么我們到底應(yīng)該使用哪一種對(duì)稱(chēng)密碼算法呢?
- 今后最好不要將DES用于新的用途,因?yàn)殡S著計(jì)算機(jī)技術(shù)的進(jìn)步,現(xiàn)在用暴力破解法已經(jīng)能夠在現(xiàn)實(shí)的時(shí)間內(nèi)完成對(duì)DES的破譯。但是,在某些情況下也需要保持與舊版本軟件的兼容性。
- 出于兼容性的因素三重DES在今后還會(huì)使用一段時(shí)間,但會(huì)逐漸被AES所取代。
- 今后大家應(yīng)該使用的算法是AES(Rijndael),因?yàn)樗踩⒖焖伲夷軌蛟诟鞣N平臺(tái)上工作。此外,由于全世界的密碼學(xué)家都在對(duì)AES進(jìn)行不斷的驗(yàn)證,因此即便萬(wàn)一發(fā)現(xiàn)它有什么缺陷,也會(huì)立刻告知全世界并修復(fù)這些缺陷。
一般來(lái)說(shuō),我們不應(yīng)該使用任何自制的密碼算法,而是應(yīng)該使用AES。因?yàn)锳ES在其選定過(guò)程中,經(jīng)過(guò)了全世界密碼學(xué)家所進(jìn)行的高品質(zhì)的驗(yàn)證工作,而對(duì)于自制的密碼算法則很難進(jìn)行這樣的驗(yàn)證。
歡迎與我交流
本篇文章由一文多發(fā)平臺(tái)ArtiPub自動(dòng)發(fā)布