github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/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  	for len(src) > 0 {
    52  		for i := 0; i < x.blockSize; i++ {
    53  			x.iv[i] ^= src[i]
    54  		}
    55  		x.b.Encrypt(x.iv, x.iv)
    56  		for i := 0; i < x.blockSize; i++ {
    57  			dst[i] = x.iv[i]
    58  		}
    59  		src = src[x.blockSize:]
    60  		dst = dst[x.blockSize:]
    61  	}
    62  }
    63  
    64  type cbcDecrypter cbc
    65  
    66  // NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining
    67  // mode, using the given Block. The length of iv must be the same as the
    68  // Block's block size and must match the iv used to encrypt the data.
    69  func NewCBCDecrypter(b Block, iv []byte) BlockMode {
    70  	if len(iv) != b.BlockSize() {
    71  		panic("cipher.NewCBCDecrypter: IV length must equal block size")
    72  	}
    73  	return (*cbcDecrypter)(newCBC(b, iv))
    74  }
    75  
    76  func (x *cbcDecrypter) BlockSize() int { return x.blockSize }
    77  
    78  func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
    79  	if len(src)%x.blockSize != 0 {
    80  		panic("crypto/cipher: input not full blocks")
    81  	}
    82  	if len(dst) < len(src) {
    83  		panic("crypto/cipher: output smaller than input")
    84  	}
    85  	for len(src) > 0 {
    86  		x.b.Decrypt(x.tmp, src[:x.blockSize])
    87  		for i := 0; i < x.blockSize; i++ {
    88  			x.tmp[i] ^= x.iv[i]
    89  			x.iv[i] = src[i]
    90  			dst[i] = x.tmp[i]
    91  		}
    92  
    93  		src = src[x.blockSize:]
    94  		dst = dst[x.blockSize:]
    95  	}
    96  }