github.com/emmansun/gmsm@v0.29.1/sm4/cbc_cipher_asm.go (about)

     1  //go:build (amd64 || arm64 || ppc64 || ppc64le) && !purego
     2  
     3  package sm4
     4  
     5  import (
     6  	"crypto/cipher"
     7  
     8  	"github.com/emmansun/gmsm/internal/alias"
     9  	"github.com/emmansun/gmsm/internal/subtle"
    10  )
    11  
    12  // Assert that sm4CipherAsm implements the cbcEncAble and cbcDecAble interfaces.
    13  var _ cbcEncAble = (*sm4CipherAsm)(nil)
    14  var _ cbcDecAble = (*sm4CipherAsm)(nil)
    15  
    16  const cbcEncrypt = 1
    17  const cbcDecrypt = 0
    18  
    19  type cbc struct {
    20  	b   *sm4CipherAsm
    21  	iv  []byte
    22  	enc int
    23  }
    24  
    25  func (b *sm4CipherAsm) NewCBCEncrypter(iv []byte) cipher.BlockMode {
    26  	var c cbc
    27  	c.b = b
    28  	c.enc = cbcEncrypt
    29  	c.iv = make([]byte, BlockSize)
    30  	copy(c.iv, iv)
    31  	return &c
    32  }
    33  
    34  func (b *sm4CipherAsm) NewCBCDecrypter(iv []byte) cipher.BlockMode {
    35  	var c cbc
    36  	c.b = b
    37  	c.enc = cbcDecrypt
    38  	c.iv = make([]byte, BlockSize)
    39  	copy(c.iv, iv)
    40  	return &c
    41  }
    42  
    43  func (x *cbc) BlockSize() int { return BlockSize }
    44  
    45  //go:noescape
    46  func decryptBlocksChain(xk *uint32, dst, src []byte, iv *byte)
    47  
    48  func (x *cbc) CryptBlocks(dst, src []byte) {
    49  	if len(src)%BlockSize != 0 {
    50  		panic("cipher: input not full blocks")
    51  	}
    52  	if len(dst) < len(src) {
    53  		panic("cipher: output smaller than input")
    54  	}
    55  	if alias.InexactOverlap(dst[:len(src)], src) {
    56  		panic("cipher: invalid buffer overlap")
    57  	}
    58  	if len(src) == 0 {
    59  		return
    60  	}
    61  	if x.enc == cbcEncrypt {
    62  		iv := x.iv
    63  
    64  		for len(src) >= BlockSize {
    65  			// Write the xor to dst, then encrypt in place.
    66  			subtle.XORBytes(dst[:BlockSize], src[:BlockSize], iv)
    67  			x.b.encrypt(dst[:BlockSize], dst[:BlockSize])
    68  
    69  			// Move to the next block with this block as the next iv.
    70  			iv = dst[:BlockSize]
    71  			src = src[BlockSize:]
    72  			dst = dst[BlockSize:]
    73  		}
    74  
    75  		// Save the iv for the next CryptBlocks call.
    76  		copy(x.iv, iv)
    77  		return
    78  	}
    79  
    80  	decryptBlocksChain(&x.b.dec[0], dst, src, &x.iv[0])
    81  }
    82  
    83  func (x *cbc) SetIV(iv []byte) {
    84  	if len(iv) != BlockSize {
    85  		panic("cipher: incorrect length IV")
    86  	}
    87  	copy(x.iv[:], iv)
    88  }