github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/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  // 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  }