Skip to content

proposal: crypto/ecdh: allow external curve and key implementations #69863

@MagicalTux

Description

@MagicalTux

Proposal Details

At this point this is more a number of thoughts and description of issues I've encountered trying to work with crypto/ecdh rather than a proposal to change things in a specific way. crypto/ecdh is used by a lot of people, so breaking changes are out of the picture unless maybe if a /v2 version is created, but I am not sure this is warranted or even qualifies.

My goal here is first to start a discussion.

Golang's crypto package is nice because objects like crypto.PrivateKey are interfaces that allows both the use of local secrets managed via the standard libraries, or hardware encryption where secrets aren't stored on the machine at all.

It seems that this was a goal, as crypto/ecdh.Curve is an interface that could be implemented by a third party package, for the exception that it has private functions and it is impossible to implement NewPrivateKey or NewPublicKey because both are opaque objects.

Ideally both ecdh.PublicKey and ecdh.PrivateKey would be interfaces, however now that the package is widely used it is not possible to change that without causing a lot of breakage.

An alternative would be to have a method to create private/public key objects by specifying the data (bytes) and curve interface, and making the private elements of the curve interface public. Actually it would be better if the private key data could be an interface for the private key, as in the case of a tpm it would be a Handle, and in some cases libraries may prefer keeping track of specific values for performance.

Point is, the ecdh interface as it exists is very nice. Creating an ephemeral private key to encode a message to a recipient is as easy as recipient.Curve().GenerateKey(rand.Reader), it's a shame however that it is not possible to implement other curves.

Current library has a nice API, the part about PrivateKey can actually be worked around fairly easily as long as the curve is one supported by crypto/ecdh. Working with other curves however is proving to be extremely difficult, dirty alternatives include things like implementing GenerateKey directly on the public key object that returns not a *ecdh.PrivateKey but a custom object that simply implements the minimum required.

Some suggestions here:

type PrivateKeyInterface interface {
    Curve() Curve
    ECDH(remote *PublicKey) ([]byte, error)
    Equal(x crypto.PrivateKey) bool
    Public() crypto.PublicKey
}

type GenericCurve interface {
    // Using a different name so that to not break existing Curve
    GeneratePrivateKey(rand io.Reader) (PrivateKeyInterface, error)

    // The current ecdh package does not expose the following methods, making these public would allow custom implementations so I'm curious for the more specific reason than "breaking backward compatibility" for an interface that cannot be implemented externally anyway
    ECDH(local *PrivateKey, remote *PublicKey) ([]byte, error)
    PrivateKeyToPublicKey(PrivateKeyInterface) *PublicKey
}

// NewPublicKey would simply return a public key object
func NewPublicKey(c Curve, data []byte) *PublicKey

// This could be nice to allow custom curve objects to be marshalable, and maybe parsable if there is some method to register a type
type X509Marshalable interface {
    GetOID() pkix.AlgorithmIdentifier
    Bytes() []byte // current name in ecdh
}

More curves are being requested, and being able to extend things without the need for users of crypto/ecdh to think too much about makes sense I believe.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ProposalProposal-CryptoProposal related to crypto packages or other security issues

    Type

    No type

    Projects

    Status

    Incoming

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions