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

import (
	
	
	
)

type cbc struct {
	b         Block
	blockSize int
	iv        []byte
	tmp       []byte
}

func newCBC( Block,  []byte) *cbc {
	return &cbc{
		b:         ,
		blockSize: .BlockSize(),
		iv:        bytes.Clone(),
		tmp:       make([]byte, .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 ( Block,  []byte) BlockMode {
	if len() != .BlockSize() {
		panic("cipher.NewCBCEncrypter: IV length must equal block size")
	}
	if ,  := .(cbcEncAble);  {
		return .NewCBCEncrypter()
	}
	return (*cbcEncrypter)(newCBC(, ))
}

// newCBCGenericEncrypter 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. This always returns the generic non-asm encrypter for use
// in fuzz testing.
func newCBCGenericEncrypter( Block,  []byte) BlockMode {
	if len() != .BlockSize() {
		panic("cipher.NewCBCEncrypter: IV length must equal block size")
	}
	return (*cbcEncrypter)(newCBC(, ))
}

func ( *cbcEncrypter) () int { return .blockSize }

func ( *cbcEncrypter) (,  []byte) {
	if len()%.blockSize != 0 {
		panic("crypto/cipher: input not full blocks")
	}
	if len() < len() {
		panic("crypto/cipher: output smaller than input")
	}
	if alias.InexactOverlap([:len()], ) {
		panic("crypto/cipher: invalid buffer overlap")
	}

	 := .iv

	for len() > 0 {
		// Write the xor to dst, then encrypt in place.
		subtle.XORBytes([:.blockSize], [:.blockSize], )
		.b.Encrypt([:.blockSize], [:.blockSize])

		// Move to the next block with this block as the next iv.
		 = [:.blockSize]
		 = [.blockSize:]
		 = [.blockSize:]
	}

	// Save the iv for the next CryptBlocks call.
	copy(.iv, )
}

func ( *cbcEncrypter) ( []byte) {
	if len() != len(.iv) {
		panic("cipher: incorrect length IV")
	}
	copy(.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 ( Block,  []byte) BlockMode {
	if len() != .BlockSize() {
		panic("cipher.NewCBCDecrypter: IV length must equal block size")
	}
	if ,  := .(cbcDecAble);  {
		return .NewCBCDecrypter()
	}
	return (*cbcDecrypter)(newCBC(, ))
}

// newCBCGenericDecrypter 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. This always returns the generic non-asm decrypter for use in
// fuzz testing.
func newCBCGenericDecrypter( Block,  []byte) BlockMode {
	if len() != .BlockSize() {
		panic("cipher.NewCBCDecrypter: IV length must equal block size")
	}
	return (*cbcDecrypter)(newCBC(, ))
}

func ( *cbcDecrypter) () int { return .blockSize }

func ( *cbcDecrypter) (,  []byte) {
	if len()%.blockSize != 0 {
		panic("crypto/cipher: input not full blocks")
	}
	if len() < len() {
		panic("crypto/cipher: output smaller than input")
	}
	if alias.InexactOverlap([:len()], ) {
		panic("crypto/cipher: invalid buffer overlap")
	}
	if len() == 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.
	 := len()
	 :=  - .blockSize
	 :=  - .blockSize

	// Copy the last block of ciphertext in preparation as the new iv.
	copy(.tmp, [:])

	// Loop over all but the first block.
	for  > 0 {
		.b.Decrypt([:], [:])
		subtle.XORBytes([:], [:], [:])

		 = 
		 = 
		 -= .blockSize
	}

	// The first block is special because it uses the saved iv.
	.b.Decrypt([:], [:])
	subtle.XORBytes([:], [:], .iv)

	// Set the new iv to the first block we copied earlier.
	.iv, .tmp = .tmp, .iv
}

func ( *cbcDecrypter) ( []byte) {
	if len() != len(.iv) {
		panic("cipher: incorrect length IV")
	}
	copy(.iv, )
}