Home | History | Annotate | Download | only in cipher
      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 }
    156