Skip to content
This repository has been archived by the owner on Dec 7, 2019. It is now read-only.

Added ECDSA; Added RSA tests; Fixed linting errors; Handling all un-handled errors #35

Merged
merged 1 commit into from
Sep 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.DS_Store

# vim
.swp
*~
*.swp
*.swo
186 changes: 186 additions & 0 deletions ecdsa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package crypto

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"encoding/asn1"
"errors"
"io"
"math/big"

pb "github.com/libp2p/go-libp2p-crypto/pb"

sha256 "github.com/minio/sha256-simd"
)

// ECDSAPrivateKey is an implementation of an ECDSA private key
type ECDSAPrivateKey struct {
priv *ecdsa.PrivateKey
}

// ECDSAPublicKey is an implementation of an ECDSA public key
type ECDSAPublicKey struct {
pub *ecdsa.PublicKey
}

// ECDSASig holds the r and s values of an ECDSA signature
type ECDSASig struct {
R, S *big.Int
}

var (
// ErrNotECDSAPubKey is returned when the public key passed is not an ecdsa public key
ErrNotECDSAPubKey = errors.New("not an ecdsa public key")
// ErrNilSig is returned when the signature is nil
ErrNilSig = errors.New("sig is nil")
// ErrNilPrivateKey is returned when a nil private key is provided
ErrNilPrivateKey = errors.New("private key is nil")
// ECDSACurve is the default ecdsa curve used
ECDSACurve = elliptic.P256()
)

// GenerateECDSAKeyPair generates a new ecdsa private and public key
func GenerateECDSAKeyPair(src io.Reader) (PrivKey, PubKey, error) {
return GenerateECDSAKeyPairWithCurve(ECDSACurve, src)
}

// GenerateECDSAKeyPairWithCurve generates a new ecdsa private and public key with a speicified curve
func GenerateECDSAKeyPairWithCurve(curve elliptic.Curve, src io.Reader) (PrivKey, PubKey, error) {
priv, err := ecdsa.GenerateKey(curve, src)
if err != nil {
return nil, nil, err
}

return &ECDSAPrivateKey{priv}, &ECDSAPublicKey{&priv.PublicKey}, nil
}

// ECDSAKeyPairFromKey generates a new ecdsa private and public key from an input private key
func ECDSAKeyPairFromKey(priv *ecdsa.PrivateKey) (PrivKey, PubKey, error) {
if priv == nil {
return nil, nil, ErrNilPrivateKey
}

return &ECDSAPrivateKey{priv}, &ECDSAPublicKey{&priv.PublicKey}, nil
}

// MarshalECDSAPrivateKey returns x509 bytes from a private key
func MarshalECDSAPrivateKey(ePriv ECDSAPrivateKey) ([]byte, error) {
return x509.MarshalECPrivateKey(ePriv.priv)
}

// MarshalECDSAPublicKey returns x509 bytes from a public key
func MarshalECDSAPublicKey(ePub ECDSAPublicKey) ([]byte, error) {
return x509.MarshalPKIXPublicKey(ePub.pub)
}

// UnmarshalECDSAPrivateKey returns a private key from x509 bytes
func UnmarshalECDSAPrivateKey(data []byte) (PrivKey, error) {
priv, err := x509.ParseECPrivateKey(data)
if err != nil {
return nil, err
}

return &ECDSAPrivateKey{priv}, nil
}

// UnmarshalECDSAPublicKey returns the public key from x509 bytes
func UnmarshalECDSAPublicKey(data []byte) (PubKey, error) {
pubIfc, err := x509.ParsePKIXPublicKey(data)
if err != nil {
return nil, err
}

pub, ok := pubIfc.(*ecdsa.PublicKey)
if !ok {
return nil, ErrNotECDSAPubKey
}

return &ECDSAPublicKey{pub}, nil
}

// Bytes returns the private key as protobuf bytes
func (ePriv *ECDSAPrivateKey) Bytes() ([]byte, error) {
return MarshalPrivateKey(ePriv)
}

// Type returns the key type
func (ePriv *ECDSAPrivateKey) Type() pb.KeyType {
return pb.KeyType_ECDSA
}

// Raw returns x509 bytes from a private key
func (ePriv *ECDSAPrivateKey) Raw() ([]byte, error) {
return x509.MarshalECPrivateKey(ePriv.priv)
}

// Equals compares to private keys
func (ePriv *ECDSAPrivateKey) Equals(o Key) bool {
oPriv, ok := o.(*ECDSAPrivateKey)
if !ok {
return false
}

return ePriv.priv.D.Cmp(oPriv.priv.D) == 0
}

// Sign returns the signature of the input data
func (ePriv *ECDSAPrivateKey) Sign(data []byte) ([]byte, error) {
hash := sha256.Sum256(data)
r, s, err := ecdsa.Sign(rand.Reader, ePriv.priv, hash[:])
if err != nil {
return nil, err
}

return asn1.Marshal(ECDSASig{
R: r,
S: s,
})
}

// GetPublic returns a public key
func (ePriv *ECDSAPrivateKey) GetPublic() PubKey {
return &ECDSAPublicKey{&ePriv.priv.PublicKey}
}

// Bytes returns the public key as protobuf bytes
func (ePub *ECDSAPublicKey) Bytes() ([]byte, error) {
return MarshalPublicKey(ePub)
}

// Type returns the key type
func (ePub *ECDSAPublicKey) Type() pb.KeyType {
return pb.KeyType_ECDSA
}

// Raw returns x509 bytes from a public key
func (ePub ECDSAPublicKey) Raw() ([]byte, error) {
return x509.MarshalPKIXPublicKey(ePub.pub)
}

// Equals compares to public keys
func (ePub *ECDSAPublicKey) Equals(o Key) bool {
oPub, ok := o.(*ECDSAPublicKey)
if !ok {
return false
}

return ePub.pub.X != nil && ePub.pub.Y != nil && oPub.pub.X != nil && oPub.pub.Y != nil &&
0 == ePub.pub.X.Cmp(oPub.pub.X) && 0 == ePub.pub.Y.Cmp(oPub.pub.Y)
}

// Verify compares data to a signature
func (ePub *ECDSAPublicKey) Verify(data, sigBytes []byte) (bool, error) {
sig := new(ECDSASig)
if _, err := asn1.Unmarshal(sigBytes, sig); err != nil {
return false, err
}
if sig == nil {
return false, ErrNilSig
}

hash := sha256.Sum256(data)

return ecdsa.Verify(ePub.pub, hash[:], sig.R, sig.S), nil
}
96 changes: 96 additions & 0 deletions ecdsa_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package crypto

import (
"crypto/rand"
"testing"
)

func TestECDSABasicSignAndVerify(t *testing.T) {
priv, pub, err := GenerateECDSAKeyPair(rand.Reader)
if err != nil {
t.Fatal(err)
}

data := []byte("hello! and welcome to some awesome crypto primitives")

sig, err := priv.Sign(data)
if err != nil {
t.Fatal(err)
}

ok, err := pub.Verify(data, sig)
if err != nil {
t.Fatal(err)
}

if !ok {
t.Fatal("signature didnt match")
}

// change data
data[0] = ^data[0]
ok, err = pub.Verify(data, sig)
if err != nil {
t.Fatal(err)
}

if ok {
t.Fatal("signature matched and shouldn't")
}
}

func TestECDSASignZero(t *testing.T) {
priv, pub, err := GenerateECDSAKeyPair(rand.Reader)
if err != nil {
t.Fatal(err)
}

data := make([]byte, 0)
sig, err := priv.Sign(data)
if err != nil {
t.Fatal(err)
}

ok, err := pub.Verify(data, sig)
if err != nil {
t.Fatal(err)
}
if !ok {
t.Fatal("signature didn't match")
}
}

func TestECDSAMarshalLoop(t *testing.T) {
priv, pub, err := GenerateECDSAKeyPair(rand.Reader)
if err != nil {
t.Fatal(err)
}

privB, err := priv.Bytes()
if err != nil {
t.Fatal(err)
}

privNew, err := UnmarshalPrivateKey(privB)
if err != nil {
t.Fatal(err)
}

if !priv.Equals(privNew) || !privNew.Equals(priv) {
t.Fatal("keys are not equal")
}

pubB, err := pub.Bytes()
if err != nil {
t.Fatal(err)
}
pubNew, err := UnmarshalPublicKey(pubB)
if err != nil {
t.Fatal(err)
}

if !pub.Equals(pubNew) || !pubNew.Equals(pub) {
t.Fatal("keys are not equal")
}

}
12 changes: 12 additions & 0 deletions ed25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ import (
"io"

pb "github.com/libp2p/go-libp2p-crypto/pb"

"golang.org/x/crypto/ed25519"
)

// Ed25519PrivateKey is an ed25519 private key
type Ed25519PrivateKey struct {
k ed25519.PrivateKey
}

// Ed25519PublicKey is an ed25519 public key
type Ed25519PublicKey struct {
k ed25519.PublicKey
}

// GenerateEd25519Key generate a new ed25519 private and public key pair
func GenerateEd25519Key(src io.Reader) (PrivKey, PubKey, error) {
pub, priv, err := ed25519.GenerateKey(src)
if err != nil {
Expand All @@ -36,6 +40,7 @@ func (k *Ed25519PrivateKey) Type() pb.KeyType {
return pb.KeyType_Ed25519
}

// Bytes marshals an ed25519 private key to protobuf bytes
func (k *Ed25519PrivateKey) Bytes() ([]byte, error) {
return MarshalPrivateKey(k)
}
Expand All @@ -55,6 +60,7 @@ func (k *Ed25519PrivateKey) pubKeyBytes() []byte {
return k.k[ed25519.PrivateKeySize-ed25519.PublicKeySize:]
}

// Equals compares two ed25519 private keys
func (k *Ed25519PrivateKey) Equals(o Key) bool {
edk, ok := o.(*Ed25519PrivateKey)
if !ok {
Expand All @@ -64,10 +70,12 @@ func (k *Ed25519PrivateKey) Equals(o Key) bool {
return bytes.Equal(k.k, edk.k)
}

// GetPublic returns an ed25519 public key from a private key
func (k *Ed25519PrivateKey) GetPublic() PubKey {
return &Ed25519PublicKey{k: k.pubKeyBytes()}
}

// Sign returns a signature from an input message
func (k *Ed25519PrivateKey) Sign(msg []byte) ([]byte, error) {
return ed25519.Sign(k.k, msg), nil
}
Expand All @@ -76,6 +84,7 @@ func (k *Ed25519PublicKey) Type() pb.KeyType {
return pb.KeyType_Ed25519
}

// Bytes returns a ed25519 public key as protobuf bytes
func (k *Ed25519PublicKey) Bytes() ([]byte, error) {
return MarshalPublicKey(k)
}
Expand All @@ -84,6 +93,7 @@ func (k *Ed25519PublicKey) Raw() ([]byte, error) {
return k.k, nil
}

// Equals compares two ed25519 public keys
func (k *Ed25519PublicKey) Equals(o Key) bool {
edk, ok := o.(*Ed25519PublicKey)
if !ok {
Expand All @@ -93,6 +103,7 @@ func (k *Ed25519PublicKey) Equals(o Key) bool {
return bytes.Equal(k.k, edk.k)
}

// Verify checks a signature agains the input data
func (k *Ed25519PublicKey) Verify(data []byte, sig []byte) (bool, error) {
return ed25519.Verify(k.k, data, sig), nil
}
Expand All @@ -106,6 +117,7 @@ func UnmarshalEd25519PublicKey(data []byte) (PubKey, error) {
}, nil
}

// UnmarshalEd25519PrivateKey returns a private key from input bytes
func UnmarshalEd25519PrivateKey(data []byte) (PrivKey, error) {
switch len(data) {
case ed25519.PrivateKeySize + ed25519.PublicKeySize:
Expand Down
Loading