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