// 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-11package cipherimport ()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. crypto/aes doesn't use this// anymore, and we'd like to eventually remove it.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 {iflen() != .BlockSize() {panic("cipher.NewCBCEncrypter: IV length must equal block size") }if , := .(*aes.Block); {returnaes.NewCBCEncrypter(, [16]byte()) }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 {iflen() != .BlockSize() {panic("cipher.NewCBCEncrypter: IV length must equal block size") }return (*cbcEncrypter)(newCBC(, ))}func ( *cbcEncrypter) () int { return .blockSize }func ( *cbcEncrypter) (, []byte) {iflen()%.blockSize != 0 {panic("crypto/cipher: input not full blocks") }iflen() < len() {panic("crypto/cipher: output smaller than input") }ifalias.InexactOverlap([:len()], ) {panic("crypto/cipher: invalid buffer overlap") }if , := .b.(*aes.Block); {panic("crypto/cipher: internal error: generic CBC used with AES") } := .ivforlen() > 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) {iflen() != 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. crypto/aes doesn't use this// anymore, and we'd like to eventually remove it.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 {iflen() != .BlockSize() {panic("cipher.NewCBCDecrypter: IV length must equal block size") }if , := .(*aes.Block); {returnaes.NewCBCDecrypter(, [16]byte()) }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 {iflen() != .BlockSize() {panic("cipher.NewCBCDecrypter: IV length must equal block size") }return (*cbcDecrypter)(newCBC(, ))}func ( *cbcDecrypter) () int { return .blockSize }func ( *cbcDecrypter) (, []byte) {iflen()%.blockSize != 0 {panic("crypto/cipher: input not full blocks") }iflen() < len() {panic("crypto/cipher: output smaller than input") }ifalias.InexactOverlap([:len()], ) {panic("crypto/cipher: invalid buffer overlap") }if , := .b.(*aes.Block); {panic("crypto/cipher: internal error: generic CBC used with AES") }iflen() == 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) {iflen() != len(.iv) {panic("cipher: incorrect length IV") }copy(.iv, )}
The pages are generated with Goldsv0.7.3. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.