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