golang aes加密 扩展ecb模式

110 阅读2分钟

AES加密属于对称加密(当然还有非对称加密rsa),对称加密一般分为流加密(如OFB、CFB等)和块加密(如ECB、CBC等)。

但是golang的官方库中没有ECB的模式,至于为什么没有ECB模式,可以查看官方issue,意思就是不安全,但是我们确实要使用的话,怎么去实现呢,下面进入正题。

我先把ECB模式实现代码贴出来,有想看分析怎么实现的可以看下面的分析实现过程。

    type ecb struct {
    	b         cipher.Block
    	blockSize int
    }

    func newECB(b cipher.Block) *ecb {
    	return &ecb{
    		b:         b,
    		blockSize: b.BlockSize(),
    	}
    }

    type ecbEncrypter ecb

    func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
    	return (*ecbEncrypter)(newECB(b))
    }

    func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
    func (x *ecbEncrypter) 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")
    	}
    	for len(src) > 0 {
    		x.b.Encrypt(dst, src[:x.blockSize])
    		src = src[x.blockSize:]
    		dst = dst[x.blockSize:]
    	}
    }

    type ecbDecrypter ecb

    func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
    	return (*ecbDecrypter)(newECB(b))
    }
    func (x *ecbDecrypter) BlockSize() int { return x.blockSize }
    func (x *ecbDecrypter) 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")
    	}
    	for len(src) > 0 {
    		x.b.Decrypt(dst, src[:x.blockSize])
    		src = src[x.blockSize:]
    		dst = dst[x.blockSize:]
    	}
    }

使用实例

const (
  CBC = "CBC"
  ECB = "ECB"
)


//创建加密实例
block, err := aes.NewCipher(key)
if err != nil {
        return "", err
}
//判断加密快的大小
blockSize := block.BlockSize()
//填充
encryptBytes := pkcs7Padding(data, blockSize)
//初始化加密数据接收切片
crypted := make([]byte, len(encryptBytes))

var blockMode cipher.BlockMode
//使用cbc加密模式
switch mode {
case ECB:
        blockMode = NewECBEncrypter(block)
case CBC:
        blockMode = cipher.NewCBCEncrypter(block, key[:blockSize])
}
//执行加密
blockMode.CryptBlocks(crypted, encryptBytes)

ECB的实现,可以参照标准库中cbc的实现方式

首先我们看CBC的代码实现

NewCBCEncrypter函数返回了一个BlockMode接口,说明cbcEncrypter是实现了BlockMode接口


type cbc struct {
    b         Block
    blockSize int
    iv        []byte
    tmp       []byte
}

func newCBC(b Block, iv []byte) *cbc {
	return &cbc{
		b:         b,
		blockSize: b.BlockSize(),
		iv:        dup(iv),
		tmp:       make([]byte, b.BlockSize()),
	}
}


type cbcEncrypter cbc

// NewCBCEncrypter函数返回了一个BlockMode接口,说明cbcEncrypter是实现了BlockMode接口
func NewCBCEncrypter(b Block, iv []byte) BlockMode {
	...
	return (*cbcEncrypter)(newCBC(b, iv))
}

type BlockMode interface {
    BlockSize() int
    CryptBlocks(dst, src []byte)
}

我们也可以仿照cbc,用ecb也去实现BlockMode接口


type ecb struct {
	b         cipher.Block
	blockSize int
}

func newECB(b cipher.Block) *ecb {
	return &ecb{
		b:         b,
		blockSize: b.BlockSize(),
	}
}

type ecbEncrypter ecb

func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
	return (*ecbEncrypter)(newECB(b))
}

func (x *ecbEncrypter) BlockSize() int { return x.blockSize }

// 具体这块的算法,就不多讲了,有兴趣了解的朋友,可以去看看cbc和ecb的算法区别
func (x *ecbEncrypter) 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")
	}
	for len(src) > 0 {
		x.b.Encrypt(dst, src[:x.blockSize])
		src = src[x.blockSize:]
		dst = dst[x.blockSize:]
	}
}

image.png

ecbEncrypter也实现了BlockMode的接口,就可以按照cbc的方式进行解密了

	//使用cbc加密模式
    blockMode := cipher.NewCBCEncrypter(block, d.key[:blockSize])
    // 使用ecb加密模式
    blockMode := NewECBEncrypter(block)