// Copyright 2022 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 ecdh import ( "bytes" "crypto/internal/boring" "crypto/internal/fips140/ecdh" "crypto/internal/fips140only" "errors" "io" ) type nistCurve struct { name string generate func(io.Reader) (*ecdh.PrivateKey, error) newPrivateKey func([]byte) (*ecdh.PrivateKey, error) newPublicKey func(publicKey []byte) (*ecdh.PublicKey, error) sharedSecret func(*ecdh.PrivateKey, *ecdh.PublicKey) (sharedSecret []byte, err error) } func (c *nistCurve) String() string { return c.name } func (c *nistCurve) GenerateKey(rand io.Reader) (*PrivateKey, error) { if boring.Enabled && rand == boring.RandReader { key, bytes, err := boring.GenerateKeyECDH(c.name) if err != nil { return nil, err } pub, err := key.PublicKey() if err != nil { return nil, err } k := &PrivateKey{ curve: c, privateKey: bytes, publicKey: &PublicKey{curve: c, publicKey: pub.Bytes(), boring: pub}, boring: key, } return k, nil } if fips140only.Enabled && !fips140only.ApprovedRandomReader(rand) { return nil, errors.New("crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-only mode") } privateKey, err := c.generate(rand) if err != nil { return nil, err } k := &PrivateKey{ curve: c, privateKey: privateKey.Bytes(), fips: privateKey, publicKey: &PublicKey{ curve: c, publicKey: privateKey.PublicKey().Bytes(), fips: privateKey.PublicKey(), }, } if boring.Enabled { bk, err := boring.NewPrivateKeyECDH(c.name, k.privateKey) if err != nil { return nil, err } pub, err := bk.PublicKey() if err != nil { return nil, err } k.boring = bk k.publicKey.boring = pub } return k, nil } func (c *nistCurve) NewPrivateKey(key []byte) (*PrivateKey, error) { if boring.Enabled { bk, err := boring.NewPrivateKeyECDH(c.name, key) if err != nil { return nil, errors.New("crypto/ecdh: invalid private key") } pub, err := bk.PublicKey() if err != nil { return nil, errors.New("crypto/ecdh: invalid private key") } k := &PrivateKey{ curve: c, privateKey: bytes.Clone(key), publicKey: &PublicKey{curve: c, publicKey: pub.Bytes(), boring: pub}, boring: bk, } return k, nil } fk, err := c.newPrivateKey(key) if err != nil { return nil, err } k := &PrivateKey{ curve: c, privateKey: bytes.Clone(key), fips: fk, publicKey: &PublicKey{ curve: c, publicKey: fk.PublicKey().Bytes(), fips: fk.PublicKey(), }, } return k, nil } func (c *nistCurve) NewPublicKey(key []byte) (*PublicKey, error) { // Reject the point at infinity and compressed encodings. // Note that boring.NewPublicKeyECDH would accept them. if len(key) == 0 || key[0] != 4 { return nil, errors.New("crypto/ecdh: invalid public key") } k := &PublicKey{ curve: c, publicKey: bytes.Clone(key), } if boring.Enabled { bk, err := boring.NewPublicKeyECDH(c.name, k.publicKey) if err != nil { return nil, errors.New("crypto/ecdh: invalid public key") } k.boring = bk } else { fk, err := c.newPublicKey(key) if err != nil { return nil, err } k.fips = fk } return k, nil } func (c *nistCurve) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) { // Note that this function can't return an error, as NewPublicKey rejects // invalid points and the point at infinity, and NewPrivateKey rejects // invalid scalars and the zero value. BytesX returns an error for the point // at infinity, but in a prime order group such as the NIST curves that can // only be the result of a scalar multiplication if one of the inputs is the // zero scalar or the point at infinity. if boring.Enabled { return boring.ECDH(local.boring, remote.boring) } return c.sharedSecret(local.fips, remote.fips) } // P256 returns a [Curve] which implements NIST P-256 (FIPS 186-3, section D.2.3), // also known as secp256r1 or prime256v1. // // Multiple invocations of this function will return the same value, which can // be used for equality checks and switch statements. func P256() Curve { return p256 } var p256 = &nistCurve{ name: "P-256", generate: func(r io.Reader) (*ecdh.PrivateKey, error) { return ecdh.GenerateKey(ecdh.P256(), r) }, newPrivateKey: func(b []byte) (*ecdh.PrivateKey, error) { return ecdh.NewPrivateKey(ecdh.P256(), b) }, newPublicKey: func(publicKey []byte) (*ecdh.PublicKey, error) { return ecdh.NewPublicKey(ecdh.P256(), publicKey) }, sharedSecret: func(priv *ecdh.PrivateKey, pub *ecdh.PublicKey) (sharedSecret []byte, err error) { return ecdh.ECDH(ecdh.P256(), priv, pub) }, } // P384 returns a [Curve] which implements NIST P-384 (FIPS 186-3, section D.2.4), // also known as secp384r1. // // Multiple invocations of this function will return the same value, which can // be used for equality checks and switch statements. func P384() Curve { return p384 } var p384 = &nistCurve{ name: "P-384", generate: func(r io.Reader) (*ecdh.PrivateKey, error) { return ecdh.GenerateKey(ecdh.P384(), r) }, newPrivateKey: func(b []byte) (*ecdh.PrivateKey, error) { return ecdh.NewPrivateKey(ecdh.P384(), b) }, newPublicKey: func(publicKey []byte) (*ecdh.PublicKey, error) { return ecdh.NewPublicKey(ecdh.P384(), publicKey) }, sharedSecret: func(priv *ecdh.PrivateKey, pub *ecdh.PublicKey) (sharedSecret []byte, err error) { return ecdh.ECDH(ecdh.P384(), priv, pub) }, } // P521 returns a [Curve] which implements NIST P-521 (FIPS 186-3, section D.2.5), // also known as secp521r1. // // Multiple invocations of this function will return the same value, which can // be used for equality checks and switch statements. func P521() Curve { return p521 } var p521 = &nistCurve{ name: "P-521", generate: func(r io.Reader) (*ecdh.PrivateKey, error) { return ecdh.GenerateKey(ecdh.P521(), r) }, newPrivateKey: func(b []byte) (*ecdh.PrivateKey, error) { return ecdh.NewPrivateKey(ecdh.P521(), b) }, newPublicKey: func(publicKey []byte) (*ecdh.PublicKey, error) { return ecdh.NewPublicKey(ecdh.P521(), publicKey) }, sharedSecret: func(priv *ecdh.PrivateKey, pub *ecdh.PublicKey) (sharedSecret []byte, err error) { return ecdh.ECDH(ecdh.P521(), priv, pub) }, }