| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Cipher block chaining (CBC) mode. | |
| // CBC provides confidentiality by xoring (chaining) each plaintext block | |
| // with the previous ciphertext block before applying the block cipher. | |
| // See NIST SP 800-38A, pp 10-11 | |
| package cipher | |
| type cbc struct { | |
| b Block | |
| blockSize int | |
| iv []byte | |
| tmp []byte | |
| } | |
| func newCBC(b Block, iv []byte) *cbc { | |
| return &cbc{ | |
| b: b, | |
| blockSize: b.BlockSize(), | |
| iv: dup(iv), | |
| tmp: make([]byte, b.BlockSize()), | |
| } | |
| } | |
| type cbcEncrypter cbc | |
| // cbcEncAble is an interface implemented by ciphers that have a specific | |
| // optimized implementation of CBC encryption, like crypto/aes. | |
| // NewCBCEncrypter will check for this interface and return the specific | |
| // BlockMode if found. | |
| type cbcEncAble interface { | |
| NewCBCEncrypter(iv []byte) BlockMode | |
| } | |
| // NewCBCEncrypter returns a BlockMode which encrypts in cipher block chaining | |
| // mode, using the given Block. The length of iv must be the same as the | |
| // Block's block size. | |
| func NewCBCEncrypter(b Block, iv []byte) BlockMode { | |
| if len(iv) != b.BlockSize() { | |
| panic("cipher.NewCBCEncrypter: IV length must equal block size") | |
| } | |
| if cbc, ok := b.(cbcEncAble); ok { | |
| return cbc.NewCBCEncrypter(iv) | |
| } | |
| return (*cbcEncrypter)(newCBC(b, iv)) | |
| } | |
| func (x *cbcEncrypter) BlockSize() int { return x.blockSize } | |
| func (x *cbcEncrypter) CryptBlocks(dst, src []byte) { | |
| if len(src)%x.blockSize != 0 { | |
| panic("crypto/cipher: input not full blocks") | |
| } | |
| if len(dst) < len(src) { | |
| panic("crypto/cipher: output smaller than input") | |
| } | |
| iv := x.iv | |
| for len(src) > 0 { | |
| // Write the xor to dst, then encrypt in place. | |
| xorBytes(dst[:x.blockSize], src[:x.blockSize], iv) | |
| x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize]) | |
| // Move to the next block with this block as the next iv. | |
| iv = dst[:x.blockSize] | |
| src = src[x.blockSize:] | |
| dst = dst[x.blockSize:] | |
| } | |
| // Save the iv for the next CryptBlocks call. | |
| copy(x.iv, iv) | |
| } | |
| func (x *cbcEncrypter) SetIV(iv []byte) { | |
| if len(iv) != len(x.iv) { | |
| panic("cipher: incorrect length IV") | |
| } | |
| copy(x.iv, iv) | |
| } | |
| type cbcDecrypter cbc | |
| // cbcDecAble is an interface implemented by ciphers that have a specific | |
| // optimized implementation of CBC decryption, like crypto/aes. | |
| // NewCBCDecrypter will check for this interface and return the specific | |
| // BlockMode if found. | |
| type cbcDecAble interface { | |
| NewCBCDecrypter(iv []byte) BlockMode | |
| } | |
| // NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining | |
| // mode, using the given Block. The length of iv must be the same as the | |
| // Block's block size and must match the iv used to encrypt the data. | |
| func NewCBCDecrypter(b Block, iv []byte) BlockMode { | |
| if len(iv) != b.BlockSize() { | |
| panic("cipher.NewCBCDecrypter: IV length must equal block size") | |
| } | |
| if cbc, ok := b.(cbcDecAble); ok { | |
| return cbc.NewCBCDecrypter(iv) | |
| } | |
| return (*cbcDecrypter)(newCBC(b, iv)) | |
| } | |
| func (x *cbcDecrypter) BlockSize() int { return x.blockSize } | |
| func (x *cbcDecrypter) CryptBlocks(dst, src []byte) { | |
| if len(src)%x.blockSize != 0 { | |
| panic("crypto/cipher: input not full blocks") | |
| } | |
| if len(dst) < len(src) { | |
| panic("crypto/cipher: output smaller than input") | |
| } | |
| if len(src) == 0 { | |
| return | |
| } | |
| // For each block, we need to xor the decrypted data with the previous block's ciphertext (the iv). | |
| // To avoid making a copy each time, we loop over the blocks BACKWARDS. | |
| end := len(src) | |
| start := end - x.blockSize | |
| prev := start - x.blockSize | |
| // Copy the last block of ciphertext in preparation as the new iv. | |
| copy(x.tmp, src[start:end]) | |
| // Loop over all but the first block. | |
| for start > 0 { | |
| x.b.Decrypt(dst[start:end], src[start:end]) | |
| xorBytes(dst[start:end], dst[start:end], src[prev:start]) | |
| end = start | |
| start = prev | |
| prev -= x.blockSize | |
| } | |
| // The first block is special because it uses the saved iv. | |
| x.b.Decrypt(dst[start:end], src[start:end]) | |
| xorBytes(dst[start:end], dst[start:end], x.iv) | |
| // Set the new iv to the first block we copied earlier. | |
| x.iv, x.tmp = x.tmp, x.iv | |
| } | |
| func (x *cbcDecrypter) SetIV(iv []byte) { | |
| if len(iv) != len(x.iv) { | |
| panic("cipher: incorrect length IV") | |
| } | |
| copy(x.iv, iv) | |
| } |