...
Run Format

Source file src/crypto/cipher/cbc.go

Documentation: crypto/cipher

  // 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)
  }
  

View as plain text