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