...
Run Format

Source file src/crypto/cipher/ctr.go

Documentation: crypto/cipher

  // 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.
  
  // Counter (CTR) mode.
  
  // CTR converts a block cipher into a stream cipher by
  // repeatedly encrypting an incrementing counter and
  // xoring the resulting stream of data with the input.
  
  // See NIST SP 800-38A, pp 13-15
  
  package cipher
  
  type ctr struct {
  	b       Block
  	ctr     []byte
  	out     []byte
  	outUsed int
  }
  
  const streamBufferSize = 512
  
  // ctrAble is an interface implemented by ciphers that have a specific optimized
  // implementation of CTR, like crypto/aes. NewCTR will check for this interface
  // and return the specific Stream if found.
  type ctrAble interface {
  	NewCTR(iv []byte) Stream
  }
  
  // NewCTR returns a Stream which encrypts/decrypts using the given Block in
  // counter mode. The length of iv must be the same as the Block's block size.
  func NewCTR(block Block, iv []byte) Stream {
  	if ctr, ok := block.(ctrAble); ok {
  		return ctr.NewCTR(iv)
  	}
  	if len(iv) != block.BlockSize() {
  		panic("cipher.NewCTR: IV length must equal block size")
  	}
  	bufSize := streamBufferSize
  	if bufSize < block.BlockSize() {
  		bufSize = block.BlockSize()
  	}
  	return &ctr{
  		b:       block,
  		ctr:     dup(iv),
  		out:     make([]byte, 0, bufSize),
  		outUsed: 0,
  	}
  }
  
  func (x *ctr) refill() {
  	remain := len(x.out) - x.outUsed
  	copy(x.out, x.out[x.outUsed:])
  	x.out = x.out[:cap(x.out)]
  	bs := x.b.BlockSize()
  	for remain <= len(x.out)-bs {
  		x.b.Encrypt(x.out[remain:], x.ctr)
  		remain += bs
  
  		// Increment counter
  		for i := len(x.ctr) - 1; i >= 0; i-- {
  			x.ctr[i]++
  			if x.ctr[i] != 0 {
  				break
  			}
  		}
  	}
  	x.out = x.out[:remain]
  	x.outUsed = 0
  }
  
  func (x *ctr) XORKeyStream(dst, src []byte) {
  	for len(src) > 0 {
  		if x.outUsed >= len(x.out)-x.b.BlockSize() {
  			x.refill()
  		}
  		n := xorBytes(dst, src, x.out[x.outUsed:])
  		dst = dst[n:]
  		src = src[n:]
  		x.outUsed += n
  	}
  }
  

View as plain text