]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/internal/fips/aes/gcm: add GCMForTLS12 and GCMForTLS13
authorFilippo Valsorda <filippo@golang.org>
Fri, 8 Nov 2024 18:56:50 +0000 (19:56 +0100)
committerGopher Robot <gobot@golang.org>
Tue, 19 Nov 2024 00:32:09 +0000 (00:32 +0000)
For #69536

Change-Id: I2d7b6e7b9932d0f0f582a5ab0bb871395dc2a1e8
Reviewed-on: https://go-review.googlesource.com/c/go/+/626675
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>

src/crypto/internal/fips/aes/gcm/gcm_nonces.go
src/crypto/tls/cipher_suites.go

index 3dc02ac07a34426a4807f39c307b2cb78472de29..2d3164033ad93fed1026271496e177ce1885e410 100644 (file)
@@ -5,8 +5,11 @@
 package gcm
 
 import (
+       "crypto/internal/fips/aes"
        "crypto/internal/fips/alias"
        "crypto/internal/fips/drbg"
+       "internal/byteorder"
+       "math"
 )
 
 // SealWithRandomNonce encrypts plaintext to out, and writes a random nonce to
@@ -36,3 +39,98 @@ func SealWithRandomNonce(g *GCM, nonce, out, plaintext, additionalData []byte) {
        drbg.Read(nonce)
        seal(out, g, nonce, plaintext, additionalData)
 }
+
+// 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 Resolution 1.a.
+func NewGCMForTLS12(cipher *aes.Block) (*GCMForTLS12, error) {
+       g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize)
+       if err != nil {
+               return nil, err
+       }
+       return &GCMForTLS12{g: *g}, nil
+}
+
+type GCMForTLS12 struct {
+       g    GCM
+       next uint64
+}
+
+func (g *GCMForTLS12) NonceSize() int { return gcmStandardNonceSize }
+
+func (g *GCMForTLS12) Overhead() int { return gcmTagSize }
+
+func (g *GCMForTLS12) Seal(dst, nonce, plaintext, data []byte) []byte {
+       if len(nonce) != gcmStandardNonceSize {
+               panic("crypto/cipher: incorrect nonce length given to GCM")
+       }
+
+       counter := byteorder.BeUint64(nonce[len(nonce)-8:])
+
+       // Ensure the counter is monotonically increasing.
+       if counter == math.MaxUint64 {
+               panic("crypto/cipher: counter wrapped")
+       }
+       if counter < g.next {
+               panic("crypto/cipher: counter decreased")
+       }
+       g.next = counter + 1
+
+       return g.g.Seal(dst, nonce, plaintext, data)
+}
+
+func (g *GCMForTLS12) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
+       return g.g.Open(dst, nonce, ciphertext, data)
+}
+
+// NewGCMForTLS13 returns a new AEAD that works like GCM, but enforces the
+// construction of nonces as specified in RFC 8446, Section 5.3.
+func NewGCMForTLS13(cipher *aes.Block) (*GCMForTLS13, error) {
+       g, err := newGCM(&GCM{}, cipher, gcmStandardNonceSize, gcmTagSize)
+       if err != nil {
+               return nil, err
+       }
+       return &GCMForTLS13{g: *g}, nil
+}
+
+type GCMForTLS13 struct {
+       g     GCM
+       ready bool
+       mask  uint64
+       next  uint64
+}
+
+func (g *GCMForTLS13) NonceSize() int { return gcmStandardNonceSize }
+
+func (g *GCMForTLS13) Overhead() int { return gcmTagSize }
+
+func (g *GCMForTLS13) Seal(dst, nonce, plaintext, data []byte) []byte {
+       if len(nonce) != gcmStandardNonceSize {
+               panic("crypto/cipher: incorrect nonce length given to GCM")
+       }
+
+       counter := byteorder.BeUint64(nonce[len(nonce)-8:])
+       if !g.ready {
+               // In the first call, the counter is zero, so we learn the XOR mask.
+               g.ready = true
+               g.mask = counter
+       }
+       counter ^= g.mask
+
+       // Ensure the counter is monotonically increasing.
+       if counter == math.MaxUint64 {
+               panic("crypto/cipher: counter wrapped")
+       }
+       if counter < g.next {
+               panic("crypto/cipher: counter decreased")
+       }
+       g.next = counter + 1
+
+       return g.g.Seal(dst, nonce, plaintext, data)
+}
+
+func (g *GCMForTLS13) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
+       return g.g.Open(dst, nonce, ciphertext, data)
+}
index ec867ceab0acbaf0d173b5b8f6f6c6d9c14fa8aa..1c849e3c2746dd430723718a1dff4ade0f55e574 100644 (file)
@@ -11,6 +11,8 @@ import (
        "crypto/des"
        "crypto/hmac"
        "crypto/internal/boring"
+       fipsaes "crypto/internal/fips/aes"
+       "crypto/internal/fips/aes/gcm"
        "crypto/rc4"
        "crypto/sha1"
        "crypto/sha256"
@@ -521,7 +523,7 @@ func aeadAESGCM(key, noncePrefix []byte) aead {
                aead, err = boring.NewGCMTLS(aes)
        } else {
                boring.Unreachable()
-               aead, err = cipher.NewGCM(aes)
+               aead, err = gcm.NewGCMForTLS12(aes.(*fipsaes.Block))
        }
        if err != nil {
                panic(err)
@@ -555,7 +557,7 @@ func aeadAESGCMTLS13(key, nonceMask []byte) aead {
                aead, err = boring.NewGCMTLS13(aes)
        } else {
                boring.Unreachable()
-               aead, err = cipher.NewGCM(aes)
+               aead, err = gcm.NewGCMForTLS13(aes.(*fipsaes.Block))
        }
        if err != nil {
                panic(err)