github.com/emmansun/gmsm@v0.29.1/cipher/bc.go (about) 1 // Block Chaining operation mode (BC mode) in Chinese national standard GB/T 17964-2021. 2 // See GB/T 17964-2021 Chapter 12. 3 package cipher 4 5 import ( 6 _cipher "crypto/cipher" 7 8 "github.com/emmansun/gmsm/internal/subtle" 9 ) 10 11 type bc struct { 12 b _cipher.Block 13 blockSize int 14 iv []byte 15 } 16 17 func newBC(b _cipher.Block, iv []byte) *bc { 18 c := &bc{ 19 b: b, 20 blockSize: b.BlockSize(), 21 iv: make([]byte, b.BlockSize()), 22 } 23 copy(c.iv, iv) 24 return c 25 } 26 27 type bcEncrypter bc 28 29 // bcEncAble is an interface implemented by ciphers that have a specific 30 // optimized implementation of BC encryption. 31 // NewBCEncrypter will check for this interface and return the specific 32 // BlockMode if found. 33 type bcEncAble interface { 34 NewBCEncrypter(iv []byte) _cipher.BlockMode 35 } 36 37 // NewBCEncrypter returns a BlockMode which encrypts in block chaining 38 // mode, using the given Block. The length of iv must be the same as the 39 // Block's block size. 40 func NewBCEncrypter(b _cipher.Block, iv []byte) _cipher.BlockMode { 41 if len(iv) != b.BlockSize() { 42 panic("cipher.NewBCEncrypter: IV length must equal block size") 43 } 44 if bc, ok := b.(bcEncAble); ok { 45 return bc.NewBCEncrypter(iv) 46 } 47 return (*bcEncrypter)(newBC(b, iv)) 48 } 49 50 func (x *bcEncrypter) BlockSize() int { return x.blockSize } 51 52 func (x *bcEncrypter) CryptBlocks(dst, src []byte) { 53 validate(x.blockSize, dst, src) 54 55 iv := x.iv 56 57 for len(src) > 0 { 58 // Write the xor to dst, then encrypt in place. 59 subtle.XORBytes(dst[:x.blockSize], src[:x.blockSize], iv) 60 x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize]) 61 subtle.XORBytes(iv, iv, dst[:x.blockSize]) 62 63 src = src[x.blockSize:] 64 dst = dst[x.blockSize:] 65 } 66 67 // Save the iv for the next CryptBlocks call. 68 copy(x.iv, iv) 69 } 70 71 func (x *bcEncrypter) SetIV(iv []byte) { 72 if len(iv) != len(x.iv) { 73 panic("cipher: incorrect length IV") 74 } 75 copy(x.iv, iv) 76 } 77 78 type bcDecrypter bc 79 80 // bcDecAble is an interface implemented by ciphers that have a specific 81 // optimized implementation of BC decryption. 82 // NewBCDecrypter will check for this interface and return the specific 83 // BlockMode if found. 84 type bcDecAble interface { 85 NewBCDecrypter(iv []byte) _cipher.BlockMode 86 } 87 88 // NewBCDecrypter returns a BlockMode which decrypts in block chaining 89 // mode, using the given Block. The length of iv must be the same as the 90 // Block's block size and must match the iv used to encrypt the data. 91 func NewBCDecrypter(b _cipher.Block, iv []byte) _cipher.BlockMode { 92 if len(iv) != b.BlockSize() { 93 panic("cipher.NewBCDecrypter: IV length must equal block size") 94 } 95 if bc, ok := b.(bcDecAble); ok { 96 return bc.NewBCDecrypter(iv) 97 } 98 return (*bcDecrypter)(newBC(b, iv)) 99 } 100 101 func (x *bcDecrypter) BlockSize() int { return x.blockSize } 102 103 func (x *bcDecrypter) CryptBlocks(dst, src []byte) { 104 validate(x.blockSize, dst, src) 105 106 if len(src) == 0 { 107 return 108 } 109 110 iv := x.iv 111 nextIV := make([]byte, x.blockSize) 112 113 for len(src) > 0 { 114 // Get F(i+1) 115 subtle.XORBytes(nextIV, iv, src[:x.blockSize]) 116 // Get plaintext P(i) 117 x.b.Decrypt(dst[:x.blockSize], src[:x.blockSize]) 118 subtle.XORBytes(dst[:x.blockSize], dst[:x.blockSize], iv) 119 120 copy(iv, nextIV) 121 src = src[x.blockSize:] 122 dst = dst[x.blockSize:] 123 } 124 125 // Save the iv for the next CryptBlocks call. 126 copy(x.iv, iv) 127 } 128 129 func (x *bcDecrypter) SetIV(iv []byte) { 130 if len(iv) != len(x.iv) { 131 panic("cipher: incorrect length IV") 132 } 133 copy(x.iv, iv) 134 }