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 }