ctr.mx raw

   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/fips140/aes"
  18  	"crypto/internal/fips140/alias"
  19  	"crypto/internal/fips140only"
  20  	"crypto/subtle"
  21  )
  22  
  23  type ctr struct {
  24  	b       Block
  25  	ctr     []byte
  26  	out     []byte
  27  	outUsed int
  28  }
  29  
  30  const streamBufferSize = 512
  31  
  32  // ctrAble is an interface implemented by ciphers that have a specific optimized
  33  // implementation of CTR. crypto/aes doesn't use this anymore, and we'd like to
  34  // eventually remove it.
  35  type ctrAble interface {
  36  	NewCTR(iv []byte) Stream
  37  }
  38  
  39  // NewCTR returns a [Stream] which encrypts/decrypts using the given [Block] in
  40  // counter mode. The length of iv must be the same as the [Block]'s block size.
  41  func NewCTR(block Block, iv []byte) Stream {
  42  	if block, ok := block.(*aes.Block); ok {
  43  		return aesCtrWrapper{aes.NewCTR(block, iv)}
  44  	}
  45  	if fips140only.Enabled {
  46  		panic("crypto/cipher: use of CTR with non-AES ciphers is not allowed in FIPS 140-only mode")
  47  	}
  48  	if ctr, ok := block.(ctrAble); ok {
  49  		return ctr.NewCTR(iv)
  50  	}
  51  	if len(iv) != block.BlockSize() {
  52  		panic("cipher.NewCTR: IV length must equal block size")
  53  	}
  54  	bufSize := streamBufferSize
  55  	if bufSize < block.BlockSize() {
  56  		bufSize = block.BlockSize()
  57  	}
  58  	return &ctr{
  59  		b:       block,
  60  		ctr:     bytes.Clone(iv),
  61  		out:     []byte{:0:bufSize},
  62  		outUsed: 0,
  63  	}
  64  }
  65  
  66  // aesCtrWrapper hides extra methods from aes.CTR.
  67  type aesCtrWrapper struct {
  68  	c *aes.CTR
  69  }
  70  
  71  func (x aesCtrWrapper) XORKeyStream(dst, src []byte) {
  72  	x.c.XORKeyStream(dst, src)
  73  }
  74  
  75  func (x *ctr) refill() {
  76  	remain := len(x.out) - x.outUsed
  77  	copy(x.out, x.out[x.outUsed:])
  78  	x.out = x.out[:cap(x.out)]
  79  	bs := x.b.BlockSize()
  80  	for remain <= len(x.out)-bs {
  81  		x.b.Encrypt(x.out[remain:], x.ctr)
  82  		remain += bs
  83  
  84  		// Increment counter
  85  		for i := len(x.ctr) - 1; i >= 0; i-- {
  86  			x.ctr[i]++
  87  			if x.ctr[i] != 0 {
  88  				break
  89  			}
  90  		}
  91  	}
  92  	x.out = x.out[:remain]
  93  	x.outUsed = 0
  94  }
  95  
  96  func (x *ctr) XORKeyStream(dst, src []byte) {
  97  	if len(dst) < len(src) {
  98  		panic("crypto/cipher: output smaller than input")
  99  	}
 100  	if alias.InexactOverlap(dst[:len(src)], src) {
 101  		panic("crypto/cipher: invalid buffer overlap")
 102  	}
 103  	if _, ok := x.b.(*aes.Block); ok {
 104  		panic("crypto/cipher: internal error: generic CTR used with AES")
 105  	}
 106  	for len(src) > 0 {
 107  		if x.outUsed >= len(x.out)-x.b.BlockSize() {
 108  			x.refill()
 109  		}
 110  		n := subtle.XORBytes(dst, src, x.out[x.outUsed:])
 111  		dst = dst[n:]
 112  		src = src[n:]
 113  		x.outUsed += n
 114  	}
 115  }
 116