github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/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  // ctrAble is an interface implemented by ciphers that have a specific optimized
    25  // implementation of CTR, like crypto/aes. NewCTR will check for this interface
    26  // and return the specific Stream if found.
    27  type ctrAble interface {
    28  	NewCTR(iv []byte) Stream
    29  }
    30  
    31  // NewCTR returns a Stream which encrypts/decrypts using the given Block in
    32  // counter mode. The length of iv must be the same as the Block's block size.
    33  func NewCTR(block Block, iv []byte) Stream {
    34  	if ctr, ok := block.(ctrAble); ok {
    35  		return ctr.NewCTR(iv)
    36  	}
    37  	if len(iv) != block.BlockSize() {
    38  		panic("cipher.NewCTR: IV length must equal block size")
    39  	}
    40  	bufSize := streamBufferSize
    41  	if bufSize < block.BlockSize() {
    42  		bufSize = block.BlockSize()
    43  	}
    44  	return &ctr{
    45  		b:       block,
    46  		ctr:     dup(iv),
    47  		out:     make([]byte, 0, bufSize),
    48  		outUsed: 0,
    49  	}
    50  }
    51  
    52  func (x *ctr) refill() {
    53  	remain := len(x.out) - x.outUsed
    54  	copy(x.out, x.out[x.outUsed:])
    55  	x.out = x.out[:cap(x.out)]
    56  	bs := x.b.BlockSize()
    57  	for remain <= len(x.out)-bs {
    58  		x.b.Encrypt(x.out[remain:], x.ctr)
    59  		remain += bs
    60  
    61  		// Increment counter
    62  		for i := len(x.ctr) - 1; i >= 0; i-- {
    63  			x.ctr[i]++
    64  			if x.ctr[i] != 0 {
    65  				break
    66  			}
    67  		}
    68  	}
    69  	x.out = x.out[:remain]
    70  	x.outUsed = 0
    71  }
    72  
    73  func (x *ctr) XORKeyStream(dst, src []byte) {
    74  	for len(src) > 0 {
    75  		if x.outUsed >= len(x.out)-x.b.BlockSize() {
    76  			x.refill()
    77  		}
    78  		n := xorBytes(dst, src, x.out[x.outUsed:])
    79  		dst = dst[n:]
    80  		src = src[n:]
    81  		x.outUsed += n
    82  	}
    83  }