1 // Copyright 2024 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 package ecdsa
6 7 import (
8 "bytes"
9 "crypto/internal/fips140"
10 "crypto/internal/fips140/hmac"
11 "hash"
12 )
13 14 // hmacDRBG is an SP 800-90A Rev. 1 HMAC_DRBG.
15 //
16 // It is only intended to be used to generate ECDSA nonces. Since it will be
17 // instantiated ex-novo for each signature, its Generate function will only be
18 // invoked once or twice (only for P-256, with probability 2⁻³²).
19 //
20 // Per Table 2, it has a reseed interval of 2^48 requests, and a maximum request
21 // size of 2^19 bits (2^16 bytes, 64 KiB).
22 type hmacDRBG struct {
23 newHMAC func(key []byte) *hmac.HMAC
24 25 hK *hmac.HMAC
26 V []byte
27 28 reseedCounter uint64
29 }
30 31 const (
32 reseedInterval = 1 << 48
33 maxRequestSize = (1 << 19) / 8
34 )
35 36 // plainPersonalizationString is used by HMAC_DRBG as-is.
37 type plainPersonalizationString []byte
38 39 func (plainPersonalizationString) isPersonalizationString() {}
40 41 // Each entry in blockAlignedPersonalizationString is written to the HMAC at a
42 // block boundary, as specified in draft-irtf-cfrg-det-sigs-with-noise-04,
43 // Section 4.
44 type blockAlignedPersonalizationString [][]byte
45 46 func (blockAlignedPersonalizationString) isPersonalizationString() {}
47 48 type personalizationString interface {
49 isPersonalizationString()
50 }
51 52 func newDRBG[H hash.Hash](hash func() H, entropy, nonce []byte, s personalizationString) *hmacDRBG {
53 // HMAC_DRBG_Instantiate_algorithm, per Section 10.1.2.3.
54 fips140.RecordApproved()
55 56 d := &hmacDRBG{
57 newHMAC: func(key []byte) *hmac.HMAC {
58 return hmac.New(hash, key)
59 },
60 }
61 size := hash().Size()
62 63 // K = 0x00 0x00 0x00 ... 0x00
64 K := []byte{:size}
65 66 // V = 0x01 0x01 0x01 ... 0x01
67 d.V = bytes.Repeat([]byte{0x01}, size)
68 69 // HMAC_DRBG_Update, per Section 10.1.2.2.
70 // K = HMAC (K, V || 0x00 || provided_data)
71 h := hmac.New(hash, K)
72 h.Write(d.V)
73 h.Write([]byte{0x00})
74 h.Write(entropy)
75 h.Write(nonce)
76 switch s := s.(type) {
77 case plainPersonalizationString:
78 h.Write(s)
79 case blockAlignedPersonalizationString:
80 l := len(d.V) + 1 + len(entropy) + len(nonce)
81 for _, b := range s {
82 pad000(h, l)
83 h.Write(b)
84 l = len(b)
85 }
86 }
87 K = h.Sum(K[:0])
88 // V = HMAC (K, V)
89 h = hmac.New(hash, K)
90 h.Write(d.V)
91 d.V = h.Sum(d.V[:0])
92 // K = HMAC (K, V || 0x01 || provided_data).
93 h.Reset()
94 h.Write(d.V)
95 h.Write([]byte{0x01})
96 h.Write(entropy)
97 h.Write(nonce)
98 switch s := s.(type) {
99 case plainPersonalizationString:
100 h.Write(s)
101 case blockAlignedPersonalizationString:
102 l := len(d.V) + 1 + len(entropy) + len(nonce)
103 for _, b := range s {
104 pad000(h, l)
105 h.Write(b)
106 l = len(b)
107 }
108 }
109 K = h.Sum(K[:0])
110 // V = HMAC (K, V)
111 h = hmac.New(hash, K)
112 h.Write(d.V)
113 d.V = h.Sum(d.V[:0])
114 115 d.hK = h
116 d.reseedCounter = 1
117 return d
118 }
119 120 // TestingOnlyNewDRBG creates an SP 800-90A Rev. 1 HMAC_DRBG with a plain
121 // personalization string.
122 //
123 // This should only be used for ACVP testing. hmacDRBG is not intended to be
124 // used directly.
125 func TestingOnlyNewDRBG[H hash.Hash](hash func() H, entropy, nonce []byte, s []byte) *hmacDRBG {
126 return newDRBG(hash, entropy, nonce, plainPersonalizationString(s))
127 }
128 129 func pad000(h *hmac.HMAC, writtenSoFar int) {
130 blockSize := h.BlockSize()
131 if rem := writtenSoFar % blockSize; rem != 0 {
132 h.Write([]byte{:blockSize-rem})
133 }
134 }
135 136 // Generate produces at most maxRequestSize bytes of random data in out.
137 func (d *hmacDRBG) Generate(out []byte) {
138 // HMAC_DRBG_Generate_algorithm, per Section 10.1.2.5.
139 fips140.RecordApproved()
140 141 if len(out) > maxRequestSize {
142 panic("ecdsa: internal error: request size exceeds maximum")
143 }
144 145 if d.reseedCounter > reseedInterval {
146 panic("ecdsa: reseed interval exceeded")
147 }
148 149 tlen := 0
150 for tlen < len(out) {
151 // V = HMAC_K(V)
152 // T = T || V
153 d.hK.Reset()
154 d.hK.Write(d.V)
155 d.V = d.hK.Sum(d.V[:0])
156 tlen += copy(out[tlen:], d.V)
157 }
158 159 // Note that if this function shows up on ECDSA-level profiles, this can be
160 // optimized in the common case by deferring the rest to the next Generate
161 // call, which will never come in nearly all cases.
162 163 // HMAC_DRBG_Update, per Section 10.1.2.2, without provided_data.
164 // K = HMAC (K, V || 0x00)
165 d.hK.Reset()
166 d.hK.Write(d.V)
167 d.hK.Write([]byte{0x00})
168 K := d.hK.Sum(nil)
169 // V = HMAC (K, V)
170 d.hK = d.newHMAC(K)
171 d.hK.Write(d.V)
172 d.V = d.hK.Sum(d.V[:0])
173 174 d.reseedCounter++
175 }
176