140 lines
4.5 KiB
Go
140 lines
4.5 KiB
Go
// Package blockmodes 使用BlockEncrypter接口封装GCM、CCM等加密模式。
|
|
// 适用于将密码机、ukey的ECB加密模式封装为GCM、CCM等加密模式。
|
|
package blockmode
|
|
|
|
import (
|
|
"crypto/cipher"
|
|
)
|
|
|
|
// var errorCodeBase = gcl.ErrorCodeBaseMap[PACKAGE_NAME]
|
|
|
|
// EcbBlockMode 是对多组数据进行加密/解密运算。可以对密码机等的ECB加密进行封装后得到。
|
|
// GCM模式、CTR等模式将基于EcbBlockMode进行计算。
|
|
// 注:由于Cipher.NewGCM的入参是cipher.Block, 针对单组数据进行的运算,不适合密码机等,
|
|
// 否则每个分组都要调用密码机或ukey,调用消耗巨大。所以这里使用多组加密接口进行GCM、CTR、CCM
|
|
// 等封装。
|
|
type EcbBlockMode interface {
|
|
// 每个分组长度
|
|
BlockSize() int
|
|
|
|
// CryptBlocks 加密多组数据。传入src保证是BlockSize()的整数倍,len(dst) >= len(src)
|
|
// 加密完成后dst[:len(src)]为(ECB)密文。
|
|
// 如果src非常大,BlockEncrypter负责进行分组调用密码机, 可能因为网络等原因会返回错误。
|
|
// 本函数为阻塞函数
|
|
EcbEncCryptBlocks(dst, src []byte) error
|
|
EcbDecCryptBlocks(dst, src []byte) error
|
|
}
|
|
|
|
// CbcBlockMode CBC计算。BlockEncrypter对象也可以做CBC,但是,如果每次分组都去调密码卡或ukey,会非常慢。
|
|
type CbcBlockMode interface {
|
|
// 分组长度
|
|
BlockSize() int
|
|
|
|
// CBCEncrypt CBC加密多组数据。传入src保证是BlockSize()的整数倍,len(dst) >= len(src)
|
|
// iv是BlockSize()大小。 dst和src要么完全重合,要么完全不相交
|
|
// 返回时:如果正常则填充dst[:len(src)]为密文。iv返回时不作要求,可以保持不变,也可以为最后一个分组内容。
|
|
// 如果src非常大,CBCEncrypter负责进行分组调用密码机, 可能因为网络等原因会返回错误。
|
|
// 本函数为阻塞函数
|
|
CbcEncCryptBlocks(dst, iv, src []byte) error
|
|
CbcDecCryptBlocks(dst, iv, src []byte) error
|
|
}
|
|
|
|
type EcbCbcBlockMode interface {
|
|
EcbBlockMode
|
|
CbcBlockMode
|
|
}
|
|
|
|
// 三段式加解密接口
|
|
type TernaryCrypter interface {
|
|
// 三段式加密
|
|
// Init an BlockUpdater. Set nonce as iv and additional data.
|
|
EncryptInit(iv []byte) error
|
|
|
|
// Encrypt 单组加密,等价于调用EncryptUpdate后EncryptFinal
|
|
Encrypt(dst []byte, in []byte) ([]byte, error)
|
|
|
|
// Update appends the encrypted/decrypted result to dst and return it
|
|
EncryptUpdate(dst []byte, in []byte) ([]byte, error)
|
|
// Final 将剩余密文和tag append到out上并返回。返回结果的最后16字节为tag.
|
|
EncryptFinal(dst []byte) ([]byte, error)
|
|
|
|
// 三段式解密
|
|
DecryptInit(iv []byte) error
|
|
Decrypt(dst []byte, in []byte) ([]byte, error)
|
|
DecryptUpdate(dst []byte, in []byte) ([]byte, error)
|
|
DecryptFinal(dst []byte) ([]byte, error)
|
|
}
|
|
|
|
// TernaryGCM 标准库cipher.AEAD和SDF/SKF的三段式用法。
|
|
// 在三段式调用中,若某次返回错误(比如某个大文件已经EncryptUpdate多次了,但如果某次网络原因
|
|
// EncryptUpdate返回错误),则保证内部状态不变, 可以重复该次返错的调用。
|
|
type TernaryGCM interface {
|
|
// 保留标准库用法,AEAD.Seal和AEAD.Open前无需调用EncryptInit/DecryptInit
|
|
cipher.AEAD
|
|
|
|
// SpecifyADD 在三段式调用中必须在调用EncryptInit后调用
|
|
ADDSpecifier
|
|
TernaryCrypter
|
|
}
|
|
|
|
type ADDSpecifier interface {
|
|
SpecifyADD(additionalData []byte)
|
|
}
|
|
|
|
type ADDAndDataLenSpecifier interface {
|
|
SpecifyADDAndDataLen(ad []byte, dataLen int)
|
|
}
|
|
|
|
// Stream for ctr mode
|
|
type TernaryStream interface {
|
|
cipher.Stream
|
|
TernaryCrypter
|
|
}
|
|
|
|
// Wrapper 将一个cipher.Block接口包装为EcbCbcEncBlockMode接口
|
|
type wrapper struct {
|
|
cipher.Block
|
|
}
|
|
|
|
func Wrap(b cipher.Block) EcbCbcBlockMode {
|
|
// If b is also an EcbCbcBlockMode interface.
|
|
if bm, ok := b.(EcbCbcBlockMode); ok {
|
|
return bm
|
|
}
|
|
return wrapper{b}
|
|
}
|
|
|
|
func (w wrapper) BlockSize() int {
|
|
return w.Block.BlockSize()
|
|
}
|
|
|
|
func (w wrapper) EcbEncCryptBlocks(dst, src []byte) error {
|
|
for len(src) > 0 {
|
|
w.Encrypt(dst, src)
|
|
dst = dst[w.BlockSize():]
|
|
src = src[w.BlockSize():]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w wrapper) CbcEncCryptBlocks(dst, iv, src []byte) error {
|
|
cbc := cipher.NewCBCEncrypter(w.Block, iv)
|
|
cbc.CryptBlocks(dst, src)
|
|
return nil
|
|
}
|
|
|
|
func (w wrapper) EcbDecCryptBlocks(dst, src []byte) error {
|
|
for len(src) > 0 {
|
|
w.Decrypt(dst, src)
|
|
dst = dst[w.BlockSize():]
|
|
src = src[w.BlockSize():]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w wrapper) CbcDecCryptBlocks(dst, iv, src []byte) error {
|
|
cbc := cipher.NewCBCDecrypter(w.Block, iv)
|
|
cbc.CryptBlocks(dst, src)
|
|
return nil
|
|
}
|