// 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 }