github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/crypto/cipher/cbc.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Cipher block chaining (CBC) mode. 6 7 // CBC provides confidentiality by xoring (chaining) each plaintext block 8 // with the previous ciphertext block before applying the block cipher. 9 10 // See NIST SP 800-38A, pp 10-11 11 12 package cipher 13 14 import ( 15 "bytes" 16 "crypto/internal/alias" 17 "crypto/subtle" 18 ) 19 20 type cbc struct { 21 b Block 22 blockSize int 23 iv []byte 24 tmp []byte 25 } 26 27 func newCBC(b Block, iv []byte) *cbc { 28 return &cbc{ 29 b: b, 30 blockSize: b.BlockSize(), 31 iv: bytes.Clone(iv), 32 tmp: make([]byte, b.BlockSize()), 33 } 34 } 35 36 type cbcEncrypter cbc 37 38 // cbcEncAble is an interface implemented by ciphers that have a specific 39 // optimized implementation of CBC encryption, like crypto/aes. 40 // NewCBCEncrypter will check for this interface and return the specific 41 // BlockMode if found. 42 type cbcEncAble interface { 43 NewCBCEncrypter(iv []byte) BlockMode 44 } 45 46 // NewCBCEncrypter returns a BlockMode which encrypts in cipher block chaining 47 // mode, using the given Block. The length of iv must be the same as the 48 // Block's block size. 49 func NewCBCEncrypter(b Block, iv []byte) BlockMode { 50 if len(iv) != b.BlockSize() { 51 panic("cipher.NewCBCEncrypter: IV length must equal block size") 52 } 53 if cbc, ok := b.(cbcEncAble); ok { 54 return cbc.NewCBCEncrypter(iv) 55 } 56 return (*cbcEncrypter)(newCBC(b, iv)) 57 } 58 59 // newCBCGenericEncrypter returns a BlockMode which encrypts in cipher block chaining 60 // mode, using the given Block. The length of iv must be the same as the 61 // Block's block size. This always returns the generic non-asm encrypter for use 62 // in fuzz testing. 63 func newCBCGenericEncrypter(b Block, iv []byte) BlockMode { 64 if len(iv) != b.BlockSize() { 65 panic("cipher.NewCBCEncrypter: IV length must equal block size") 66 } 67 return (*cbcEncrypter)(newCBC(b, iv)) 68 } 69 70 func (x *cbcEncrypter) BlockSize() int { return x.blockSize } 71 72 func (x *cbcEncrypter) CryptBlocks(dst, src []byte) { 73 if len(src)%x.blockSize != 0 { 74 panic("crypto/cipher: input not full blocks") 75 } 76 if len(dst) < len(src) { 77 panic("crypto/cipher: output smaller than input") 78 } 79 if alias.InexactOverlap(dst[:len(src)], src) { 80 panic("crypto/cipher: invalid buffer overlap") 81 } 82 83 iv := x.iv 84 85 for len(src) > 0 { 86 // Write the xor to dst, then encrypt in place. 87 subtle.XORBytes(dst[:x.blockSize], src[:x.blockSize], iv) 88 x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize]) 89 90 // Move to the next block with this block as the next iv. 91 iv = dst[:x.blockSize] 92 src = src[x.blockSize:] 93 dst = dst[x.blockSize:] 94 } 95 96 // Save the iv for the next CryptBlocks call. 97 copy(x.iv, iv) 98 } 99 100 func (x *cbcEncrypter) SetIV(iv []byte) { 101 if len(iv) != len(x.iv) { 102 panic("cipher: incorrect length IV") 103 } 104 copy(x.iv, iv) 105 } 106 107 type cbcDecrypter cbc 108 109 // cbcDecAble is an interface implemented by ciphers that have a specific 110 // optimized implementation of CBC decryption, like crypto/aes. 111 // NewCBCDecrypter will check for this interface and return the specific 112 // BlockMode if found. 113 type cbcDecAble interface { 114 NewCBCDecrypter(iv []byte) BlockMode 115 } 116 117 // NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining 118 // mode, using the given Block. The length of iv must be the same as the 119 // Block's block size and must match the iv used to encrypt the data. 120 func NewCBCDecrypter(b Block, iv []byte) BlockMode { 121 if len(iv) != b.BlockSize() { 122 panic("cipher.NewCBCDecrypter: IV length must equal block size") 123 } 124 if cbc, ok := b.(cbcDecAble); ok { 125 return cbc.NewCBCDecrypter(iv) 126 } 127 return (*cbcDecrypter)(newCBC(b, iv)) 128 } 129 130 // newCBCGenericDecrypter returns a BlockMode which encrypts in cipher block chaining 131 // mode, using the given Block. The length of iv must be the same as the 132 // Block's block size. This always returns the generic non-asm decrypter for use in 133 // fuzz testing. 134 func newCBCGenericDecrypter(b Block, iv []byte) BlockMode { 135 if len(iv) != b.BlockSize() { 136 panic("cipher.NewCBCDecrypter: IV length must equal block size") 137 } 138 return (*cbcDecrypter)(newCBC(b, iv)) 139 } 140 141 func (x *cbcDecrypter) BlockSize() int { return x.blockSize } 142 143 func (x *cbcDecrypter) CryptBlocks(dst, src []byte) { 144 if len(src)%x.blockSize != 0 { 145 panic("crypto/cipher: input not full blocks") 146 } 147 if len(dst) < len(src) { 148 panic("crypto/cipher: output smaller than input") 149 } 150 if alias.InexactOverlap(dst[:len(src)], src) { 151 panic("crypto/cipher: invalid buffer overlap") 152 } 153 if len(src) == 0 { 154 return 155 } 156 157 // For each block, we need to xor the decrypted data with the previous block's ciphertext (the iv). 158 // To avoid making a copy each time, we loop over the blocks BACKWARDS. 159 end := len(src) 160 start := end - x.blockSize 161 prev := start - x.blockSize 162 163 // Copy the last block of ciphertext in preparation as the new iv. 164 copy(x.tmp, src[start:end]) 165 166 // Loop over all but the first block. 167 for start > 0 { 168 x.b.Decrypt(dst[start:end], src[start:end]) 169 subtle.XORBytes(dst[start:end], dst[start:end], src[prev:start]) 170 171 end = start 172 start = prev 173 prev -= x.blockSize 174 } 175 176 // The first block is special because it uses the saved iv. 177 x.b.Decrypt(dst[start:end], src[start:end]) 178 subtle.XORBytes(dst[start:end], dst[start:end], x.iv) 179 180 // Set the new iv to the first block we copied earlier. 181 x.iv, x.tmp = x.tmp, x.iv 182 } 183 184 func (x *cbcDecrypter) SetIV(iv []byte) { 185 if len(iv) != len(x.iv) { 186 panic("cipher: incorrect length IV") 187 } 188 copy(x.iv, iv) 189 }