This repository has been archived by the owner on Dec 7, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from c3systems/forPR
Added ECDSA; Added RSA tests; Fixed linting errors; Handling all un-handled errors
- Loading branch information
Showing
12 changed files
with
513 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.DS_Store | ||
|
||
# vim | ||
.swp | ||
*~ | ||
*.swp | ||
*.swo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.