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 // Most applications should use [crypto/rand.Reader] as rand. Note that the
22 // returned key does not depend deterministically on the bytes read from rand,
23 // and may change between calls and/or between versions.
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 // PrivateKey is an ECDH private key, usually kept secret.
96 //
97 // These keys can be parsed with [crypto/x509.ParsePKCS8PrivateKey] and encoded
98 // with [crypto/x509.MarshalPKCS8PrivateKey]. For NIST curves, they then need to
99 // be converted with [crypto/ecdsa.PrivateKey.ECDH] after parsing.
100 type PrivateKey struct {
101 curve Curve
102 privateKey []byte
103 publicKey *PublicKey
104 boring *boring.PrivateKeyECDH
105 fips *ecdh.PrivateKey
106 }
107 108 // ECDH performs an ECDH exchange and returns the shared secret. The [PrivateKey]
109 // and [PublicKey] must use the same curve.
110 //
111 // For NIST curves, this performs ECDH as specified in SEC 1, Version 2.0,
112 // Section 3.3.1, and returns the x-coordinate encoded according to SEC 1,
113 // Version 2.0, Section 2.3.5. The result is never the point at infinity.
114 // This is also known as the Shared Secret Computation of the Ephemeral Unified
115 // Model scheme specified in NIST SP 800-56A Rev. 3, Section 6.1.2.2.
116 //
117 // For [X25519], this performs ECDH as specified in RFC 7748, Section 6.1. If
118 // the result is the all-zero value, ECDH returns an error.
119 func (k *PrivateKey) ECDH(remote *PublicKey) ([]byte, error) {
120 if k.curve != remote.curve {
121 return nil, errors.New("crypto/ecdh: private key and public key curves do not match")
122 }
123 return k.curve.ecdh(k, remote)
124 }
125 126 // Bytes returns a copy of the encoding of the private key.
127 func (k *PrivateKey) Bytes() []byte {
128 // Copy the private key to a fixed size buffer that can get allocated on the
129 // caller's stack after inlining.
130 var buf [66]byte
131 return append(buf[:0], k.privateKey...)
132 }
133 134 // Equal returns whether x represents the same private key as k.
135 //
136 // Note that there can be equivalent private keys with different encodings which
137 // would return false from this check but behave the same way as inputs to [ECDH].
138 //
139 // This check is performed in constant time as long as the key types and their
140 // curve match.
141 func (k *PrivateKey) Equal(x crypto.PrivateKey) bool {
142 xx, ok := x.(*PrivateKey)
143 if !ok {
144 return false
145 }
146 return k.curve == xx.curve &&
147 subtle.ConstantTimeCompare(k.privateKey, xx.privateKey) == 1
148 }
149 150 func (k *PrivateKey) Curve() Curve {
151 return k.curve
152 }
153 154 func (k *PrivateKey) PublicKey() *PublicKey {
155 return k.publicKey
156 }
157 158 // Public implements the implicit interface of all standard library private
159 // keys. See the docs of [crypto.PrivateKey].
160 func (k *PrivateKey) Public() crypto.PublicKey {
161 return k.PublicKey()
162 }
163