github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/crypto/cipher/ctr.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  // Counter (CTR) mode.
     6  
     7  // CTR converts a block cipher into a stream cipher by
     8  // repeatedly encrypting an incrementing counter and
     9  // xoring the resulting stream of data with the input.
    10  
    11  // See NIST SP 800-38A, pp 13-15
    12  
    13  package cipher
    14  
    15  type ctr struct {
    16  	b       Block
    17  	ctr     []byte
    18  	out     []byte
    19  	outUsed int
    20  }
    21  
    22  const streamBufferSize = 512
    23  
    24  // NewCTR returns a Stream which encrypts/decrypts using the given Block in
    25  // counter mode. The length of iv must be the same as the Block's block size.
    26  func NewCTR(block Block, iv []byte) Stream {
    27  	if len(iv) != block.BlockSize() {
    28  		panic("cipher.NewCTR: IV length must equal block size")
    29  	}
    30  	bufSize := streamBufferSize
    31  	if bufSize < block.BlockSize() {
    32  		bufSize = block.BlockSize()
    33  	}
    34  	return &ctr{
    35  		b:       block,
    36  		ctr:     dup(iv),
    37  		out:     make([]byte, 0, bufSize),
    38  		outUsed: 0,
    39  	}
    40  }
    41  
    42  func (x *ctr) refill() {
    43  	remain := len(x.out) - x.outUsed
    44  	if remain > x.outUsed {
    45  		return
    46  	}
    47  	copy(x.out, x.out[x.outUsed:])
    48  	x.out = x.out[:cap(x.out)]
    49  	bs := x.b.BlockSize()
    50  	for remain < len(x.out)-bs {
    51  		x.b.Encrypt(x.out[remain:], x.ctr)
    52  		remain += bs
    53  
    54  		// Increment counter
    55  		for i := len(x.ctr) - 1; i >= 0; i-- {
    56  			x.ctr[i]++
    57  			if x.ctr[i] != 0 {
    58  				break
    59  			}
    60  		}
    61  	}
    62  	x.out = x.out[:remain]
    63  	x.outUsed = 0
    64  }
    65  
    66  func (x *ctr) XORKeyStream(dst, src []byte) {
    67  	for len(src) > 0 {
    68  		if x.outUsed >= len(x.out)-x.b.BlockSize() {
    69  			x.refill()
    70  		}
    71  		n := xorBytes(dst, src, x.out[x.outUsed:])
    72  		dst = dst[n:]
    73  		src = src[n:]
    74  		x.outUsed += n
    75  	}
    76  }