From 5d043d79e78ca44e44a96fc4790e4a76dc5f947e Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 29 Jan 2016 08:36:04 -0500 Subject: [PATCH] * rework dsa test * add initial ed25519 (not done) * fix common.Certificate compile error * add more functions to crypto.SigningPrivateKey interface, not everyone implements them yet --- lib/common/certificate.go | 10 +++-- lib/crypto/dsa.go | 43 +++++++++++++----- lib/crypto/dsa_test.go | 49 ++++++++++++++------- lib/crypto/ed25519.go | 89 ++++++++++++++++++++++++++++++++++++++ lib/crypto/ed25519_test.go | 9 ++++ lib/crypto/elg_test.go | 4 +- lib/crypto/sign.go | 9 +++- 7 files changed, 182 insertions(+), 31 deletions(-) create mode 100644 lib/crypto/ed25519_test.go diff --git a/lib/common/certificate.go b/lib/common/certificate.go index 5c3f3f4..686309f 100644 --- a/lib/common/certificate.go +++ b/lib/common/certificate.go @@ -38,15 +38,19 @@ func (c Certificate) Type() byte { } // get the length of the data in this certificate +// return -1 if the size of the certificate is invalid func (c Certificate) Len() int { + if len(c) <= 2 { + // invalid size + return -1 + } return int(binary.BigEndian.Uint16(c[1:3])) } -// get the data for this certificate or null if non exists +// get the data for this certificate or null if none exists func (c Certificate) Data() (d []byte) { l := c.Len() - if l > 0 { - // TODO(psi): check bounds correctly? + if l > 0 && len(c) <= 3+l { d = c[3 : 3+l] } return diff --git a/lib/crypto/dsa.go b/lib/crypto/dsa.go index f049db5..9e48af4 100644 --- a/lib/crypto/dsa.go +++ b/lib/crypto/dsa.go @@ -42,7 +42,7 @@ var param = dsa.Parameters{ } // generate a dsa keypair -func DSAGenerate(priv *dsa.PrivateKey, rand io.Reader) error { +func generateDSA(priv *dsa.PrivateKey, rand io.Reader) error { // put our paramters in priv.P = param.P priv.Q = param.Q @@ -60,16 +60,19 @@ func createDSAPublicKey(Y *big.Int) *dsa.PublicKey { } // createa i2p dsa private key given its public component -func createDSAPrivkey(X *big.Int) *dsa.PrivateKey { - Y := new(big.Int) - Y.Exp(dsag, X, dsap) - return &dsa.PrivateKey{ - PublicKey: dsa.PublicKey{ - Parameters: param, - Y: Y, - }, - X: X, +func createDSAPrivkey(X *big.Int) (k *dsa.PrivateKey) { + if X.Cmp(dsap) == -1 { + Y := new(big.Int) + Y.Exp(dsag, X, dsap) + k = &dsa.PrivateKey{ + PublicKey: dsa.PublicKey{ + Parameters: param, + Y: Y, + }, + X: X, + } } + return } type DSAVerifier struct { @@ -128,6 +131,26 @@ func (k DSAPrivateKey) NewSigner() (s Signer, err error) { return } +func (k DSAPrivateKey) Public() (pk DSAPublicKey, err error) { + p := createDSAPrivkey(new(big.Int).SetBytes(k[:])) + if p == nil { + err = ErrInvalidKeyFormat + } else { + copy(pk[:], p.Y.Bytes()) + } + return +} + +func (k DSAPrivateKey) Generate() (s DSAPrivateKey, err error) { + dk := new(dsa.PrivateKey) + err = generateDSA(dk, rand.Reader) + if err == nil { + copy(k[:], dk.X.Bytes()) + s = k + } + return +} + func (ds *DSASigner) Sign(data []byte) (sig []byte, err error) { h := sha1.Sum(data) sig, err = ds.SignHash(h[:]) diff --git a/lib/crypto/dsa_test.go b/lib/crypto/dsa_test.go index f5068bf..f207ed6 100644 --- a/lib/crypto/dsa_test.go +++ b/lib/crypto/dsa_test.go @@ -1,27 +1,46 @@ package crypto import ( - "crypto/dsa" - "crypto/rand" "testing" ) func TestDSA(t *testing.T) { - rng := rand.Reader - kp := new(dsa.PrivateKey) - err := DSAGenerate(kp, rng) + var sk DSAPrivateKey + var pk DSAPublicKey + var err error + sk, err = sk.Generate() if err == nil { - t.Logf("DSA Key Pair generated") - } else { - t.Logf("error while generating key: %s", err) - t.Fail() + zeros := 0 + for b, _ := range sk { + if b == 0 { + zeros ++ + } + } + if zeros == len(sk) { + t.Logf("key generation yielded all zeros") + t.Fail() + } + pk, err = sk.Public() + if err == nil { + data := make([]byte, 512) + var sig []byte + var signer Signer + signer, err = sk.NewSigner() + if err == nil { + sig, err = signer.Sign(data) + if err == nil { + t.Logf("sig=%q", sig) + var verify Verifier + verify, err = pk.NewVerifier() + if err == nil { + err = verify.Verify(data, sig) + } + } + } + } } - h := make([]byte, 20) - _, _, err = dsa.Sign(rng, kp, h) - if err == nil { - t.Log("signed") - } else { - t.Logf("error signing: %s", err) + if err != nil { + t.Logf("failed: %s", err.Error()) t.Fail() } } diff --git a/lib/crypto/ed25519.go b/lib/crypto/ed25519.go index 456ab20..040a10c 100644 --- a/lib/crypto/ed25519.go +++ b/lib/crypto/ed25519.go @@ -1,4 +1,93 @@ package crypto +/* +#cgo pkg-config: libsodium +#include +#include +*/ +import "C" + +import ( + "crypto/sha512" + "errors" + "fmt" +) + type Ed25519PublicKey [32]byte + +type Ed25519Verifier struct { + k [32]C.uchar +} + +func (k Ed25519PublicKey) NewVerifier() (v Verifier, err error) { + ev := new(Ed25519Verifier) + for i, b := range k { + ev.k[i] = C.uchar(b) + } + v = ev + return +} + +func (v *Ed25519Verifier) VerifyHash(h, sig []byte) (err error) { + if len(sig) == C.crypto_sign_BYTES { + // valid size of sig + // copy signature and hash + var csig, ch [32]C.uchar + for i, b := range h { + ch[i] = C.uchar(b) + } + for i, b := range sig { + csig[i] = C.uchar(b) + } + // verify + if C.crypto_sign_verify_detached(&csig[0], &ch[0], C.ulonglong(32), &v.k[0]) == 0 { + // valid signature + } else { + // bad signature + err = ErrInvalidSignature + } + } else { + // bad size of sig + err = ErrBadSignatureSize + } + return +} + +func (v *Ed25519Verifier) Verify(data, sig []byte) (err error) { + h := sha512.Sum512(data) + err = v.VerifyHash(h[:], sig) + return +} + type Ed25519PrivateKey [32]byte + +type Ed25519Signer struct { + k [32]C.uchar +} + +func (s *Ed25519Signer) Sign(data []byte) (sig []byte, err error) { + h := sha512.Sum512(data) + sig, err = s.SignHash(h[:]) + return +} + +func (s *Ed25519Signer) SignHash(h []byte) (sig []byte, err error) { + var ch [32]C.uchar + for i, b := range h { + ch[i] = C.uchar(b) + } + var csig [32]C.uchar + var smlen_p C.ulonglong + res := C.crypto_sign_detached(&csig[0], &smlen_p, &ch[0], C.ulonglong(32), &s.k[0]) + if res == 0 { + // success signing + sig = make([]byte, 32) + for i, b := range csig { + sig[i] = byte(b) + } + } else { + // failed signing + err = errors.New(fmt.Sprintf("failed to sign: crypto_sign_detached exit code %d", int(res))) + } + return +} diff --git a/lib/crypto/ed25519_test.go b/lib/crypto/ed25519_test.go new file mode 100644 index 0000000..3666f5d --- /dev/null +++ b/lib/crypto/ed25519_test.go @@ -0,0 +1,9 @@ +package crypto + +import ( + "testing" +) + +func TestEd25519(t *testing.T) { + +} diff --git a/lib/crypto/elg_test.go b/lib/crypto/elg_test.go index d17fa2e..8b1d8a4 100644 --- a/lib/crypto/elg_test.go +++ b/lib/crypto/elg_test.go @@ -22,7 +22,9 @@ func TestElg(t *testing.T) { if err == nil { dec, err := elgamalDecrypt(k, emsg, true) if err == nil { - if !bytes.Equal(dec, msg) { + if bytes.Equal(dec, msg) { + t.Logf("%q == %q", dec, msg) + } else { t.Logf("%q != %q", dec, msg) t.Fail() } diff --git a/lib/crypto/sign.go b/lib/crypto/sign.go index fb13083..1f98e6b 100644 --- a/lib/crypto/sign.go +++ b/lib/crypto/sign.go @@ -12,7 +12,7 @@ var ErrInvalidSignature = errors.New("invalid signature") type Verifier interface { // verify hashed data with this signing key // return nil on valid signature otherwise error - VerifyHash(data, sig []byte) error + VerifyHash(h, sig []byte) error // verify an unhashed piece of data by hashing it and calling VerifyHash Verify(data, sig []byte) error } @@ -42,6 +42,11 @@ type SigningPrivateKey interface { // create a new signer to sign data // return signer or nil and error if key format is invalid NewSigner() (Signer, error) - + // length of this private key Len() int + // get public key or return nil and error if invalid key data in private key + Public() (SigningPublicKey, error) + // generate a new private key, put it into itself + // returns itself or nil and error if an error occurs + Generate() (SigningPrivateKey, error) }