1
2
3
4
5 package drbg
6
7 import (
8 "crypto/internal/fips140"
9 "crypto/internal/fips140/aes"
10 "crypto/internal/fips140/subtle"
11 "crypto/internal/fips140deps/byteorder"
12 "math/bits"
13 )
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 type Counter struct {
33
34 c aes.CTR
35
36 reseedCounter uint64
37 }
38
39 const (
40 keySize = 256 / 8
41 SeedSize = keySize + aes.BlockSize
42 reseedInterval = 1 << 48
43 maxRequestSize = (1 << 19) / 8
44 )
45
46 func NewCounter(entropy *[SeedSize]byte) *Counter {
47
48 fips140.RecordApproved()
49
50 K := make([]byte, keySize)
51 V := make([]byte, aes.BlockSize)
52
53
54
55 V[len(V)-1] = 1
56
57 cipher, err := aes.New(K)
58 if err != nil {
59 panic(err)
60 }
61
62 c := &Counter{}
63 c.c = *aes.NewCTR(cipher, V)
64 c.update(entropy)
65 c.reseedCounter = 1
66 return c
67 }
68
69 func (c *Counter) update(seed *[SeedSize]byte) {
70
71
72 temp := make([]byte, SeedSize)
73 c.c.XORKeyStream(temp, seed[:])
74 K := temp[:keySize]
75 V := temp[keySize:]
76
77
78 increment((*[aes.BlockSize]byte)(V))
79
80 cipher, err := aes.New(K)
81 if err != nil {
82 panic(err)
83 }
84 c.c = *aes.NewCTR(cipher, V)
85 }
86
87 func increment(v *[aes.BlockSize]byte) {
88 hi := byteorder.BEUint64(v[:8])
89 lo := byteorder.BEUint64(v[8:])
90 lo, c := bits.Add64(lo, 1, 0)
91 hi, _ = bits.Add64(hi, 0, c)
92 byteorder.BEPutUint64(v[:8], hi)
93 byteorder.BEPutUint64(v[8:], lo)
94 }
95
96 func (c *Counter) Reseed(entropy, additionalInput *[SeedSize]byte) {
97
98 fips140.RecordApproved()
99
100 var seed [SeedSize]byte
101 subtle.XORBytes(seed[:], entropy[:], additionalInput[:])
102 c.update(&seed)
103 c.reseedCounter = 1
104 }
105
106
107 func (c *Counter) Generate(out []byte, additionalInput *[SeedSize]byte) (reseedRequired bool) {
108
109 fips140.RecordApproved()
110
111 if len(out) > maxRequestSize {
112 panic("crypto/drbg: internal error: request size exceeds maximum")
113 }
114
115
116 if c.reseedCounter > reseedInterval {
117 return true
118 }
119
120
121 if additionalInput != nil {
122 c.update(additionalInput)
123 } else {
124
125
126
127 additionalInput = new([SeedSize]byte)
128 }
129
130
131 clear(out)
132 c.c.XORKeyStream(out, out)
133 aes.RoundToBlock(&c.c)
134
135
136 c.update(additionalInput)
137
138
139 c.reseedCounter++
140
141
142 return false
143 }
144
View as plain text