...

Source file src/crypto/cipher/cbc.go

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

View as plain text