]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/hpke: apply fips140.WithoutEnforcement to ML-KEM+X25519 hybrid
authorFilippo Valsorda <filippo@golang.org>
Tue, 9 Dec 2025 00:04:16 +0000 (01:04 +0100)
committerGopher Robot <gobot@golang.org>
Wed, 10 Dec 2025 21:46:00 +0000 (13:46 -0800)
Since it uses an Approved KEM (ML-KEM), the overall hybrid KEM is
Approved, even if X25519 is not.

Updates #70514
Updates #74630

Change-Id: I2bb60c36fcf570baa3c389e2daa3698e6a6a6964
Reviewed-on: https://go-review.googlesource.com/c/go/+/728505
Auto-Submit: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
src/crypto/hpke/pq.go

index f2adbef54ea808053976fcfce54c70c173698246..e8dc80fd23a61a268dde3fd8f3bb4a74cbc62e6d 100644 (file)
@@ -8,6 +8,7 @@ import (
        "bytes"
        "crypto"
        "crypto/ecdh"
+       "crypto/fips140"
        "crypto/internal/fips140/drbg"
        "crypto/internal/rand"
        "crypto/mlkem"
@@ -168,7 +169,10 @@ func (kem *hybridKEM) NewPublicKey(data []byte) (PublicKey, error) {
        if err != nil {
                return nil, err
        }
-       k, err := kem.curve.NewPublicKey(data[kem.pqEncapsKeySize:])
+       var k *ecdh.PublicKey
+       fips140.WithoutEnforcement(func() { // Hybrid of ML-KEM, which is Approved.
+               k, err = kem.curve.NewPublicKey(data[kem.pqEncapsKeySize:])
+       })
        if err != nil {
                return nil, err
        }
@@ -186,14 +190,20 @@ func (pk *hybridPublicKey) Bytes() []byte {
 var testingOnlyEncapsulate func() (ss, ct []byte)
 
 func (pk *hybridPublicKey) encap() (sharedSecret []byte, encapPub []byte, err error) {
-       skE, err := pk.t.Curve().GenerateKey(rand.Reader)
+       var skE *ecdh.PrivateKey
+       fips140.WithoutEnforcement(func() { // Hybrid of ML-KEM, which is Approved.
+               skE, err = pk.t.Curve().GenerateKey(rand.Reader)
+       })
        if err != nil {
                return nil, nil, err
        }
        if testingOnlyGenerateKey != nil {
                skE = testingOnlyGenerateKey()
        }
-       ssT, err := skE.ECDH(pk.t)
+       var ssT []byte
+       fips140.WithoutEnforcement(func() {
+               ssT, err = skE.ECDH(pk.t)
+       })
        if err != nil {
                return nil, nil, err
        }
@@ -259,7 +269,10 @@ func (kem *hybridKEM) NewPrivateKey(priv []byte) (PrivateKey, error) {
        seedT := make([]byte, kem.curveSeedSize)
        for {
                s.Read(seedT)
-               k, err := kem.curve.NewPrivateKey(seedT)
+               var k ecdh.KeyExchanger
+               fips140.WithoutEnforcement(func() { // Hybrid of ML-KEM, which is Approved.
+                       k, err = kem.curve.NewPrivateKey(seedT)
+               })
                if err != nil {
                        continue
                }
@@ -326,11 +339,17 @@ func (k *hybridPrivateKey) decap(enc []byte) ([]byte, error) {
        if err != nil {
                return nil, err
        }
-       pub, err := k.t.Curve().NewPublicKey(ctT)
+       var pub *ecdh.PublicKey
+       fips140.WithoutEnforcement(func() { // Hybrid of ML-KEM, which is Approved.
+               pub, err = k.t.Curve().NewPublicKey(ctT)
+       })
        if err != nil {
                return nil, err
        }
-       ssT, err := k.t.ECDH(pub)
+       var ssT []byte
+       fips140.WithoutEnforcement(func() {
+               ssT, err = k.t.ECDH(pub)
+       })
        if err != nil {
                return nil, err
        }