github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/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/internal/boring" 12 "crypto/subtle" 13 "errors" 14 "io" 15 "sync" 16 ) 17 18 type Curve interface { 19 // GenerateKey generates a new PrivateKey from rand. 20 GenerateKey(rand io.Reader) (*PrivateKey, error) 21 22 // NewPrivateKey checks that key is valid and returns a PrivateKey. 23 // 24 // For NIST curves, this follows SEC 1, Version 2.0, Section 2.3.6, which 25 // amounts to decoding the bytes as a fixed length big endian integer and 26 // checking that the result is lower than the order of the curve. The zero 27 // private key is also rejected, as the encoding of the corresponding public 28 // key would be irregular. 29 // 30 // For X25519, this only checks the scalar length. 31 NewPrivateKey(key []byte) (*PrivateKey, error) 32 33 // NewPublicKey checks that key is valid and returns a PublicKey. 34 // 35 // For NIST curves, this decodes an uncompressed point according to SEC 1, 36 // Version 2.0, Section 2.3.4. Compressed encodings and the point at 37 // infinity are rejected. 38 // 39 // For X25519, this only checks the u-coordinate length. Adversarially 40 // selected public keys can cause ECDH to return an error. 41 NewPublicKey(key []byte) (*PublicKey, error) 42 43 // ecdh performs a ECDH exchange and returns the shared secret. It's exposed 44 // as the PrivateKey.ECDH method. 45 // 46 // The private method also allow us to expand the ECDH interface with more 47 // methods in the future without breaking backwards compatibility. 48 ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) 49 50 // privateKeyToPublicKey converts a PrivateKey to a PublicKey. It's exposed 51 // as the PrivateKey.PublicKey method. 52 // 53 // This method always succeeds: for X25519, the zero key can't be 54 // constructed due to clamping; for NIST curves, it is rejected by 55 // NewPrivateKey. 56 privateKeyToPublicKey(*PrivateKey) *PublicKey 57 } 58 59 // PublicKey is an ECDH public key, usually a peer's ECDH share sent over the wire. 60 // 61 // These keys can be parsed with [crypto/x509.ParsePKIXPublicKey] and encoded 62 // with [crypto/x509.MarshalPKIXPublicKey]. For NIST curves, they then need to 63 // be converted with [crypto/ecdsa.PublicKey.ECDH] after parsing. 64 type PublicKey struct { 65 curve Curve 66 publicKey []byte 67 boring *boring.PublicKeyECDH 68 } 69 70 // Bytes returns a copy of the encoding of the public key. 71 func (k *PublicKey) Bytes() []byte { 72 // Copy the public key to a fixed size buffer that can get allocated on the 73 // caller's stack after inlining. 74 var buf [133]byte 75 return append(buf[:0], k.publicKey...) 76 } 77 78 // Equal returns whether x represents the same public key as k. 79 // 80 // Note that there can be equivalent public keys with different encodings which 81 // would return false from this check but behave the same way as inputs to ECDH. 82 // 83 // This check is performed in constant time as long as the key types and their 84 // curve match. 85 func (k *PublicKey) Equal(x crypto.PublicKey) bool { 86 xx, ok := x.(*PublicKey) 87 if !ok { 88 return false 89 } 90 return k.curve == xx.curve && 91 subtle.ConstantTimeCompare(k.publicKey, xx.publicKey) == 1 92 } 93 94 func (k *PublicKey) Curve() Curve { 95 return k.curve 96 } 97 98 // PrivateKey is an ECDH private key, usually kept secret. 99 // 100 // These keys can be parsed with [crypto/x509.ParsePKCS8PrivateKey] and encoded 101 // with [crypto/x509.MarshalPKCS8PrivateKey]. For NIST curves, they then need to 102 // be converted with [crypto/ecdsa.PrivateKey.ECDH] after parsing. 103 type PrivateKey struct { 104 curve Curve 105 privateKey []byte 106 boring *boring.PrivateKeyECDH 107 // publicKey is set under publicKeyOnce, to allow loading private keys with 108 // NewPrivateKey without having to perform a scalar multiplication. 109 publicKey *PublicKey 110 publicKeyOnce sync.Once 111 } 112 113 // ECDH performs a ECDH exchange and returns the shared secret. The PrivateKey 114 // and PublicKey must use the same curve. 115 // 116 // For NIST curves, this performs ECDH as specified in SEC 1, Version 2.0, 117 // Section 3.3.1, and returns the x-coordinate encoded according to SEC 1, 118 // Version 2.0, Section 2.3.5. The result is never the point at infinity. 119 // 120 // For X25519, this performs ECDH as specified in RFC 7748, Section 6.1. If 121 // the result is the all-zero value, ECDH returns an error. 122 func (k *PrivateKey) ECDH(remote *PublicKey) ([]byte, error) { 123 if k.curve != remote.curve { 124 return nil, errors.New("crypto/ecdh: private key and public key curves do not match") 125 } 126 return k.curve.ecdh(k, remote) 127 } 128 129 // Bytes returns a copy of the encoding of the private key. 130 func (k *PrivateKey) Bytes() []byte { 131 // Copy the private key to a fixed size buffer that can get allocated on the 132 // caller's stack after inlining. 133 var buf [66]byte 134 return append(buf[:0], k.privateKey...) 135 } 136 137 // Equal returns whether x represents the same private key as k. 138 // 139 // Note that there can be equivalent private keys with different encodings which 140 // would return false from this check but behave the same way as inputs to ECDH. 141 // 142 // This check is performed in constant time as long as the key types and their 143 // curve match. 144 func (k *PrivateKey) Equal(x crypto.PrivateKey) bool { 145 xx, ok := x.(*PrivateKey) 146 if !ok { 147 return false 148 } 149 return k.curve == xx.curve && 150 subtle.ConstantTimeCompare(k.privateKey, xx.privateKey) == 1 151 } 152 153 func (k *PrivateKey) Curve() Curve { 154 return k.curve 155 } 156 157 func (k *PrivateKey) PublicKey() *PublicKey { 158 k.publicKeyOnce.Do(func() { 159 if k.boring != nil { 160 // Because we already checked in NewPrivateKey that the key is valid, 161 // there should not be any possible errors from BoringCrypto, 162 // so we turn the error into a panic. 163 // (We can't return it anyhow.) 164 kpub, err := k.boring.PublicKey() 165 if err != nil { 166 panic("boringcrypto: " + err.Error()) 167 } 168 k.publicKey = &PublicKey{ 169 curve: k.curve, 170 publicKey: kpub.Bytes(), 171 boring: kpub, 172 } 173 } else { 174 k.publicKey = k.curve.privateKeyToPublicKey(k) 175 } 176 }) 177 return k.publicKey 178 } 179 180 // Public implements the implicit interface of all standard library private 181 // keys. See the docs of crypto.PrivateKey. 182 func (k *PrivateKey) Public() crypto.PublicKey { 183 return k.PublicKey() 184 }