From 522f2f23b9ebfb31311e3179a5904e12db45675e Mon Sep 17 00:00:00 2001 From: Nick Sullivan Date: Sat, 1 Mar 2014 11:55:10 -0800 Subject: [PATCH] Add support for unmarshalling ECC passvault - Minor readme fixes - Add structure for EC Public key unmarshal --- README.md | 6 +++--- ecdh/ecdh.go | 2 +- ecdh/ecdh_test.go | 2 +- passvault/passvault.go | 26 ++++++++++++++++++++++---- passvault/passvault_test.go | 18 ++++++++++++++++++ 5 files changed, 45 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 20a96fc..378da48 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ encryption and decryption server. [![Build Status](https://travis-ci.org/cloudflare/redoctober.png?branch=master)](https://travis-ci.org/cloudflare/redoctober) [![Build Status](https://drone.io/github.com/cloudflare/redoctober/status.png)](https://drone.io/github.com/cloudflare/redoctober/latest) -This project requires [Go 1.1](http://golang.org/doc/install#download) +This project requires [Go 1.2](http://golang.org/doc/install#download) or later to compile. Verify your go version by running `go version`: $ go version - go version go1.1 + go version go1.2 As with any Go program you do need to set the [GOPATH enviroment variable](http://golang.org/doc/code.html#GOPATH) @@ -35,7 +35,7 @@ secure) way is to skip the [Certificate Authority](https://en.wikipedia.org/wiki/Certificate_authority#Issuing_a_certificate) verification and generate a self-signed TLS certificate. Read this [detailed guide](http://www.akadia.com/services/ssh_test_certificate.html) -or, alternatively, follow this unsecure commands: +or, alternatively, follow these unsecure commands: $ mkdir cert $ chmod 700 cert diff --git a/ecdh/ecdh.go b/ecdh/ecdh.go index 5b2c06c..0b2f15f 100644 --- a/ecdh/ecdh.go +++ b/ecdh/ecdh.go @@ -28,7 +28,7 @@ func zero(in []byte) { // Encrypt secures and authenticates its input using the public key // using ECDHE with AES-128-CBC-HMAC-SHA1. -func Encrypt(pub ecdsa.PublicKey, in []byte) (out []byte, err error) { +func Encrypt(pub *ecdsa.PublicKey, in []byte) (out []byte, err error) { ephemeral, err := ecdsa.GenerateKey(Curve(), rand.Reader) if err != nil { return diff --git a/ecdh/ecdh_test.go b/ecdh/ecdh_test.go index 0efbd28..b0d7cdc 100644 --- a/ecdh/ecdh_test.go +++ b/ecdh/ecdh_test.go @@ -20,7 +20,7 @@ func TestGenerateKey(t *testing.T) { func TestCrypt(t *testing.T) { message := []byte("One ping only, please.") - out, err := Encrypt(testKey.PublicKey, message) + out, err := Encrypt(&testKey.PublicKey, message) if err != nil { t.Fatalf("%v", err) } diff --git a/passvault/passvault.go b/passvault/passvault.go index fa9b7cd..8cc3de9 100644 --- a/passvault/passvault.go +++ b/passvault/passvault.go @@ -50,6 +50,22 @@ const ( // Path of current vault var localPath string +type ECPublicKey struct { + Curve *elliptic.CurveParams + X, Y *big.Int +} + +// toECDSA takes the internal ECPublicKey and returns an equivalent +// an ecdsa.PublicKey +func (pk *ECPublicKey) toECDSA() *ecdsa.PublicKey { + ecdsaPub := new(ecdsa.PublicKey) + ecdsaPub.Curve = pk.Curve + ecdsaPub.X = pk.X + ecdsaPub.Y = pk.Y + + return ecdsaPub +} + // PasswordRecord is the structure used to store password and key // material for a single user name. It is written and read from // storage in JSON format. @@ -71,7 +87,7 @@ type PasswordRecord struct { ECKey struct { ECPriv []byte ECPrivIV []byte - ECPublic ecdsa.PublicKey + ECPublic ECPublicKey } Admin bool } @@ -200,7 +216,9 @@ func createPasswordRec(password string, admin bool) (newRec PasswordRecord, err if err = encryptECCRecord(&newRec, ecPriv, passKey); err != nil { return } - newRec.ECKey.ECPublic = ecPriv.PublicKey + newRec.ECKey.ECPublic.Curve = ecPriv.PublicKey.Curve.Params() + newRec.ECKey.ECPublic.X = ecPriv.PublicKey.X + newRec.ECKey.ECPublic.Y = ecPriv.PublicKey.Y } // encrypt AES key with password key @@ -530,7 +548,7 @@ func (pr PasswordRecord) EncryptKey(in []byte) (out []byte, err error) { if pr.Type == RSARecord { return rsa.EncryptOAEP(sha1.New(), rand.Reader, &pr.RSAKey.RSAPublic, in, nil) } else if pr.Type == ECCRecord { - return ecdh.Encrypt(pr.ECKey.ECPublic, in) + return ecdh.Encrypt(pr.ECKey.ECPublic.toECDSA(), in) } else { return nil, errors.New("Invalid function for record type") } @@ -568,7 +586,7 @@ func (pr PasswordRecord) GetKeyECCPub() (out *ecdsa.PublicKey, err error) { if pr.Type != ECCRecord { return out, errors.New("Invalid function for record type") } - return &pr.ECKey.ECPublic, err + return pr.ECKey.ECPublic.toECDSA(), err } // GetKeyECC returns the ECDSA private key of the record given the correct password. diff --git a/passvault/passvault_test.go b/passvault/passvault_test.go index 575e781..8eeda14 100644 --- a/passvault/passvault_test.go +++ b/passvault/passvault_test.go @@ -6,8 +6,26 @@ package passvault import ( "testing" + "os" ) +func TestStaticVault(t *testing.T) { + err := InitFromDisk("/tmp/redoctober.json") + if err != nil { + t.Fatalf("Error reading record", err) + } + + _, err = AddNewRecord("test", "bad pass", true) + if err != nil { + t.Fatalf("Error creating record", err) + } + err = InitFromDisk("/tmp/redoctober.json") + if err != nil { + t.Fatalf("Error reading record", err) + } + os.Remove("/tmp/redoctober.json") +} + func TestRSAEncryptDecrypt(t *testing.T) { oldDefaultRecordType := DefaultRecordType DefaultRecordType = RSARecord