hmacdrbg.mx raw

   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