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