1
2
3
4
5
6
7
8
9
10
11
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
33
34
35 type ctrAble interface {
36 NewCTR(iv []byte) Stream
37 }
38
39
40
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
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
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