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/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:     make([]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  

View as plain text