// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package gcm import ( "crypto/internal/fips140" "crypto/internal/fips140/aes" "crypto/internal/fips140/alias" "crypto/internal/fips140/drbg" "crypto/internal/fips140deps/byteorder" "errors" "math" ) // SealWithRandomNonce encrypts plaintext to out, and writes a random nonce to // nonce. nonce must be 12 bytes, and out must be 16 bytes longer than plaintext. // out and plaintext may overlap exactly or not at all. additionalData and out // must not overlap. // // This complies with FIPS 140-3 IG C.H Scenario 2. // // Note that this is NOT a [cipher.AEAD].Seal method. func SealWithRandomNonce(g *GCM, nonce, out, plaintext, additionalData []byte) { if uint64(len(plaintext)) > uint64((1<<32)-2)*gcmBlockSize { panic("crypto/cipher: message too large for GCM") } if len(nonce) != gcmStandardNonceSize { panic("crypto/cipher: incorrect nonce length given to GCMWithRandomNonce") } if len(out) != len(plaintext)+gcmTagSize { panic("crypto/cipher: incorrect output length given to GCMWithRandomNonce") } if alias.InexactOverlap(out, plaintext) { panic("crypto/cipher: invalid buffer overlap of output and input") } if alias.AnyOverlap(out, additionalData) { panic("crypto/cipher: invalid buffer overlap of output and additional data") } fips140.RecordApproved() drbg.Read(nonce) seal(out, g, nonce, plaintext, additionalData) } // NewGCMWithCounterNonce returns a new AEAD that works like GCM, but enforces // the construction of deterministic nonces. The nonce must be 96 bits, the // first 32 bits must be an encoding of the module name, and the last 64 bits // must be a counter. The starting value of the counter is set on the first call // to Seal, and each subsequent call must increment it as a big-endian uint64. // If the counter reaches the starting value minus one, Seal will panic. // // This complies with FIPS 140-3 IG C.H Scenario 3. func NewGCMWithCounterNonce(cipher *aes.Block) (*GCMWithCounterNonce, error) { g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize) if err != nil { return nil, err } return &GCMWithCounterNonce{g: *g}, nil } // NewGCMForTLS12 returns a new AEAD that works like GCM, but enforces the // construction of nonces as specified in RFC 5288, Section 3 and RFC 9325, // Section 7.2.1. // // This complies with FIPS 140-3 IG C.H Scenario 1.a. func NewGCMForTLS12(cipher *aes.Block) (*GCMWithCounterNonce, error) { g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize) if err != nil { return nil, err } // TLS 1.2 counters always start at zero. return &GCMWithCounterNonce{g: *g, startReady: true}, nil } // NewGCMForSSH returns a new AEAD that works like GCM, but enforces the // construction of nonces as specified in RFC 5647. // // This complies with FIPS 140-3 IG C.H Scenario 1.d. func NewGCMForSSH(cipher *aes.Block) (*GCMWithCounterNonce, error) { g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize) if err != nil { return nil, err } return &GCMWithCounterNonce{g: *g}, nil } type GCMWithCounterNonce struct { g GCM prefixReady bool prefix uint32 startReady bool start uint64 next uint64 } func (g *GCMWithCounterNonce) NonceSize() int { return gcmStandardNonceSize } func (g *GCMWithCounterNonce) Overhead() int { return gcmTagSize } // Seal implements the [cipher.AEAD] interface, checking that the nonce prefix // is stable and that the counter is strictly increasing. // // It is not safe for concurrent use. func (g *GCMWithCounterNonce) Seal(dst, nonce, plaintext, data []byte) []byte { if len(nonce) != gcmStandardNonceSize { panic("crypto/cipher: incorrect nonce length given to GCM") } if fips140.Enabled { if !g.prefixReady { // The first invocation sets the fixed prefix. g.prefixReady = true g.prefix = byteorder.BEUint32(nonce[:4]) } if g.prefix != byteorder.BEUint32(nonce[:4]) { panic("crypto/cipher: GCM nonce prefix changed") } counter := byteorder.BEUint64(nonce[len(nonce)-8:]) if !g.startReady { // The first invocation sets the starting counter, if not fixed. g.startReady = true g.start = counter } counter -= g.start // Ensure the counter is strictly increasing. if counter == math.MaxUint64 { panic("crypto/cipher: counter exhausted") } if counter < g.next { panic("crypto/cipher: counter decreased or remained the same") } g.next = counter + 1 } fips140.RecordApproved() return g.g.sealAfterIndicator(dst, nonce, plaintext, data) } func (g *GCMWithCounterNonce) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { fips140.RecordApproved() return g.g.Open(dst, nonce, ciphertext, data) } // NewGCMWithXORCounterNonce returns a new AEAD that works like GCM, but // enforces the construction of deterministic nonces. The nonce must be 96 bits, // the first 32 bits must be an encoding of the module name, and the last 64 // bits must be a counter XOR'd with a fixed value. The module name and XOR mask // can be set with [GCMWithCounterNonce.SetNoncePrefixAndMask], or they are set // on the first call to Seal, assuming the counter starts at zero. Each // subsequent call must increment the counter as a big-endian uint64. If the // counter reaches 2⁶⁴ minus one, Seal will panic. // // This complies with FIPS 140-3 IG C.H Scenario 3. func NewGCMWithXORCounterNonce(cipher *aes.Block) (*GCMWithXORCounterNonce, error) { g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize) if err != nil { return nil, err } return &GCMWithXORCounterNonce{g: *g}, nil } // NewGCMForTLS13 returns a new AEAD that works like GCM, but enforces the // construction of nonces as specified in RFC 8446, Section 5.3. // // This complies with FIPS 140-3 IG C.H Scenario 1.a. func NewGCMForTLS13(cipher *aes.Block) (*GCMWithXORCounterNonce, error) { g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize) if err != nil { return nil, err } return &GCMWithXORCounterNonce{g: *g}, nil } // NewGCMForHPKE returns a new AEAD that works like GCM, but enforces the // construction of nonces as specified in RFC 9180, Section 5.2. // // This complies with FIPS 140-3 IG C.H Scenario 5. func NewGCMForHPKE(cipher *aes.Block) (*GCMWithXORCounterNonce, error) { g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize) if err != nil { return nil, err } return &GCMWithXORCounterNonce{g: *g}, nil } // NewGCMForQUIC returns a new AEAD that works like GCM, but enforces the // construction of nonces as specified in RFC 9001, Section 5.3. // // Unlike in TLS 1.3, the QUIC nonce counter does not always start at zero, as // the packet number does not reset on key updates, so the XOR mask must be // provided explicitly instead of being learned on the first Seal call. Note // that the nonce passed to Seal must already be XOR'd with the IV, the IV is // provided here only to allow Seal to enforce that the counter is strictly // increasing. // // This complies with FIPS 140-3 IG C.H Scenario 5. func NewGCMForQUIC(cipher *aes.Block, iv []byte) (*GCMWithXORCounterNonce, error) { g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize) if err != nil { return nil, err } gcm := &GCMWithXORCounterNonce{g: *g} if err := gcm.SetNoncePrefixAndMask(iv); err != nil { return nil, err } return gcm, nil } type GCMWithXORCounterNonce struct { g GCM ready bool prefix uint32 mask uint64 next uint64 } // SetNoncePrefixAndMask sets the fixed prefix and XOR mask for the nonces used // in Seal. It must be called before the first call to Seal. // // The first 32 bits of nonce are used as the fixed prefix, and the last 64 bits // are used as the XOR mask. // // Note that Seal expects the nonce to be already XOR'd with the mask. The mask // is provided here only to allow Seal to enforce that the counter is strictly // increasing. func (g *GCMWithXORCounterNonce) SetNoncePrefixAndMask(nonce []byte) error { if len(nonce) != gcmStandardNonceSize { return errors.New("crypto/cipher: incorrect nonce length given to SetNoncePrefixAndMask") } if g.ready { return errors.New("crypto/cipher: SetNoncePrefixAndMask called twice or after first Seal") } g.prefix = byteorder.BEUint32(nonce[:4]) g.mask = byteorder.BEUint64(nonce[4:]) g.ready = true return nil } func (g *GCMWithXORCounterNonce) NonceSize() int { return gcmStandardNonceSize } func (g *GCMWithXORCounterNonce) Overhead() int { return gcmTagSize } // Seal implements the [cipher.AEAD] interface, checking that the nonce prefix // is stable and that the counter is strictly increasing. // // It is not safe for concurrent use. func (g *GCMWithXORCounterNonce) Seal(dst, nonce, plaintext, data []byte) []byte { if len(nonce) != gcmStandardNonceSize { panic("crypto/cipher: incorrect nonce length given to GCM") } if fips140.Enabled { counter := byteorder.BEUint64(nonce[len(nonce)-8:]) if !g.ready { // In the first call, if [GCMWithXORCounterNonce.SetNoncePrefixAndMask] // wasn't used, we assume the counter is zero to learn the XOR mask and // fixed prefix. g.ready = true g.mask = counter g.prefix = byteorder.BEUint32(nonce[:4]) } if g.prefix != byteorder.BEUint32(nonce[:4]) { panic("crypto/cipher: GCM nonce prefix changed") } counter ^= g.mask // Ensure the counter is strictly increasing. if counter == math.MaxUint64 { panic("crypto/cipher: counter exhausted") } if counter < g.next { panic("crypto/cipher: counter decreased or remained the same") } g.next = counter + 1 } fips140.RecordApproved() return g.g.sealAfterIndicator(dst, nonce, plaintext, data) } func (g *GCMWithXORCounterNonce) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { fips140.RecordApproved() return g.g.Open(dst, nonce, ciphertext, data) }