Source file src/crypto/internal/fips140/ecdsa/hmacdrbg.go

     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 := make([]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(hash func() hash.Hash, 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(make([]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  

View as plain text