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 13package cipher 14 15import ( 16 "bytes" 17 "crypto/internal/alias" 18 "crypto/subtle" 19) 20 21type ctr struct { 22 b Block 23 ctr []byte 24 out []byte 25 outUsed int 26} 27 28const 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. 33type 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. 39func 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 58func (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 79func (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