github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/crypto/cipher/cbc.go (about)

     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  }