gmsm/sm4/cbc_cipher_asm.go
2024-03-27 13:08:27 +08:00

89 lines
1.8 KiB
Go

//go:build (amd64 || arm64) && !purego
package sm4
import (
"crypto/cipher"
"github.com/emmansun/gmsm/internal/alias"
"github.com/emmansun/gmsm/internal/subtle"
)
// Assert that sm4CipherAsm implements the cbcEncAble and cbcDecAble interfaces.
var _ cbcEncAble = (*sm4CipherAsm)(nil)
var _ cbcDecAble = (*sm4CipherAsm)(nil)
const cbcEncrypt = 1
const cbcDecrypt = 0
type cbc struct {
b *sm4CipherAsm
iv []byte
enc int
}
func (b *sm4CipherAsm) NewCBCEncrypter(iv []byte) cipher.BlockMode {
var c cbc
c.b = b
c.enc = cbcEncrypt
c.iv = make([]byte, BlockSize)
copy(c.iv, iv)
return &c
}
func (b *sm4CipherAsm) NewCBCDecrypter(iv []byte) cipher.BlockMode {
var c cbc
c.b = b
c.enc = cbcDecrypt
c.iv = make([]byte, BlockSize)
copy(c.iv, iv)
return &c
}
func (x *cbc) BlockSize() int { return BlockSize }
//go:noescape
func decryptBlocksChain(xk *uint32, dst, src []byte, iv *byte)
func (x *cbc) CryptBlocks(dst, src []byte) {
if len(src)%BlockSize != 0 {
panic("cipher: input not full blocks")
}
if len(dst) < len(src) {
panic("cipher: output smaller than input")
}
if alias.InexactOverlap(dst[:len(src)], src) {
panic("cipher: invalid buffer overlap")
}
if len(src) == 0 {
return
}
if x.enc == cbcEncrypt {
iv := x.iv
for len(src) >= BlockSize {
// Write the xor to dst, then encrypt in place.
subtle.XORBytes(dst[:BlockSize], src[:BlockSize], iv)
x.b.encrypt(dst[:BlockSize], dst[:BlockSize])
// Move to the next block with this block as the next iv.
iv = dst[:BlockSize]
src = src[BlockSize:]
dst = dst[BlockSize:]
}
// Save the iv for the next CryptBlocks call.
copy(x.iv, iv)
return
}
decryptBlocksChain(&x.b.dec[0], dst, src, &x.iv[0])
}
func (x *cbc) SetIV(iv []byte) {
if len(iv) != BlockSize {
panic("cipher: incorrect length IV")
}
copy(x.iv[:], iv)
}