github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/crypto/ecdh/ecdh.go (about)

     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/subtle"
    12  	"io"
    13  	"sync"
    14  )
    15  
    16  type Curve interface {
    17  	// ECDH performs a ECDH exchange and returns the shared secret.
    18  	//
    19  	// For NIST curves, this performs ECDH as specified in SEC 1, Version 2.0,
    20  	// Section 3.3.1, and returns the x-coordinate encoded according to SEC 1,
    21  	// Version 2.0, Section 2.3.5. In particular, if the result is the point at
    22  	// infinity, ECDH returns an error. (Note that for NIST curves, that's only
    23  	// possible if the private key is the all-zero value.)
    24  	//
    25  	// For X25519, this performs ECDH as specified in RFC 7748, Section 6.1. If
    26  	// the result is the all-zero value, ECDH returns an error.
    27  	ECDH(local *PrivateKey, remote *PublicKey) ([]byte, error)
    28  
    29  	// GenerateKey generates a new PrivateKey from rand.
    30  	GenerateKey(rand io.Reader) (*PrivateKey, error)
    31  
    32  	// NewPrivateKey checks that key is valid and returns a PrivateKey.
    33  	//
    34  	// For NIST curves, this follows SEC 1, Version 2.0, Section 2.3.6, which
    35  	// amounts to decoding the bytes as a fixed length big endian integer and
    36  	// checking that the result is lower than the order of the curve. The zero
    37  	// private key is also rejected, as the encoding of the corresponding public
    38  	// key would be irregular.
    39  	//
    40  	// For X25519, this only checks the scalar length. Adversarially selected
    41  	// private keys can cause ECDH to return an error.
    42  	NewPrivateKey(key []byte) (*PrivateKey, error)
    43  
    44  	// NewPublicKey checks that key is valid and returns a PublicKey.
    45  	//
    46  	// For NIST curves, this decodes an uncompressed point according to SEC 1,
    47  	// Version 2.0, Section 2.3.4. Compressed encodings and the point at
    48  	// infinity are rejected.
    49  	//
    50  	// For X25519, this only checks the u-coordinate length. Adversarially
    51  	// selected public keys can cause ECDH to return an error.
    52  	NewPublicKey(key []byte) (*PublicKey, error)
    53  
    54  	// privateKeyToPublicKey converts a PrivateKey to a PublicKey. It's exposed
    55  	// as the PrivateKey.PublicKey method.
    56  	//
    57  	// This method always succeeds: for X25519, it might output the all-zeroes
    58  	// value (unlike the ECDH method); for NIST curves, it would only fail for
    59  	// the zero private key, which is rejected by NewPrivateKey.
    60  	//
    61  	// The private method also allow us to expand the ECDH interface with more
    62  	// methods in the future without breaking backwards compatibility.
    63  	privateKeyToPublicKey(*PrivateKey) *PublicKey
    64  }
    65  
    66  // PublicKey is an ECDH public key, usually a peer's ECDH share sent over the wire.
    67  type PublicKey struct {
    68  	curve     Curve
    69  	publicKey []byte
    70  }
    71  
    72  // Bytes returns a copy of the encoding of the public key.
    73  func (k *PublicKey) Bytes() []byte {
    74  	// Copy the public key to a fixed size buffer that can get allocated on the
    75  	// caller's stack after inlining.
    76  	var buf [133]byte
    77  	return append(buf[:0], k.publicKey...)
    78  }
    79  
    80  // Equal returns whether x represents the same public key as k.
    81  //
    82  // Note that there can be equivalent public keys with different encodings which
    83  // would return false from this check but behave the same way as inputs to ECDH.
    84  //
    85  // This check is performed in constant time as long as the key types and their
    86  // curve match.
    87  func (k *PublicKey) Equal(x crypto.PublicKey) bool {
    88  	xx, ok := x.(*PublicKey)
    89  	if !ok {
    90  		return false
    91  	}
    92  	return k.curve == xx.curve &&
    93  		subtle.ConstantTimeCompare(k.publicKey, xx.publicKey) == 1
    94  }
    95  
    96  func (k *PublicKey) Curve() Curve {
    97  	return k.curve
    98  }
    99  
   100  // PrivateKey is an ECDH private key, usually kept secret.
   101  type PrivateKey struct {
   102  	curve      Curve
   103  	privateKey []byte
   104  	// publicKey is set under publicKeyOnce, to allow loading private keys with
   105  	// NewPrivateKey without having to perform a scalar multiplication.
   106  	publicKey     *PublicKey
   107  	publicKeyOnce sync.Once
   108  }
   109  
   110  // Bytes returns a copy of the encoding of the private key.
   111  func (k *PrivateKey) Bytes() []byte {
   112  	// Copy the private key to a fixed size buffer that can get allocated on the
   113  	// caller's stack after inlining.
   114  	var buf [66]byte
   115  	return append(buf[:0], k.privateKey...)
   116  }
   117  
   118  // Equal returns whether x represents the same private key as k.
   119  //
   120  // Note that there can be equivalent private keys with different encodings which
   121  // would return false from this check but behave the same way as inputs to ECDH.
   122  //
   123  // This check is performed in constant time as long as the key types and their
   124  // curve match.
   125  func (k *PrivateKey) Equal(x crypto.PrivateKey) bool {
   126  	xx, ok := x.(*PrivateKey)
   127  	if !ok {
   128  		return false
   129  	}
   130  	return k.curve == xx.curve &&
   131  		subtle.ConstantTimeCompare(k.privateKey, xx.privateKey) == 1
   132  }
   133  
   134  func (k *PrivateKey) Curve() Curve {
   135  	return k.curve
   136  }
   137  
   138  func (k *PrivateKey) PublicKey() *PublicKey {
   139  	k.publicKeyOnce.Do(func() {
   140  		k.publicKey = k.curve.privateKeyToPublicKey(k)
   141  	})
   142  	return k.publicKey
   143  }
   144  
   145  // Public implements the implicit interface of all standard library private
   146  // keys. See the docs of crypto.PrivateKey.
   147  func (k *PrivateKey) Public() crypto.PublicKey {
   148  	return k.PublicKey()
   149  }