Source File
ecdh.go
Belonging Package
crypto/ecdh
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package ecdh implements Elliptic Curve Diffie-Hellman over
// NIST curves and Curve25519.
package ecdh
import (
)
type Curve interface {
// GenerateKey generates a random PrivateKey.
//
// Most applications should use [crypto/rand.Reader] as rand. Note that the
// returned key does not depend deterministically on the bytes read from rand,
// and may change between calls and/or between versions.
GenerateKey(rand io.Reader) (*PrivateKey, error)
// NewPrivateKey checks that key is valid and returns a PrivateKey.
//
// For NIST curves, this follows SEC 1, Version 2.0, Section 2.3.6, which
// amounts to decoding the bytes as a fixed length big endian integer and
// checking that the result is lower than the order of the curve. The zero
// private key is also rejected, as the encoding of the corresponding public
// key would be irregular.
//
// For X25519, this only checks the scalar length.
NewPrivateKey(key []byte) (*PrivateKey, error)
// NewPublicKey checks that key is valid and returns a PublicKey.
//
// For NIST curves, this decodes an uncompressed point according to SEC 1,
// Version 2.0, Section 2.3.4. Compressed encodings and the point at
// infinity are rejected.
//
// For X25519, this only checks the u-coordinate length. Adversarially
// selected public keys can cause ECDH to return an error.
NewPublicKey(key []byte) (*PublicKey, error)
// ecdh performs an ECDH exchange and returns the shared secret. It's exposed
// as the PrivateKey.ECDH method.
//
// The private method also allow us to expand the ECDH interface with more
// methods in the future without breaking backwards compatibility.
ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error)
// privateKeyToPublicKey converts a PrivateKey to a PublicKey. It's exposed
// as the PrivateKey.PublicKey method.
//
// This method always succeeds: for X25519, the zero key can't be
// constructed due to clamping; for NIST curves, it is rejected by
// NewPrivateKey.
privateKeyToPublicKey(*PrivateKey) *PublicKey
}
// PublicKey is an ECDH public key, usually a peer's ECDH share sent over the wire.
//
// These keys can be parsed with [crypto/x509.ParsePKIXPublicKey] and encoded
// with [crypto/x509.MarshalPKIXPublicKey]. For NIST curves, they then need to
// be converted with [crypto/ecdsa.PublicKey.ECDH] after parsing.
type PublicKey struct {
curve Curve
publicKey []byte
boring *boring.PublicKeyECDH
}
// Bytes returns a copy of the encoding of the public key.
func ( *PublicKey) () []byte {
// Copy the public key to a fixed size buffer that can get allocated on the
// caller's stack after inlining.
var [133]byte
return append([:0], .publicKey...)
}
// Equal returns whether x represents the same public key as k.
//
// Note that there can be equivalent public keys with different encodings which
// would return false from this check but behave the same way as inputs to ECDH.
//
// This check is performed in constant time as long as the key types and their
// curve match.
func ( *PublicKey) ( crypto.PublicKey) bool {
, := .(*PublicKey)
if ! {
return false
}
return .curve == .curve &&
subtle.ConstantTimeCompare(.publicKey, .publicKey) == 1
}
func ( *PublicKey) () Curve {
return .curve
}
// PrivateKey is an ECDH private key, usually kept secret.
//
// These keys can be parsed with [crypto/x509.ParsePKCS8PrivateKey] and encoded
// with [crypto/x509.MarshalPKCS8PrivateKey]. For NIST curves, they then need to
// be converted with [crypto/ecdsa.PrivateKey.ECDH] after parsing.
type PrivateKey struct {
curve Curve
privateKey []byte
boring *boring.PrivateKeyECDH
// publicKey is set under publicKeyOnce, to allow loading private keys with
// NewPrivateKey without having to perform a scalar multiplication.
publicKey *PublicKey
publicKeyOnce sync.Once
}
// ECDH performs an ECDH exchange and returns the shared secret. The [PrivateKey]
// and [PublicKey] must use the same curve.
//
// For NIST curves, this performs ECDH as specified in SEC 1, Version 2.0,
// Section 3.3.1, and returns the x-coordinate encoded according to SEC 1,
// Version 2.0, Section 2.3.5. The result is never the point at infinity.
//
// For [X25519], this performs ECDH as specified in RFC 7748, Section 6.1. If
// the result is the all-zero value, ECDH returns an error.
func ( *PrivateKey) ( *PublicKey) ([]byte, error) {
if .curve != .curve {
return nil, errors.New("crypto/ecdh: private key and public key curves do not match")
}
return .curve.ecdh(, )
}
// Bytes returns a copy of the encoding of the private key.
func ( *PrivateKey) () []byte {
// Copy the private key to a fixed size buffer that can get allocated on the
// caller's stack after inlining.
var [66]byte
return append([:0], .privateKey...)
}
// Equal returns whether x represents the same private key as k.
//
// Note that there can be equivalent private keys with different encodings which
// would return false from this check but behave the same way as inputs to [ECDH].
//
// This check is performed in constant time as long as the key types and their
// curve match.
func ( *PrivateKey) ( crypto.PrivateKey) bool {
, := .(*PrivateKey)
if ! {
return false
}
return .curve == .curve &&
subtle.ConstantTimeCompare(.privateKey, .privateKey) == 1
}
func ( *PrivateKey) () Curve {
return .curve
}
func ( *PrivateKey) () *PublicKey {
.publicKeyOnce.Do(func() {
if .boring != nil {
// Because we already checked in NewPrivateKey that the key is valid,
// there should not be any possible errors from BoringCrypto,
// so we turn the error into a panic.
// (We can't return it anyhow.)
, := .boring.PublicKey()
if != nil {
panic("boringcrypto: " + .Error())
}
.publicKey = &PublicKey{
curve: .curve,
publicKey: .Bytes(),
boring: ,
}
} else {
.publicKey = .curve.privateKeyToPublicKey()
}
})
return .publicKey
}
// Public implements the implicit interface of all standard library private
// keys. See the docs of [crypto.PrivateKey].
func ( *PrivateKey) () crypto.PublicKey {
return .PublicKey()
}
The pages are generated with Golds v0.7.0-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |