Source file src/crypto/internal/fips140/aes/gcm/gcm_nonces.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 gcm
     6  
     7  import (
     8  	"crypto/internal/fips140"
     9  	"crypto/internal/fips140/aes"
    10  	"crypto/internal/fips140/alias"
    11  	"crypto/internal/fips140/drbg"
    12  	"crypto/internal/fips140deps/byteorder"
    13  	"errors"
    14  	"math"
    15  )
    16  
    17  // SealWithRandomNonce encrypts plaintext to out, and writes a random nonce to
    18  // nonce. nonce must be 12 bytes, and out must be 16 bytes longer than plaintext.
    19  // out and plaintext may overlap exactly or not at all. additionalData and out
    20  // must not overlap.
    21  //
    22  // This complies with FIPS 140-3 IG C.H Scenario 2.
    23  //
    24  // Note that this is NOT a [cipher.AEAD].Seal method.
    25  func SealWithRandomNonce(g *GCM, nonce, out, plaintext, additionalData []byte) {
    26  	if uint64(len(plaintext)) > uint64((1<<32)-2)*gcmBlockSize {
    27  		panic("crypto/cipher: message too large for GCM")
    28  	}
    29  	if len(nonce) != gcmStandardNonceSize {
    30  		panic("crypto/cipher: incorrect nonce length given to GCMWithRandomNonce")
    31  	}
    32  	if len(out) != len(plaintext)+gcmTagSize {
    33  		panic("crypto/cipher: incorrect output length given to GCMWithRandomNonce")
    34  	}
    35  	if alias.InexactOverlap(out, plaintext) {
    36  		panic("crypto/cipher: invalid buffer overlap of output and input")
    37  	}
    38  	if alias.AnyOverlap(out, additionalData) {
    39  		panic("crypto/cipher: invalid buffer overlap of output and additional data")
    40  	}
    41  	fips140.RecordApproved()
    42  	drbg.Read(nonce)
    43  	seal(out, g, nonce, plaintext, additionalData)
    44  }
    45  
    46  // NewGCMWithCounterNonce returns a new AEAD that works like GCM, but enforces
    47  // the construction of deterministic nonces. The nonce must be 96 bits, the
    48  // first 32 bits must be an encoding of the module name, and the last 64 bits
    49  // must be a counter. The starting value of the counter is set on the first call
    50  // to Seal, and each subsequent call must increment it as a big-endian uint64.
    51  // If the counter reaches the starting value minus one, Seal will panic.
    52  //
    53  // This complies with FIPS 140-3 IG C.H Scenario 3.
    54  func NewGCMWithCounterNonce(cipher *aes.Block) (*GCMWithCounterNonce, error) {
    55  	g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	return &GCMWithCounterNonce{g: *g}, nil
    60  }
    61  
    62  // NewGCMForTLS12 returns a new AEAD that works like GCM, but enforces the
    63  // construction of nonces as specified in RFC 5288, Section 3 and RFC 9325,
    64  // Section 7.2.1.
    65  //
    66  // This complies with FIPS 140-3 IG C.H Scenario 1.a.
    67  func NewGCMForTLS12(cipher *aes.Block) (*GCMWithCounterNonce, error) {
    68  	g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	// TLS 1.2 counters always start at zero.
    73  	return &GCMWithCounterNonce{g: *g, startReady: true}, nil
    74  }
    75  
    76  // NewGCMForSSH returns a new AEAD that works like GCM, but enforces the
    77  // construction of nonces as specified in RFC 5647.
    78  //
    79  // This complies with FIPS 140-3 IG C.H Scenario 1.d.
    80  func NewGCMForSSH(cipher *aes.Block) (*GCMWithCounterNonce, error) {
    81  	g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	return &GCMWithCounterNonce{g: *g}, nil
    86  }
    87  
    88  type GCMWithCounterNonce struct {
    89  	g           GCM
    90  	prefixReady bool
    91  	prefix      uint32
    92  	startReady  bool
    93  	start       uint64
    94  	next        uint64
    95  }
    96  
    97  func (g *GCMWithCounterNonce) NonceSize() int { return gcmStandardNonceSize }
    98  
    99  func (g *GCMWithCounterNonce) Overhead() int { return gcmTagSize }
   100  
   101  // Seal implements the [cipher.AEAD] interface, checking that the nonce prefix
   102  // is stable and that the counter is strictly increasing.
   103  //
   104  // It is not safe for concurrent use.
   105  func (g *GCMWithCounterNonce) Seal(dst, nonce, plaintext, data []byte) []byte {
   106  	if len(nonce) != gcmStandardNonceSize {
   107  		panic("crypto/cipher: incorrect nonce length given to GCM")
   108  	}
   109  
   110  	if fips140.Enabled {
   111  		if !g.prefixReady {
   112  			// The first invocation sets the fixed prefix.
   113  			g.prefixReady = true
   114  			g.prefix = byteorder.BEUint32(nonce[:4])
   115  		}
   116  		if g.prefix != byteorder.BEUint32(nonce[:4]) {
   117  			panic("crypto/cipher: GCM nonce prefix changed")
   118  		}
   119  
   120  		counter := byteorder.BEUint64(nonce[len(nonce)-8:])
   121  		if !g.startReady {
   122  			// The first invocation sets the starting counter, if not fixed.
   123  			g.startReady = true
   124  			g.start = counter
   125  		}
   126  		counter -= g.start
   127  
   128  		// Ensure the counter is strictly increasing.
   129  		if counter == math.MaxUint64 {
   130  			panic("crypto/cipher: counter exhausted")
   131  		}
   132  		if counter < g.next {
   133  			panic("crypto/cipher: counter decreased or remained the same")
   134  		}
   135  		g.next = counter + 1
   136  	}
   137  
   138  	fips140.RecordApproved()
   139  	return g.g.sealAfterIndicator(dst, nonce, plaintext, data)
   140  }
   141  
   142  func (g *GCMWithCounterNonce) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
   143  	fips140.RecordApproved()
   144  	return g.g.Open(dst, nonce, ciphertext, data)
   145  }
   146  
   147  // NewGCMWithXORCounterNonce returns a new AEAD that works like GCM, but
   148  // enforces the construction of deterministic nonces. The nonce must be 96 bits,
   149  // the first 32 bits must be an encoding of the module name, and the last 64
   150  // bits must be a counter XOR'd with a fixed value. The module name and XOR mask
   151  // can be set with [GCMWithCounterNonce.SetNoncePrefixAndMask], or they are set
   152  // on the first call to Seal, assuming the counter starts at zero. Each
   153  // subsequent call must increment the counter as a big-endian uint64. If the
   154  // counter reaches 2⁶⁴ minus one, Seal will panic.
   155  //
   156  // This complies with FIPS 140-3 IG C.H Scenario 3.
   157  func NewGCMWithXORCounterNonce(cipher *aes.Block) (*GCMWithXORCounterNonce, error) {
   158  	g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize)
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  	return &GCMWithXORCounterNonce{g: *g}, nil
   163  }
   164  
   165  // NewGCMForTLS13 returns a new AEAD that works like GCM, but enforces the
   166  // construction of nonces as specified in RFC 8446, Section 5.3.
   167  //
   168  // This complies with FIPS 140-3 IG C.H Scenario 1.a.
   169  func NewGCMForTLS13(cipher *aes.Block) (*GCMWithXORCounterNonce, error) {
   170  	g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	return &GCMWithXORCounterNonce{g: *g}, nil
   175  }
   176  
   177  // NewGCMForHPKE returns a new AEAD that works like GCM, but enforces the
   178  // construction of nonces as specified in RFC 9180, Section 5.2.
   179  //
   180  // This complies with FIPS 140-3 IG C.H Scenario 5.
   181  func NewGCMForHPKE(cipher *aes.Block) (*GCMWithXORCounterNonce, error) {
   182  	g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	return &GCMWithXORCounterNonce{g: *g}, nil
   187  }
   188  
   189  // NewGCMForQUIC returns a new AEAD that works like GCM, but enforces the
   190  // construction of nonces as specified in RFC 9001, Section 5.3.
   191  //
   192  // Unlike in TLS 1.3, the QUIC nonce counter does not always start at zero, as
   193  // the packet number does not reset on key updates, so the XOR mask must be
   194  // provided explicitly instead of being learned on the first Seal call. Note
   195  // that the nonce passed to Seal must already be XOR'd with the IV, the IV is
   196  // provided here only to allow Seal to enforce that the counter is strictly
   197  // increasing.
   198  //
   199  // This complies with FIPS 140-3 IG C.H Scenario 5.
   200  func NewGCMForQUIC(cipher *aes.Block, iv []byte) (*GCMWithXORCounterNonce, error) {
   201  	g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	gcm := &GCMWithXORCounterNonce{g: *g}
   206  	if err := gcm.SetNoncePrefixAndMask(iv); err != nil {
   207  		return nil, err
   208  	}
   209  	return gcm, nil
   210  }
   211  
   212  type GCMWithXORCounterNonce struct {
   213  	g      GCM
   214  	ready  bool
   215  	prefix uint32
   216  	mask   uint64
   217  	next   uint64
   218  }
   219  
   220  // SetNoncePrefixAndMask sets the fixed prefix and XOR mask for the nonces used
   221  // in Seal. It must be called before the first call to Seal.
   222  //
   223  // The first 32 bits of nonce are used as the fixed prefix, and the last 64 bits
   224  // are used as the XOR mask.
   225  //
   226  // Note that Seal expects the nonce to be already XOR'd with the mask. The mask
   227  // is provided here only to allow Seal to enforce that the counter is strictly
   228  // increasing.
   229  func (g *GCMWithXORCounterNonce) SetNoncePrefixAndMask(nonce []byte) error {
   230  	if len(nonce) != gcmStandardNonceSize {
   231  		return errors.New("crypto/cipher: incorrect nonce length given to SetNoncePrefixAndMask")
   232  	}
   233  	if g.ready {
   234  		return errors.New("crypto/cipher: SetNoncePrefixAndMask called twice or after first Seal")
   235  	}
   236  	g.prefix = byteorder.BEUint32(nonce[:4])
   237  	g.mask = byteorder.BEUint64(nonce[4:])
   238  	g.ready = true
   239  	return nil
   240  }
   241  
   242  func (g *GCMWithXORCounterNonce) NonceSize() int { return gcmStandardNonceSize }
   243  
   244  func (g *GCMWithXORCounterNonce) Overhead() int { return gcmTagSize }
   245  
   246  // Seal implements the [cipher.AEAD] interface, checking that the nonce prefix
   247  // is stable and that the counter is strictly increasing.
   248  //
   249  // It is not safe for concurrent use.
   250  func (g *GCMWithXORCounterNonce) Seal(dst, nonce, plaintext, data []byte) []byte {
   251  	if len(nonce) != gcmStandardNonceSize {
   252  		panic("crypto/cipher: incorrect nonce length given to GCM")
   253  	}
   254  
   255  	if fips140.Enabled {
   256  		counter := byteorder.BEUint64(nonce[len(nonce)-8:])
   257  		if !g.ready {
   258  			// In the first call, if [GCMWithXORCounterNonce.SetNoncePrefixAndMask]
   259  			// wasn't used, we assume the counter is zero to learn the XOR mask and
   260  			// fixed prefix.
   261  			g.ready = true
   262  			g.mask = counter
   263  			g.prefix = byteorder.BEUint32(nonce[:4])
   264  		}
   265  		if g.prefix != byteorder.BEUint32(nonce[:4]) {
   266  			panic("crypto/cipher: GCM nonce prefix changed")
   267  		}
   268  		counter ^= g.mask
   269  
   270  		// Ensure the counter is strictly increasing.
   271  		if counter == math.MaxUint64 {
   272  			panic("crypto/cipher: counter exhausted")
   273  		}
   274  		if counter < g.next {
   275  			panic("crypto/cipher: counter decreased or remained the same")
   276  		}
   277  		g.next = counter + 1
   278  	}
   279  
   280  	fips140.RecordApproved()
   281  	return g.g.sealAfterIndicator(dst, nonce, plaintext, data)
   282  }
   283  
   284  func (g *GCMWithXORCounterNonce) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
   285  	fips140.RecordApproved()
   286  	return g.g.Open(dst, nonce, ciphertext, data)
   287  }
   288  

View as plain text