Black Lives Matter. Support the Equal Justice Initiative.

Source file src/crypto/cipher/ctr.go

Documentation: crypto/cipher

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

View as plain text