gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/sm4/ctr_cipher_asm.go (about) 1 //go:build amd64 || arm64 2 // +build amd64 arm64 3 4 package sm4 5 6 import ( 7 "crypto/cipher" 8 9 "gitee.com/ks-custle/core-gm/internal/subtle" 10 "gitee.com/ks-custle/core-gm/internal/xor" 11 ) 12 13 // Assert that sm4CipherAsm implements the ctrAble interface. 14 var _ ctrAble = (*sm4CipherAsm)(nil) 15 16 type ctr struct { 17 b *sm4CipherAsm 18 ctr []byte 19 out []byte 20 outUsed int 21 } 22 23 const streamBufferSize = 512 24 25 // NewCTR returns a Stream which encrypts/decrypts using the SM4 block 26 // cipher in counter mode. The length of iv must be the same as BlockSize. 27 func (sm4c *sm4CipherAsm) NewCTR(iv []byte) cipher.Stream { 28 if len(iv) != BlockSize { 29 panic("cipher.NewCTR: IV length must equal block size") 30 } 31 bufSize := streamBufferSize 32 //goland:noinspection GoBoolExpressions 33 if bufSize < BlockSize { 34 bufSize = BlockSize 35 } 36 s := &ctr{ 37 b: sm4c, 38 ctr: make([]byte, sm4c.batchBlocks*len(iv)), 39 out: make([]byte, 0, bufSize), 40 outUsed: 0, 41 } 42 copy(s.ctr, iv) 43 for i := 1; i < sm4c.batchBlocks; i++ { 44 s.genCtr(i * BlockSize) 45 } 46 return s 47 48 } 49 50 func (x *ctr) genCtr(start int) { 51 if start > 0 { 52 copy(x.ctr[start:], x.ctr[start-BlockSize:start]) 53 } else { 54 copy(x.ctr[start:], x.ctr[len(x.ctr)-BlockSize:]) 55 } 56 // Increment counter 57 end := start + BlockSize 58 for i := end - 1; i >= 0; i-- { 59 x.ctr[i]++ 60 if x.ctr[i] != 0 { 61 break 62 } 63 } 64 } 65 66 func (x *ctr) refill() { 67 remain := len(x.out) - x.outUsed 68 copy(x.out, x.out[x.outUsed:]) 69 x.out = x.out[:cap(x.out)] 70 for remain <= len(x.out)-x.b.blocksSize { 71 x.b.EncryptBlocks(x.out[remain:], x.ctr) 72 remain += x.b.blocksSize 73 74 // Increment counter 75 for i := 0; i < x.b.batchBlocks; i++ { 76 x.genCtr(i * BlockSize) 77 } 78 } 79 x.out = x.out[:remain] 80 x.outUsed = 0 81 } 82 83 func (x *ctr) XORKeyStream(dst, src []byte) { 84 if len(dst) < len(src) { 85 panic("cipher: output smaller than input") 86 } 87 if subtle.InexactOverlap(dst[:len(src)], src) { 88 panic("cipher: invalid buffer overlap") 89 } 90 for len(src) > 0 { 91 if x.outUsed >= len(x.out)-BlockSize { 92 x.refill() 93 } 94 n := xor.XorBytes(dst, src, x.out[x.outUsed:]) 95 dst = dst[n:] 96 src = src[n:] 97 x.outUsed += n 98 } 99 }