Source file src/crypto/cipher/ctr.go

     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  import (
    16  	"bytes"
    17  	"crypto/internal/alias"
    18  	"crypto/subtle"
    19  )
    20  
    21  type ctr struct {
    22  	b       Block
    23  	ctr     []byte
    24  	out     []byte
    25  	outUsed int
    26  }
    27  
    28  const streamBufferSize = 512
    29  
    30  // ctrAble is an interface implemented by ciphers that have a specific optimized
    31  // implementation of CTR, like crypto/aes. NewCTR will check for this interface
    32  // and return the specific Stream if found.
    33  type ctrAble interface {
    34  	NewCTR(iv []byte) Stream
    35  }
    36  
    37  // NewCTR returns a [Stream] which encrypts/decrypts using the given [Block] in
    38  // counter mode. The length of iv must be the same as the [Block]'s block size.
    39  func NewCTR(block Block, iv []byte) Stream {
    40  	if ctr, ok := block.(ctrAble); ok {
    41  		return ctr.NewCTR(iv)
    42  	}
    43  	if len(iv) != block.BlockSize() {
    44  		panic("cipher.NewCTR: IV length must equal block size")
    45  	}
    46  	bufSize := streamBufferSize
    47  	if bufSize < block.BlockSize() {
    48  		bufSize = block.BlockSize()
    49  	}
    50  	return &ctr{
    51  		b:       block,
    52  		ctr:     bytes.Clone(iv),
    53  		out:     make([]byte, 0, bufSize),
    54  		outUsed: 0,
    55  	}
    56  }
    57  
    58  func (x *ctr) refill() {
    59  	remain := len(x.out) - x.outUsed
    60  	copy(x.out, x.out[x.outUsed:])
    61  	x.out = x.out[:cap(x.out)]
    62  	bs := x.b.BlockSize()
    63  	for remain <= len(x.out)-bs {
    64  		x.b.Encrypt(x.out[remain:], x.ctr)
    65  		remain += bs
    66  
    67  		// Increment counter
    68  		for i := len(x.ctr) - 1; i >= 0; i-- {
    69  			x.ctr[i]++
    70  			if x.ctr[i] != 0 {
    71  				break
    72  			}
    73  		}
    74  	}
    75  	x.out = x.out[:remain]
    76  	x.outUsed = 0
    77  }
    78  
    79  func (x *ctr) XORKeyStream(dst, src []byte) {
    80  	if len(dst) < len(src) {
    81  		panic("crypto/cipher: output smaller than input")
    82  	}
    83  	if alias.InexactOverlap(dst[:len(src)], src) {
    84  		panic("crypto/cipher: invalid buffer overlap")
    85  	}
    86  	for len(src) > 0 {
    87  		if x.outUsed >= len(x.out)-x.b.BlockSize() {
    88  			x.refill()
    89  		}
    90  		n := subtle.XORBytes(dst, src, x.out[x.outUsed:])
    91  		dst = dst[n:]
    92  		src = src[n:]
    93  		x.outUsed += n
    94  	}
    95  }
    96  

View as plain text