您好,登錄后才能下訂單哦!
之前介紹的DES、3DES、AES加密算法,只能加密固定長度的明文。如果需要加密任意長度的明文,需要對明文分組加密。DES、3DES、AES等又稱分組密碼,而分組有很多模式,如:ECB模式、CBC模式、CFB模式、OFB模式、CTR模式,如下將逐一介紹。
?
ECB模式,全稱Electronic Codebook模式,譯為電子密碼本模式,即用相同的密碼分別對明文分組獨立加密。ECB模式是最簡單的模式,因為相同的明文分組會加密為相同的密文分組,因此存在一定風(fēng)險。
?
如下為ECB模式示意圖:
?
?
另外當(dāng)最后一個明文分組的內(nèi)容,小于分組長度時,需要用特定的數(shù)據(jù)進(jìn)行填充。
?
?
CBC模式,全稱Cipher Block Chaining模式,譯為密文分組鏈接模式,即加密算法的輸入是上一個密文分組和下一個明文分組的異或。因為是將上一個密文分組和下一個明文分組的內(nèi)容混合加密,因此可以避免ECB模式的缺陷。當(dāng)加密第一個明文分組時,由于不存在上一個密文分組,因此需要準(zhǔn)備與分組等長的初始化向量IV,來代替上一個密文分組。
?
如下為CBC模式示意圖:
?
?
go標(biāo)準(zhǔn)庫中CBC模式代碼如下:
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 {
//上一個密文分組和下一個明文分組的異或
//當(dāng)加密第一個明文分組時,使用初始化向量IV
xorBytes(dst[:x.blockSize], src[:x.blockSize], iv)
//執(zhí)行加密算法
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模式,全稱Cipher FeedBack模式,譯為密文反饋模式,即上一個密文分組作為加密算法的輸入,輸出與明文異或作為下一個分組的密文。在CFB模式中,明文分組和密文分組之間只有一次異或。
?
如下為CFB模式示意圖:
?
?
CFB模式與一次性密碼本相似,都是通過將明文與隨機(jī)比特序列進(jìn)行異或運算來生成密文。但由于CFB模式中密碼算法的輸出是通過計算得到的,并非真正的隨機(jī)數(shù),因此不具備一次性密碼本那樣理論上不可破譯的性質(zhì)。CFB模式可以看做使用分組方式實現(xiàn)流密碼的方式。
?
go標(biāo)準(zhǔn)庫中CFB模式代碼如下:
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模式,全稱Output Feedback模式,譯為輸出反饋模式。OFB模式與CFB模式類似,只是加密算法的輸入是上一次加密的輸出。在OFB模式中,異或所需的密鑰流,可以事先通過密碼算法生成,即生成密鑰流的操作可以與異或運算并行。
?
OFB模式加密和處理解密邏輯相同,明文與密鑰流異或生成密文,密文與密鑰流異或生成明文。
?
如下為OFB模式示意圖:
?
?
go標(biāo)準(zhǔn)庫中OFB模式代碼如下:
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模式,全稱Counter模式,譯為計數(shù)器模式。CTR模式中,每個分組對應(yīng)一個逐次累加的計數(shù)器,并通過對計數(shù)器進(jìn)行加密來生成密鑰流。也即最終的密文分組是通過將計數(shù)器加密得到的比特序列,與明文分組進(jìn)行異或運算得到的。
?
如下為CTR模式示意圖:
?
?
go標(biāo)準(zhǔn)庫中CTR模式代碼如下:
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
//計數(shù)器遞增
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
}
}
?
代碼如下:
//AES加密、CBC模式、PKCS7填充算法
func AESCBCPKCS7Encrypt(key, src []byte) ([]byte, error) {
//PKCS7填充算法
tmp := pkcs7Padding(src)
//AES加密、CBC模式
return aesCBCEncrypt(key, tmp)
}
//PKCS7填充算法
//PKCS7即填充字符串由一個字節(jié)序列組成,每個字節(jié)填充該字節(jié)序列的長度
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模式因其高風(fēng)險,不應(yīng)再使用。CBC模式、CFB模式、OFB模式、CTR模式,均可使用。其中Fabric中使用了CBC模式。
待續(xù)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。