diff --git a/README.md b/README.md index 7193251..b066241 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ [![Godoc Reference](https://godoc.org/github.com/hurae/ecdh?status.svg)](https://godoc.org/github.com/hurae/ecdh) -[![Build Status](https://travis-ci.org/hurae/ecdh.svg?branch=master)](https://travis-ci.org/hurae/ecdh) + +Fork of `github.com/aead/ecdh` ## The ECDH key exchange @@ -11,9 +12,12 @@ This package implements a generic interface for ECDH and supports the generic [c and the [x/crypto/curve25519](https://godoc.org/golang.org/x/crypto/curve25519) out of the box. ### Installation -Install in your GOPATH: `go get -u github.com/hurae/ecdh` +Install in your GOPATH: `go get -u github.com/hurae/ecdh` +### Difference: -Fork of `github.com/aead/ecdh`, I’d like to have a version that always return a []byte type public key. -Also, I'd like to use non-deprecated new X25519 API. \ No newline at end of file +- always return a []byte type public key +- use non-deprecated new X25519 API. +- implement Check for Curve25519, just the same check inside golang.org/x/crypto/curve25519. That means length 32 and not all zero. +- ComputeSecret will now pass the error which golang.org/x/crypto/curve25519 gives out. \ No newline at end of file diff --git a/curve25519.go b/curve25519.go index 82842a7..75b08d3 100644 --- a/curve25519.go +++ b/curve25519.go @@ -1,3 +1,5 @@ +// Copyright (c) 2020 Andreas huraway. All rights reserved. +// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. @@ -5,13 +7,17 @@ package ecdh import ( "crypto/rand" + "crypto/subtle" + "errors" + "fmt" "golang.org/x/crypto/curve25519" "io" - "log" ) type ecdh25519 struct{} +var zero [32]byte + var curve25519Params = CurveParams{ Name: "Curve25519", BitSize: 255, @@ -57,18 +63,22 @@ func (ecdh25519) PublicKey(private []byte) (public []byte) { return pub } -func (ecdh25519) Check([]byte) (err error) { +func (ecdh25519) Check(publicKey []byte) (err error) { + if l := len(publicKey); l != 32 { + return fmt.Errorf("bad point length: %d, expected %d", l, 32) + } + if subtle.ConstantTimeCompare(publicKey, zero[:]) == 1 { + return errors.New("bad input point: low order point") + } return nil } -func (ecdh25519) ComputeSecret(private []byte, peersPublic []byte) (secret []byte) { - var err error - +func (ecdh25519) ComputeSecret(private []byte, peersPublic []byte) (secret []byte, err error) { //curve25519.ScalarMult(&sec, &pri, &pub) secret, err = curve25519.X25519(private, peersPublic) if err != nil { - log.Fatal(err) + return secret, err } - return secret + return secret, nil } diff --git a/ecdh.go b/ecdh.go index 9ad3a5c..11a5182 100644 --- a/ecdh.go +++ b/ecdh.go @@ -1,3 +1,5 @@ +// Copyright (c) 2020 Andreas huraway. All rights reserved. +// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. @@ -29,14 +31,14 @@ type KeyExchange interface { // Check returns a non-nil error if the peers public key cannot used for the // key exchange - for instance the public key isn't a point on the elliptic curve. - // Only implemented for NIST curves. Curve25519 didn't provide such function. - // Actually, Curve25519 do not need this check. See https://cr.yp.to/ecdh.html. + // Generally, Curve25519 do not need this check, but an all zero key or nil key is not permitted. + // See https://cr.yp.to/ecdh.html for more detail about Curve25519. // It's recommended to check peer's public key before computing the secret. Check(peersPublic []byte) (err error) // ComputeSecret returns the secret value computed from the given private key // and the peers public key. - ComputeSecret(private []byte, peersPublic []byte) (secret []byte) + ComputeSecret(private []byte, peersPublic []byte) (secret []byte, err error) } // CurveParams contains the parameters of an elliptic curve. diff --git a/ecdh_test.go b/ecdh_test.go index 7309055..ecfa1c1 100644 --- a/ecdh_test.go +++ b/ecdh_test.go @@ -1,3 +1,5 @@ +// Copyright (c) 2020 Andreas huraway. All rights reserved. +// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. @@ -29,12 +31,12 @@ func ExampleGeneric() { if err := p256.Check(publicBob); err != nil { fmt.Printf("Bob's public key is not on the curve: %s\n", err) } - secretAlice := p256.ComputeSecret(privateAlice, publicBob) + secretAlice, _ := p256.ComputeSecret(privateAlice, publicBob) if err := p256.Check(publicAlice); err != nil { fmt.Printf("Alice's public key is not on the curve: %s\n", err) } - secretBob := p256.ComputeSecret(privateBob, publicAlice) + secretBob, _ := p256.ComputeSecret(privateBob, publicAlice) if !bytes.Equal(secretAlice, secretBob) { fmt.Printf("key exchange failed - secret X coordinates not equal\n") @@ -54,16 +56,17 @@ func ExampleX25519() { if err != nil { fmt.Printf("Failed to generate Bob's private/public key pair: %s\n", err) } - if err := c25519.Check(publicBob); err != nil { fmt.Printf("Bob's public key is not on the curve: %s\n", err) } - secretAlice := c25519.ComputeSecret(privateAlice, publicBob) - + secretAlice, err := c25519.ComputeSecret(privateAlice, publicBob) + if err != nil { + fmt.Println("Failed to Compute secret for the key", err) + } if err := c25519.Check(publicAlice); err != nil { fmt.Printf("Alice's public key is not on the curve: %s\n", err) } - secretBob := c25519.ComputeSecret(privateBob, publicAlice) + secretBob, err := c25519.ComputeSecret(privateBob, publicAlice) if !bytes.Equal(secretAlice, secretBob) { fmt.Printf("key exchange failed - secret X coordinates not equal\n") @@ -94,8 +97,8 @@ func TestX25519(t *testing.T) { } pubBob := dh.PublicKey(priBob) - secAlice := dh.ComputeSecret(priAlice, pubBob) - secBob := dh.ComputeSecret(priBob, pubAlice) + secAlice, _ := dh.ComputeSecret(priAlice, pubBob) + secBob, _ := dh.ComputeSecret(priBob, pubAlice) if !bytes.Equal(secAlice, secBob) { toStr := hex.EncodeToString @@ -123,7 +126,7 @@ func BenchmarkX25519(b *testing.B) { } b.ResetTimer() for i := 0; i < b.N; i++ { - curve.ComputeSecret(privateAlice, publicBob) + _, _ = curve.ComputeSecret(privateAlice, publicBob) } } @@ -150,7 +153,7 @@ func BenchmarkP256(b *testing.B) { } b.ResetTimer() for i := 0; i < b.N; i++ { - p256.ComputeSecret(privateAlice, publicBob) + _, _ = p256.ComputeSecret(privateAlice, publicBob) } } diff --git a/generic.go b/generic.go index 53eaf82..3830648 100644 --- a/generic.go +++ b/generic.go @@ -1,3 +1,5 @@ +// Copyright (c) 2020 Andreas huraway. All rights reserved. +// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. @@ -63,9 +65,9 @@ func (g genericCurve) Check(peersPublic []byte) (err error) { return } -func (g genericCurve) ComputeSecret(private []byte, peersPublic []byte) (secret []byte) { +func (g genericCurve) ComputeSecret(private []byte, peersPublic []byte) (secret []byte, _ error) { x, y := elliptic.Unmarshal(g.curve, peersPublic) sX, _ := g.curve.ScalarMult(x, y, private) secret = sX.Bytes() - return + return secret, nil }