github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/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 type cbc struct { 15 b Block 16 blockSize int 17 iv []byte 18 tmp []byte 19 } 20 21 func newCBC(b Block, iv []byte) *cbc { 22 return &cbc{ 23 b: b, 24 blockSize: b.BlockSize(), 25 iv: dup(iv), 26 tmp: make([]byte, b.BlockSize()), 27 } 28 } 29 30 type cbcEncrypter cbc 31 32 // cbcEncAble is an interface implemented by ciphers that have a specific 33 // optimized implementation of CBC encryption, like crypto/aes. 34 // NewCBCEncrypter will check for this interface and return the specific 35 // BlockMode if found. 36 type cbcEncAble interface { 37 NewCBCEncrypter(iv []byte) BlockMode 38 } 39 40 // NewCBCEncrypter returns a BlockMode which encrypts in cipher block chaining 41 // mode, using the given Block. The length of iv must be the same as the 42 // Block's block size. 43 func NewCBCEncrypter(b Block, iv []byte) BlockMode { 44 if len(iv) != b.BlockSize() { 45 panic("cipher.NewCBCEncrypter: IV length must equal block size") 46 } 47 if cbc, ok := b.(cbcEncAble); ok { 48 return cbc.NewCBCEncrypter(iv) 49 } 50 return (*cbcEncrypter)(newCBC(b, iv)) 51 } 52 53 func (x *cbcEncrypter) BlockSize() int { return x.blockSize } 54 55 func (x *cbcEncrypter) CryptBlocks(dst, src []byte) { 56 if len(src)%x.blockSize != 0 { 57 panic("crypto/cipher: input not full blocks") 58 } 59 if len(dst) < len(src) { 60 panic("crypto/cipher: output smaller than input") 61 } 62 63 iv := x.iv 64 65 for len(src) > 0 { 66 // Write the xor to dst, then encrypt in place. 67 xorBytes(dst[:x.blockSize], src[:x.blockSize], iv) 68 x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize]) 69 70 // Move to the next block with this block as the next iv. 71 iv = dst[:x.blockSize] 72 src = src[x.blockSize:] 73 dst = dst[x.blockSize:] 74 } 75 76 // Save the iv for the next CryptBlocks call. 77 copy(x.iv, iv) 78 } 79 80 func (x *cbcEncrypter) SetIV(iv []byte) { 81 if len(iv) != len(x.iv) { 82 panic("cipher: incorrect length IV") 83 } 84 copy(x.iv, iv) 85 } 86 87 type cbcDecrypter cbc 88 89 // cbcDecAble is an interface implemented by ciphers that have a specific 90 // optimized implementation of CBC decryption, like crypto/aes. 91 // NewCBCDecrypter will check for this interface and return the specific 92 // BlockMode if found. 93 type cbcDecAble interface { 94 NewCBCDecrypter(iv []byte) BlockMode 95 } 96 97 // NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining 98 // mode, using the given Block. The length of iv must be the same as the 99 // Block's block size and must match the iv used to encrypt the data. 100 func NewCBCDecrypter(b Block, iv []byte) BlockMode { 101 if len(iv) != b.BlockSize() { 102 panic("cipher.NewCBCDecrypter: IV length must equal block size") 103 } 104 if cbc, ok := b.(cbcDecAble); ok { 105 return cbc.NewCBCDecrypter(iv) 106 } 107 return (*cbcDecrypter)(newCBC(b, iv)) 108 } 109 110 func (x *cbcDecrypter) BlockSize() int { return x.blockSize } 111 112 func (x *cbcDecrypter) CryptBlocks(dst, src []byte) { 113 if len(src)%x.blockSize != 0 { 114 panic("crypto/cipher: input not full blocks") 115 } 116 if len(dst) < len(src) { 117 panic("crypto/cipher: output smaller than input") 118 } 119 if len(src) == 0 { 120 return 121 } 122 123 // For each block, we need to xor the decrypted data with the previous block's ciphertext (the iv). 124 // To avoid making a copy each time, we loop over the blocks BACKWARDS. 125 end := len(src) 126 start := end - x.blockSize 127 prev := start - x.blockSize 128 129 // Copy the last block of ciphertext in preparation as the new iv. 130 copy(x.tmp, src[start:end]) 131 132 // Loop over all but the first block. 133 for start > 0 { 134 x.b.Decrypt(dst[start:end], src[start:end]) 135 xorBytes(dst[start:end], dst[start:end], src[prev:start]) 136 137 end = start 138 start = prev 139 prev -= x.blockSize 140 } 141 142 // The first block is special because it uses the saved iv. 143 x.b.Decrypt(dst[start:end], src[start:end]) 144 xorBytes(dst[start:end], dst[start:end], x.iv) 145 146 // Set the new iv to the first block we copied earlier. 147 x.iv, x.tmp = x.tmp, x.iv 148 } 149 150 func (x *cbcDecrypter) SetIV(iv []byte) { 151 if len(iv) != len(x.iv) { 152 panic("cipher: incorrect length IV") 153 } 154 copy(x.iv, iv) 155 }