區塊鏈背後的資訊保安(5) 對稱加密演算法的分組模式及其Go語言實現
# 對稱加密演算法的分組模式及其Go語言實現
之前介紹的DES、3DES、AES加密演算法,只能加密固定長度的明文。如果需要加密任意長度的明文,需要對明文分組加密。
DES、3DES、AES等又稱分組密碼,而分組有很多模式,如:ECB模式、CBC模式、CFB模式、OFB模式、CTR模式,如下將逐一介紹。
## ECB模式
ECB模式,全稱Electronic Codebook模式,譯為電子密碼本模式,即用相同的密碼分別對明文分組獨立加密。
ECB模式是最簡單的模式,因為相同的明文分組會加密為相同的密文分組,因此存在一定風險。
如下為ECB模式示意圖:
另外當最後一個明文分組的內容,小於分組長度時,需要用特定的資料進行填充。
## CBC模式
CBC模式,全稱Cipher Block Chaining模式,譯為密文分組連結模式,即加密演算法的輸入是上一個密文分組和下一個明文分組的異或。
因為是將上一個密文分組和下一個明文分組的內容混合加密,因此可以避免ECB模式的缺陷。
當加密第一個明文分組時,由於不存在上一個密文分組,因此需要準備與分組等長的初始化向量IV,來代替上一個密文分組。
如下為CBC模式示意圖:
go標準庫中CBC模式程式碼如下:
```go
type cbc struct {
//b為加密演算法,如DES、AES
b Block
//加密演算法支援的明文分組長度
blockSize int
//初始化向量IV
iv []byte
//臨時變數
tmp []byte
}
type cbcEncrypter cbc
//指定加密演算法和IV
func NewCBCEncrypter(b Block, iv []byte) BlockMode {
if len(iv) != b.BlockSize() {
panic("cipher.NewCBCEncrypter: IV length must equal block size")
}
if cbc, ok := b.(cbcEncAble); ok {
return cbc.NewCBCEncrypter(iv)
}
return (*cbcEncrypter)(newCBC(b, iv))
}
//加密
func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
iv := x.iv
for len(src) > 0 {
//上一個密文分組和下一個明文分組的異或
//當加密第一個明文分組時,使用初始化向量IV
xorBytes(dst[:x.blockSize], src[:x.blockSize], iv)
//執行加密演算法
x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize])
iv = dst[:x.blockSize]
src = src[x.blockSize:]
dst = dst[x.blockSize:]
}
copy(x.iv, iv)
}
//程式碼位置src/crypto/cipher/cbc.go
```
## CFB模式
CFB模式,全稱Cipher FeedBack模式,譯為密文反饋模式,即上一個密文分組作為加密演算法的輸入,輸出與明文異或作為下一個分組的密文。
在CFB模式中,明文分組和密文分組之間只有一次異或。
如下為CFB模式示意圖:
CFB模式與一次性密碼本相似,都是通過將明文與隨機位元序列進行異或運算來生成密文。
但由於CFB模式中密碼演算法的輸出是通過計算得到的,並非真正的隨機數,因此不具備一次性密碼本那樣理論上不可破譯的性質。
CFB模式可以看做使用分組方式實現流密碼的方式。
go標準庫中CFB模式程式碼如下:
```go
type cfb struct {
//加密演算法
b Block
//加密的輸入
next []byte
//加密的輸出
out []byte
outUsed int
decrypt bool
}
//加密或解密
//decrypt為true表示解密
func (x *cfb) XORKeyStream(dst, src []byte) {
for len(src) > 0 {
if x.outUsed == len(x.out) {
x.b.Encrypt(x.out, x.next)
x.outUsed = 0
}
if x.decrypt {
copy(x.next[x.outUsed:], src)
}
//加密輸出與明文異或作為下一個分組的密文
n := xorBytes(dst, src, x.out[x.outUsed:])
if !x.decrypt {
//上一個密文分組作為加密演算法的輸入
copy(x.next[x.outUsed:], dst)
}
dst = dst[n:]
src = src[n:]
x.outUsed += n
}
}
//加密器
func NewCFBEncrypter(block Block, iv []byte) Stream {
return newCFB(block, iv, false)
}
//解密器
func NewCFBDecrypter(block Block, iv []byte) Stream {
return newCFB(block, iv, true)
}
func newCFB(block Block, iv []byte, decrypt bool) Stream {
//分組長度
blockSize := block.BlockSize()
if len(iv) != blockSize {
//初始化向量要求與分組長度等長
panic("cipher.newCFB: IV length must equal block size")
}
x := &cfb{
b: block,
out: make([]byte, blockSize),
next: make([]byte, blockSize),
outUsed: blockSize,
decrypt: decrypt,
}
//加密的輸入
copy(x.next, iv)
return x
}
//程式碼位置src/crypto/cipher/cfb.go
```
## OFB模式
OFB模式,全稱Output Feedback模式,譯為輸出反饋模式。
OFB模式與CFB模式類似,只是加密演算法的輸入是上一次加密的輸出。
在OFB模式中,異或所需的金鑰流,可以事先通過密碼演算法生成,即生成金鑰流的操作可以與異或運算並行。
OFB模式加密和處理解密邏輯相同,明文與金鑰流異或生成密文,密文與金鑰流異或生成明文。
如下為OFB模式示意圖:
go標準庫中OFB模式程式碼如下:
```go
type ofb struct {
//加密演算法
b Block
//加密的輸入
cipher []byte
out []byte
outUsed int
}
func NewOFB(b Block, iv []byte) Stream {
//分組長度
blockSize := b.BlockSize()
if len(iv) != blockSize {
return nil
}
//const streamBufferSize = 512
bufSize := streamBufferSize
if bufSize < blockSize {
bufSize = blockSize
}
x := &ofb{
b: b,
cipher: make([]byte, blockSize),
out: make([]byte, 0, bufSize),
outUsed: 0,
}
//加密的輸入
copy(x.cipher, iv)
return x
}
//生成金鑰流
func (x *ofb) refill() {
bs := x.b.BlockSize()
remain := len(x.out) - x.outUsed
if remain > x.outUsed {
return
}
copy(x.out, x.out[x.outUsed:])
x.out = x.out[:cap(x.out)]
for remain < len(x.out)-bs {
x.b.Encrypt(x.cipher, x.cipher)
copy(x.out[remain:], x.cipher)
remain += bs
}
x.out = x.out[:remain]
x.outUsed = 0
}
func (x *ofb) XORKeyStream(dst, src []byte) {
for len(src) > 0 {
if x.outUsed >= len(x.out)-x.b.BlockSize() {
//生成金鑰流
x.refill()
}
//與金鑰流異或運算
n := xorBytes(dst, src, x.out[x.outUsed:])
dst = dst[n:]
src = src[n:]
x.outUsed += n
}
}
//程式碼位置src/crypto/cipher/ofb.go
```
## CTR模式
CTR模式,全稱Counter模式,譯為計數器模式。
CTR模式中,每個分組對應一個逐次累加的計數器,並通過對計數器進行加密來生成金鑰流。
也即最終的密文分組是通過將計數器加密得到的位元序列,與明文分組進行異或運算得到的。
如下為CTR模式示意圖:
go標準庫中CTR模式程式碼如下:
```go
type ctr struct {
//加密演算法
b Block
//加密的輸入
ctr []byte
out []byte
outUsed int
}
const streamBufferSize = 512
type ctrAble interface {
NewCTR(iv []byte) Stream
}
func NewCTR(block Block, iv []byte) Stream {
if ctr, ok := block.(ctrAble); ok {
return ctr.NewCTR(iv)
}
if len(iv) != block.BlockSize() {
panic("cipher.NewCTR: IV length must equal block size")
}
bufSize := streamBufferSize
if bufSize < block.BlockSize() {
bufSize = block.BlockSize()
}
return &ctr{
b: block,
ctr: dup(iv),
out: make([]byte, 0, bufSize),
outUsed: 0,
}
}
//生成金鑰流
func (x *ctr) refill() {
remain := len(x.out) - x.outUsed
copy(x.out, x.out[x.outUsed:])
x.out = x.out[:cap(x.out)]
bs := x.b.BlockSize()
for remain <= len(x.out)-bs {
x.b.Encrypt(x.out[remain:], x.ctr)
remain += bs
//計數器遞增
for i := len(x.ctr) - 1; i >= 0; i-- {
x.ctr[i]++
if x.ctr[i] != 0 {
break
}
}
}
x.out = x.out[:remain]
x.outUsed = 0
}
func (x *ctr) XORKeyStream(dst, src []byte) {
for len(src) > 0 {
if x.outUsed >= len(x.out)-x.b.BlockSize() {
//生成金鑰流
x.refill()
}
//與金鑰流異或運算
n := xorBytes(dst, src, x.out[x.outUsed:])
dst = dst[n:]
src = src[n:]
x.outUsed += n
}
}
```
## Fabric中CBC模式的AES加密實現
程式碼如下:
```go
//AES加密、CBC模式、PKCS7填充演算法
func AESCBCPKCS7Encrypt(key, src []byte) ([]byte, error) {
//PKCS7填充演算法
tmp := pkcs7Padding(src)
//AES加密、CBC模式
return aesCBCEncrypt(key, tmp)
}
//PKCS7填充演算法
//PKCS7即填充字串由一個位元組序列組成,每個位元組填充該位元組序列的長度
func pkcs7Padding(src []byte) []byte {
padding := aes.BlockSize - len(src)%aes.BlockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(src, padtext...)
}
//AES加密、CBC模式
func aesCBCEncrypt(key, s []byte) ([]byte, error) {
if len(s)%aes.BlockSize != 0 {
return nil, errors.New("Invalid plaintext. It must be a multiple of the block size")
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
ciphertext := make([]byte, aes.BlockSize+len(s))
//初始向量IV
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], s)
return ciphertext, nil
}
//程式碼位置github.com/hyperledger/fabric/bccsp/sw/aes.go
```
## 後記
ECB模式因其高風險,不應再使用。
CBC模式、CFB模式、OFB模式、CTR模式,均可使用。
其中Fabric中使用了CBC模式。
待續。
網址:http://www.qukuailianxueyuan.io/
欲領取造幣技術與全套虛擬機器資料
區塊鏈技術交流QQ群:756146052 備註:CSDN
尹成學院微信:備註:CSDN
相關文章
- 區塊鏈背後的資訊保安(1)AES加密演算法原理及其GO語言實現區塊鏈加密演算法Go
- 區塊鏈背後的資訊保安(2) DES、3DES加密演算法原理及其GO語言實現區塊鏈3D加密演算法Go
- 區塊鏈背後的資訊保安(4)RSA加解密及簽名演算法的技術原理及其Go語言實現區塊鏈解密演算法Go
- 區塊鏈背後的資訊保安(3)橢圓曲線加解密及簽名演算法的技術原理及其Go語言實現區塊鏈解密演算法Go
- 兄弟連區塊鏈教程區塊鏈背後的資訊保安2DES、3DES加密演算法原理二區塊鏈3D加密演算法
- 理解區塊鏈的非對稱加密區塊鏈加密
- GO語言實現區塊鏈Part5 AddressesGo區塊鏈
- GO語言實現區塊鏈Part7 NetworkGo區塊鏈
- GO語言實現區塊鏈Part6 Transactions 2Go區塊鏈
- GO語言實現區塊鏈Part4 Transactions 1Go區塊鏈
- GO語言實現區塊鏈Part3 Persistence and CLIGo區塊鏈
- GO語言實現區塊鏈Part1 Basic PrototypeGo區塊鏈
- GIFTO背後區塊鏈技術的分類區塊鏈
- GO語言實現區塊鏈Part2 Proof-of-WorkGo區塊鏈
- 對稱塊加密演算法加密模式詳解 (轉)加密演算法模式
- 如何在NEO區塊鏈上實現資訊加密區塊鏈加密
- 使用 Go 語言打造區塊鏈(二)Go區塊鏈
- 區塊鏈,中心去,何曾著眼看君王?用Go語言實現區塊鏈技術,透過Golang秒懂區塊鏈區塊鏈Golang
- 區塊鏈入門及非對稱加密技術區塊鏈加密
- 非對稱加密-區塊鏈核心技術之一加密區塊鏈
- 實戰區塊鏈技術培訓之Go語言區塊鏈Go
- 用於加密貨幣和區塊鏈的語言Simplicity加密區塊鏈
- go 語言與區塊鏈基礎講解Go區塊鏈
- 區塊鏈開發之Go語言—IO操作區塊鏈Go
- (二)區塊鏈的共識演算法:PoS 及其 例子 程式碼 實現區塊鏈演算法
- Go 語言區塊鏈測試實踐指南(一):GO單元測試Go區塊鏈
- 比原鏈CTO James | Go語言成為區塊鏈主流開發語言的四點理由Go區塊鏈
- 資訊保安:資料加密實戰!對專案中資料使用MD5演算法進行加密加密演算法
- 使用Go語言從零編寫PoS區塊鏈(譯)Go區塊鏈
- Go語言實現HTTPS加密協議GoHTTP加密協議
- 一文搞懂對稱加密:加密演算法、工作模式、填充方式、程式碼實現加密演算法模式
- 兄弟連區塊鏈教程區塊鏈資訊保安3橢圓曲線加解密及簽名演算法的技術原理二區塊鏈解密演算法
- golang 中,非對稱加密的實現Golang加密
- Go語言實現設計模式之命令模式Go設計模式
- Go語言實現位元組記錄鎖Go
- 區塊鏈系列-----加密演算法彙總區塊鏈加密演算法
- 使用MVC模式實現區塊鏈開發MVC模式區塊鏈
- 在Go中構建區塊鏈 第5部分:地址Go區塊鏈