Source file src/crypto/ecdh/ecdh.go

     1  // Copyright 2022 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 ecdh implements Elliptic Curve Diffie-Hellman over
     6  // NIST curves and Curve25519.
     7  package ecdh
     8  
     9  import (
    10  	"crypto"
    11  	"crypto/internal/boring"
    12  	"crypto/internal/fips140/ecdh"
    13  	"crypto/subtle"
    14  	"errors"
    15  	"io"
    16  )
    17  
    18  type Curve interface {
    19  	// GenerateKey generates a random PrivateKey.
    20  	//
    21  	// Since Go 1.26, a secure source of random bytes is always used, and rand
    22  	// is ignored unless GODEBUG=cryptocustomrand=1 is set. This setting will be
    23  	// removed in a future Go release. Instead, use [testing/cryptotest.SetGlobalRandom].
    24  	GenerateKey(rand io.Reader) (*PrivateKey, error)
    25  
    26  	// NewPrivateKey checks that key is valid and returns a PrivateKey.
    27  	//
    28  	// For NIST curves, this follows SEC 1, Version 2.0, Section 2.3.6, which
    29  	// amounts to decoding the bytes as a fixed length big endian integer and
    30  	// checking that the result is lower than the order of the curve. The zero
    31  	// private key is also rejected, as the encoding of the corresponding public
    32  	// key would be irregular.
    33  	//
    34  	// For X25519, this only checks the scalar length.
    35  	NewPrivateKey(key []byte) (*PrivateKey, error)
    36  
    37  	// NewPublicKey checks that key is valid and returns a PublicKey.
    38  	//
    39  	// For NIST curves, this decodes an uncompressed point according to SEC 1,
    40  	// Version 2.0, Section 2.3.4. Compressed encodings and the point at
    41  	// infinity are rejected.
    42  	//
    43  	// For X25519, this only checks the u-coordinate length. Adversarially
    44  	// selected public keys can cause ECDH to return an error.
    45  	NewPublicKey(key []byte) (*PublicKey, error)
    46  
    47  	// ecdh performs an ECDH exchange and returns the shared secret. It's exposed
    48  	// as the PrivateKey.ECDH method.
    49  	//
    50  	// The private method also allow us to expand the ECDH interface with more
    51  	// methods in the future without breaking backwards compatibility.
    52  	ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error)
    53  }
    54  
    55  // PublicKey is an ECDH public key, usually a peer's ECDH share sent over the wire.
    56  //
    57  // These keys can be parsed with [crypto/x509.ParsePKIXPublicKey] and encoded
    58  // with [crypto/x509.MarshalPKIXPublicKey]. For NIST curves, they then need to
    59  // be converted with [crypto/ecdsa.PublicKey.ECDH] after parsing.
    60  type PublicKey struct {
    61  	curve     Curve
    62  	publicKey []byte
    63  	boring    *boring.PublicKeyECDH
    64  	fips      *ecdh.PublicKey
    65  }
    66  
    67  // Bytes returns a copy of the encoding of the public key.
    68  func (k *PublicKey) Bytes() []byte {
    69  	// Copy the public key to a fixed size buffer that can get allocated on the
    70  	// caller's stack after inlining.
    71  	var buf [133]byte
    72  	return append(buf[:0], k.publicKey...)
    73  }
    74  
    75  // Equal returns whether x represents the same public key as k.
    76  //
    77  // Note that there can be equivalent public keys with different encodings which
    78  // would return false from this check but behave the same way as inputs to ECDH.
    79  //
    80  // This check is performed in constant time as long as the key types and their
    81  // curve match.
    82  func (k *PublicKey) Equal(x crypto.PublicKey) bool {
    83  	xx, ok := x.(*PublicKey)
    84  	if !ok {
    85  		return false
    86  	}
    87  	return k.curve == xx.curve &&
    88  		subtle.ConstantTimeCompare(k.publicKey, xx.publicKey) == 1
    89  }
    90  
    91  func (k *PublicKey) Curve() Curve {
    92  	return k.curve
    93  }
    94  
    95  // KeyExchanger is an interface for an opaque private key that can be used for
    96  // key exchange operations. For example, an ECDH key kept in a hardware module.
    97  //
    98  // It is implemented by [PrivateKey].
    99  type KeyExchanger interface {
   100  	PublicKey() *PublicKey
   101  	Curve() Curve
   102  	ECDH(*PublicKey) ([]byte, error)
   103  }
   104  
   105  var _ KeyExchanger = (*PrivateKey)(nil)
   106  
   107  // PrivateKey is an ECDH private key, usually kept secret.
   108  //
   109  // These keys can be parsed with [crypto/x509.ParsePKCS8PrivateKey] and encoded
   110  // with [crypto/x509.MarshalPKCS8PrivateKey]. For NIST curves, they then need to
   111  // be converted with [crypto/ecdsa.PrivateKey.ECDH] after parsing.
   112  type PrivateKey struct {
   113  	curve      Curve
   114  	privateKey []byte
   115  	publicKey  *PublicKey
   116  	boring     *boring.PrivateKeyECDH
   117  	fips       *ecdh.PrivateKey
   118  }
   119  
   120  // ECDH performs an ECDH exchange and returns the shared secret. The [PrivateKey]
   121  // and [PublicKey] must use the same curve.
   122  //
   123  // For NIST curves, this performs ECDH as specified in SEC 1, Version 2.0,
   124  // Section 3.3.1, and returns the x-coordinate encoded according to SEC 1,
   125  // Version 2.0, Section 2.3.5. The result is never the point at infinity.
   126  // This is also known as the Shared Secret Computation of the Ephemeral Unified
   127  // Model scheme specified in NIST SP 800-56A Rev. 3, Section 6.1.2.2.
   128  //
   129  // For [X25519], this performs ECDH as specified in RFC 7748, Section 6.1. If
   130  // the result is the all-zero value, ECDH returns an error.
   131  func (k *PrivateKey) ECDH(remote *PublicKey) ([]byte, error) {
   132  	if k.curve != remote.curve {
   133  		return nil, errors.New("crypto/ecdh: private key and public key curves do not match")
   134  	}
   135  	return k.curve.ecdh(k, remote)
   136  }
   137  
   138  // Bytes returns a copy of the encoding of the private key.
   139  func (k *PrivateKey) Bytes() []byte {
   140  	// Copy the private key to a fixed size buffer that can get allocated on the
   141  	// caller's stack after inlining.
   142  	var buf [66]byte
   143  	return append(buf[:0], k.privateKey...)
   144  }
   145  
   146  // Equal returns whether x represents the same private key as k.
   147  //
   148  // Note that there can be equivalent private keys with different encodings which
   149  // would return false from this check but behave the same way as inputs to [ECDH].
   150  //
   151  // This check is performed in constant time as long as the key types and their
   152  // curve match.
   153  func (k *PrivateKey) Equal(x crypto.PrivateKey) bool {
   154  	xx, ok := x.(*PrivateKey)
   155  	if !ok {
   156  		return false
   157  	}
   158  	return k.curve == xx.curve &&
   159  		subtle.ConstantTimeCompare(k.privateKey, xx.privateKey) == 1
   160  }
   161  
   162  func (k *PrivateKey) Curve() Curve {
   163  	return k.curve
   164  }
   165  
   166  func (k *PrivateKey) PublicKey() *PublicKey {
   167  	return k.publicKey
   168  }
   169  
   170  // Public implements the implicit interface of all standard library private
   171  // keys. See the docs of [crypto.PrivateKey].
   172  func (k *PrivateKey) Public() crypto.PublicKey {
   173  	return k.PublicKey()
   174  }
   175  

View as plain text