Golang與對稱加密
目錄
1、對稱加密介紹
2、DES
2.1 概述
2.2 主要思路
2.3 DES 子密鑰生成
2.4 DES 加密過程
2.5 使用示例
2.6 分組模式
3、AES
4、CBC

1、對稱加密介紹
對稱加密算法用來對敏感數(shù)據(jù)等信息進行加密,常用的算法包括:
DES(Data Encryption Standard):數(shù)據(jù)加密標準,速度較快,適用于加密大量數(shù)據(jù)的場合 3DES(Triple DES):是基于 DES,對一塊數(shù)據(jù)用三個不同的密鑰進行三次加密,強度更高AES(Advanced Encryption Standard):高級加密標準,是下一代的加密算法標準,速度快,安全級別高 CBC 分組加密的四種模式之一 ECB、CBC、CFB、OFB
對稱加密又分為分組加密和序列密碼
分組密碼,也叫塊加密
block cyphers,一次加密明文中的一個塊。是將明文按一定的位長分組,明文組經(jīng)過加密運算得到密文組,密文組經(jīng)過解密運算(加密運算的逆運算),還原成明文組序列密碼,也叫流加密
stream cyphers,一次加密明文中的一個位。是指利用少量的密鑰(制亂元素)通過某種復(fù)雜的運算(密碼算法)產(chǎn)生大量的偽隨機位流,用于對明文位流的加密
對稱加密的特點
加密過程每一步都是可逆的
加密和解密用的是同一組密鑰
2、DES
2.1 概述
DES(Data Encryption Standard)數(shù)據(jù)加密標準,是目前最為流行的加密算法之一
DES 是一種使用密鑰加密的塊算法,1977年被美國聯(lián)邦政府的國家標準局確定為聯(lián)邦資料處理標準FIPS,并授權(quán)在非密級政府通信中使用,隨后該算法在國際上廣泛流傳開來
AES 與 3DES 的比較
| 算法名稱 | 算法類型 | 密鑰長度 | 速度 | 解密時間(建設(shè)機器每秒嘗試 255 個密鑰) | 資源消耗 |
|---|---|---|---|---|---|
| AES | 對稱 block 密碼 | 128、192、256 位 | 高 | 1490000 億年 | 低 |
| 3DES | 對稱 feistel 密碼 | 112 位或 168 位 | 低 | 46 億年 | 中 |
破解歷史
歷史上有三次對DES有影響的攻擊實驗。1997年,利用當(dāng)時各國 7萬臺計算機,歷時96天破解了DES的密鑰。1998年,電子邊境基金會(EFF)用25萬美元制造的專用計算機,用56小時破解了DES的密鑰。1999 年,EFF用22小時15分完成了破解工作
2.2 主要思路
對原始數(shù)據(jù)(明文)進行分組,每組64位bit,最后一組不足64位時按一定規(guī)則填充,每一組上單獨施加DES算法
2.3 DES 子密鑰生成
第一步
初始密鑰64位,實際有效位56位,每隔7位有一個校驗位
根據(jù)初始密鑰生成16個48位的字密鑰
密鑰置換(打散),64——>56

例如,第57位放在第1個位置,第49位放在第2個位置,將順序打亂并去除了校驗位
第二步
左旋右旋,再次置換 56——>48

2.4 DES 加密過程
明文——>初始置換——>L0(32位)、R0(32位)

S盒替換的邏輯
輸入48位,輸出32位,各分為8組,輸入每組6位,輸出每組4位
分別在每組上施加S盒替換,一共8個S盒

合并
L16(32位)、R16(32位)——>合并——>最終置換——>密文(64位)
2.5 使用示例
/DesEncrypt?DES加密
//密鑰必須是64位,所以key必須是長度為8的byte數(shù)組
func?DesEncrypt(text?string,?key?[]byte)?(string,?error)?{
?if?len(key)?!=?8?{
??return?"",?fmt.Errorf("DES加密算法要求key必須是64位bit")
?}
?block,?err?:=?des.NewCipher(key)?//用des創(chuàng)建一個加密器cipher
?if?err?!=?nil?{
??return?"",?err
?}
?src?:=?[]byte(text)
?blockSize?:=?block.BlockSize()???????????//分組的大小,blockSize=8
?src?=?common.ZeroPadding(src,?blockSize)?//填充成64位整倍數(shù)
?out?:=?make([]byte,?len(src))?//密文和明文的長度一致
?dst?:=?out
?for?len(src)?>?0?{
??//分組加密
??block.Encrypt(dst,?src[:blockSize])?//對src進行加密,加密結(jié)果放到dst里
??//移到下一組
??src?=?src[blockSize:]
??dst?=?dst[blockSize:]
?}
?return?hex.EncodeToString(out),?nil
}
//DesDecrypt?DES解密
//密鑰必須是64位,所以key必須是長度為8的byte數(shù)組
func?DesDecrypt(text?string,?key?[]byte)?(string,?error)?{
?src,?err?:=?hex.DecodeString(text)?//轉(zhuǎn)成[]byte
?if?err?!=?nil?{
??return?"",?err
?}
?block,?err?:=?des.NewCipher(key)
?if?err?!=?nil?{
??return?"",?err
?}
?blockSize?:=?block.BlockSize()
?out?:=?make([]byte,?len(src))
?dst?:=?out
?for?len(src)?>?0?{
??//分組解密
??block.Decrypt(dst,?src[:blockSize])
??src?=?src[blockSize:]
??dst?=?dst[blockSize:]
?}
?out?=?common.ZeroUnPadding(out)?//反填充
?return?string(out),?nil
}
2.6 分組模式
CBC(Cipher Block Chaining)密文分組鏈接模式,將當(dāng)前明文分組與前一個密文分組進行異或運算,然后再進行加密 其他分組模式還有 ECB、CTR、CFR、OFB
分組模式使用示例
func?DesEncryptCBC(text?string,?key?[]byte)?(string,?error)?{
?src?:=?[]byte(text)
?block,?err?:=?des.NewCipher(key)?//用des創(chuàng)建一個加密器cipher
?if?err?!=?nil?{
??return?"",?err
?}
?blockSize?:=?block.BlockSize()???????????//分組的大小,blockSize=8
?src?=?common.ZeroPadding(src,?blockSize)?//填充
?out?:=?make([]byte,?len(src))???????????????????//密文和明文的長度一致
?encrypter?:=?cipher.NewCBCEncrypter(block,?key)?//CBC分組模式加密
?encrypter.CryptBlocks(out,?src)
?return?hex.EncodeToString(out),?nil
}
func?DesDecryptCBC(text?string,?key?[]byte)?(string,?error)?{
?src,?err?:=?hex.DecodeString(text)?//轉(zhuǎn)成[]byte
?if?err?!=?nil?{
??return?"",?err
?}
?block,?err?:=?des.NewCipher(key)
?if?err?!=?nil?{
??return?"",?err
?}
?out?:=?make([]byte,?len(src))???????????????????//密文和明文的長度一致
?encrypter?:=?cipher.NewCBCDecrypter(block,?key)?//CBC分組模式解密
?encrypter.CryptBlocks(out,?src)
?out?=?common.ZeroUnPadding(out)?//反填充
?return?string(out),?nil
}
3、AES
AES(Advanced Encryption Standard)高級加密標準,旨在取代DES
2000年10月,NIST(美國國家標準和技術(shù)協(xié)會)宣布通過從15種侯選算法中選出的一項新的密匙加密標準。Rijndael被選中成為將來的AES。Rijndael是在1999年下半年,由研究員Joan Daemen和Vincent Rijmen創(chuàng)建的。AES正日益成為加密各種形式的電子數(shù)據(jù)的實際標準
并于2002年5月26日制定了新的高級加密標準AES規(guī)范
算法原理
AES算法基于排列和置換運算。排列是對數(shù)據(jù)重新進行安排,置換是將一個數(shù)據(jù)單元替換為另一個。AES使用幾種不同的方法來執(zhí)行排列和置換運算。AES是一個迭代的、對稱密鑰分組的密碼,它可以使用128、192和256位密鑰,并且用128位(16字節(jié))分組加密和解密數(shù)據(jù)。與公共密鑰密碼使用密鑰對不同,對稱密鑰密碼使用相同的密鑰加密和解密數(shù)據(jù)。通過分組密碼返回的加密數(shù)據(jù)的位數(shù)與輸入數(shù)據(jù)相同。迭代加密使用一個循環(huán)結(jié)構(gòu),在該循環(huán)中重復(fù)置換和替換輸入數(shù)據(jù)
綜上看來AES安全度最高, 基本現(xiàn)狀就是AES已經(jīng)替代DES成為新一代對稱加密的標準
AES使用示例
package?main
import?(
?"crypto/aes"
?"crypto/cipher"
?"fmt"
)
var?commonIV?=?[]byte{0x00,?0x01,?0x02,?0x03,?0x04,?0x05,?0x06,?0x07,?0x08,?0x09,?0x0a,?0x0b,?0x0c,?0x0d,?0x0e,?0x0f}
func?encrypt(plainText?string,?keyText?string)?(cipherByte?[]byte,?err?error)?{
?//?轉(zhuǎn)換成字節(jié)數(shù)據(jù),?方便加密
?plainByte?:=?[]byte(plainText)
?keyByte?:=?[]byte(keyText)
?//?創(chuàng)建加密算法aes
?c,?err?:=?aes.NewCipher(keyByte)
?if?err?!=?nil?{
??return?nil,?err
?}
?//加密字符串
?cfb?:=?cipher.NewCFBEncrypter(c,?commonIV)
?cipherByte?=?make([]byte,?len(plainByte))
?cfb.XORKeyStream(cipherByte,?plainByte)
?return
}
func?decrypt(cipherByte?[]byte,?keyText?string)?(plainText?string,?err?error)?{
?//?轉(zhuǎn)換成字節(jié)數(shù)據(jù),?方便加密
?keyByte?:=?[]byte(keyText)
?//?創(chuàng)建加密算法aes
?c,?err?:=?aes.NewCipher(keyByte)
?if?err?!=?nil?{
??return?"",?err
?}
?//?解密字符串
?cfbdec?:=?cipher.NewCFBDecrypter(c,?commonIV)
?plainByte?:=?make([]byte,?len(cipherByte))
?cfbdec.XORKeyStream(plainByte,?cipherByte)
?plainText?=?string(plainByte)
?return
}
func?main()?{
?plain?:=?"The?text?need?to?be?encrypt."
?//?AES?規(guī)定有3種長度的key:?16,?24,?32分別對應(yīng)AES-128,?AES-192,?or?AES-256
?key?:=?"abcdefgehjhijkmlkjjwwoew"
?//?加密
?cipherByte,?err?:=?encrypt(plain,?key)
?if?err?!=?nil?{
??fmt.Println(err)
?}
?fmt.Printf("%s?==>?%x\n",?plain,?cipherByte)
?//?解密
?plainText,?err?:=?decrypt(cipherByte,?key)
?if?err?!=?nil?{
??fmt.Println(err)
?}
?fmt.Printf("%x?==>?%s\n",?cipherByte,?plainText)
}
4、CBC
分組密碼,也叫塊加密block cyphers,一次加密明文中的一個塊。是將明文按一定的位長分組,明文組經(jīng)過加密運算得到密文組,密文組經(jīng)過解密運算(加密運算的逆運算),還原成明文組。序列密碼,也叫流加密stream cyphers,一次加密明文中的一個位。是指利用少量的密鑰(制亂元素)通過某種復(fù)雜的運算(密碼算法)產(chǎn)生大量的偽隨機位流,用于對明文位流的加密。解密是指用同樣的密鑰和密碼算法及與加密相同的偽隨機位流,用以還原明文位流
分組加密算法中,有ECB,CBC,CFB,OFB這幾種算法模式, 我們介紹其中常用的一種CBC
CBC(Cipher Block Chaining)密文分組鏈接方式
加密步驟如下:
首先將數(shù)據(jù)按照 8 個字節(jié)一組進行分組得到 D1D2......Dn(若數(shù)據(jù)不是 8 的整數(shù)倍,用指定的PADDING數(shù)據(jù)補位)第一組數(shù)據(jù) D1與初始化向量 I 異或后的結(jié)果進行DES加密得到第一組密文C1(初始化向量 I 為全零)第二組數(shù)據(jù) D2與第一組的加密結(jié)果C1異或以后的結(jié)果進行DES加密,得到第二組密文C2之后的數(shù)據(jù)以此類推,得到 Cn按順序連為 C1C2C3......Cn即為加密結(jié)果
//?aesCBCEncrypt?aes加密,填充秘鑰key的16位,24,32分別對應(yīng)AES-128,?AES-192,?or?AES-256.
func?aesCBCEncrypt(rawData,?key?[]byte)?([]byte,?error)?{
?block,?err?:=?aes.NewCipher(key)
?if?err?!=?nil?{
??return?nil,?err
?}
?//填充原文
?blockSize?:=?block.BlockSize()
?rawData?=?pkcs7Padding(rawData,?blockSize)
?//初始向量IV必須是唯一,但不需要保密
?cipherText?:=?make([]byte,?blockSize+len(rawData))
?//block大小?16
?iv?:=?cipherText[:blockSize]
?if?_,?err?:=?io.ReadFull(rand.Reader,?iv);?err?!=?nil?{
??return?nil,?err
?}
?//block大小和初始向量大小一定要一致
?mode?:=?cipher.NewCBCEncrypter(block,?iv)
?mode.CryptBlocks(cipherText[blockSize:],?rawData)
?return?cipherText,?nil
}
解密是加密的逆過程,步驟如下:
首先將數(shù)據(jù)按照 8個字節(jié)一組進行分組得到C1C2C3......Cn將第一組數(shù)據(jù)進行解密后與初始化向量 I進行異或得到第一組明文D1(注意:一定是先解密再異或)將第二組數(shù)據(jù) C2進行解密后與第一組密文數(shù)據(jù)進行異或得到第二組數(shù)據(jù)D2之后依此類推,得到 Dn按順序連為 D1D2D3......Dn即為解密結(jié)果
func?aesCBCDecrypt(encryptData,?key?[]byte)?([]byte,?error)?{
?block,?err?:=?aes.NewCipher(key)
?if?err?!=?nil?{
??return?nil,?err
?}
?blockSize?:=?block.BlockSize()
?if?len(encryptData)???return?nil,?errors.New("ciphertext?too?short")
?}
?iv?:=?encryptData[:blockSize]
?encryptData?=?encryptData[blockSize:]
?//?CBC?mode?always?works?in?whole?blocks.
?if?len(encryptData)%blockSize?!=?0?{
??return?nil,?errors.New("ciphertext?is?not?a?multiple?of?the?block?size")
?}
?mode?:=?cipher.NewCBCDecrypter(block,?iv)
?//?CryptBlocks?can?work?in-place?if?the?two?arguments?are?the?same.
?mode.CryptBlocks(encryptData,?encryptData)
?//解填充
?encryptData?=?pkcs7UnPadding(encryptData)
?return?encryptData,?nil
}
這里要注意的是,解密的結(jié)果并不一定是我們原來的加密數(shù)據(jù),可能還含有補位,一定要把補位去掉才是原來的數(shù)據(jù)
特點:
不容易主動攻擊,安全性好于 ECB,適合傳輸長度長的報文,是SSL、IPSec的標準。每個密文塊依賴于所有的信息塊, 明文消息中一個改變會影響所有密文塊發(fā)送方和接收方都需要知道初始化向量 加密過程是串行的,無法被并行化(在解密時,從兩個鄰接的密文塊中即可得到一個平文塊。因此,解密過程可以被并行化)
See you ~
歡迎進群一起進行技術(shù)交流
加群方式:公眾號消息私信“加群”或加我好友再加群均可
