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 // NewCBCEncrypter returns a BlockMode which encrypts in cipher block chaining
     33 // mode, using the given Block. The length of iv must be the same as the
     34 // Block's block size.
     35 func NewCBCEncrypter(b Block, iv []byte) BlockMode {
     36 	if len(iv) != b.BlockSize() {
     37 		panic("cipher.NewCBCEncrypter: IV length must equal block size")
     38 	}
     39 	return (*cbcEncrypter)(newCBC(b, iv))
     40 }
     41 
     42 func (x *cbcEncrypter) BlockSize() int { return x.blockSize }
     43 
     44 func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
     45 	if len(src)%x.blockSize != 0 {
     46 		panic("crypto/cipher: input not full blocks")
     47 	}
     48 	if len(dst) < len(src) {
     49 		panic("crypto/cipher: output smaller than input")
     50 	}
     51 
     52 	iv := x.iv
     53 
     54 	for len(src) > 0 {
     55 		// Write the xor to dst, then encrypt in place.
     56 		xorBytes(dst[:x.blockSize], src[:x.blockSize], iv)
     57 		x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize])
     58 
     59 		// Move to the next block with this block as the next iv.
     60 		iv = dst[:x.blockSize]
     61 		src = src[x.blockSize:]
     62 		dst = dst[x.blockSize:]
     63 	}
     64 
     65 	// Save the iv for the next CryptBlocks call.
     66 	copy(x.iv, iv)
     67 }
     68 
     69 func (x *cbcEncrypter) SetIV(iv []byte) {
     70 	if len(iv) != len(x.iv) {
     71 		panic("cipher: incorrect length IV")
     72 	}
     73 	copy(x.iv, iv)
     74 }
     75 
     76 type cbcDecrypter cbc
     77 
     78 // NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining
     79 // mode, using the given Block. The length of iv must be the same as the
     80 // Block's block size and must match the iv used to encrypt the data.
     81 func NewCBCDecrypter(b Block, iv []byte) BlockMode {
     82 	if len(iv) != b.BlockSize() {
     83 		panic("cipher.NewCBCDecrypter: IV length must equal block size")
     84 	}
     85 	return (*cbcDecrypter)(newCBC(b, iv))
     86 }
     87 
     88 func (x *cbcDecrypter) BlockSize() int { return x.blockSize }
     89 
     90 func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
     91 	if len(src)%x.blockSize != 0 {
     92 		panic("crypto/cipher: input not full blocks")
     93 	}
     94 	if len(dst) < len(src) {
     95 		panic("crypto/cipher: output smaller than input")
     96 	}
     97 	if len(src) == 0 {
     98 		return
     99 	}
    100 
    101 	// For each block, we need to xor the decrypted data with the previous block's ciphertext (the iv).
    102 	// To avoid making a copy each time, we loop over the blocks BACKWARDS.
    103 	end := len(src)
    104 	start := end - x.blockSize
    105 	prev := start - x.blockSize
    106 
    107 	// Copy the last block of ciphertext in preparation as the new iv.
    108 	copy(x.tmp, src[start:end])
    109 
    110 	// Loop over all but the first block.
    111 	for start > 0 {
    112 		x.b.Decrypt(dst[start:end], src[start:end])
    113 		xorBytes(dst[start:end], dst[start:end], src[prev:start])
    114 
    115 		end = start
    116 		start = prev
    117 		prev -= x.blockSize
    118 	}
    119 
    120 	// The first block is special because it uses the saved iv.
    121 	x.b.Decrypt(dst[start:end], src[start:end])
    122 	xorBytes(dst[start:end], dst[start:end], x.iv)
    123 
    124 	// Set the new iv to the first block we copied earlier.
    125 	x.iv, x.tmp = x.tmp, x.iv
    126 }
    127 
    128 func (x *cbcDecrypter) SetIV(iv []byte) {
    129 	if len(iv) != len(x.iv) {
    130 		panic("cipher: incorrect length IV")
    131 	}
    132 	copy(x.iv, iv)
    133 }
    134