Skip to content

Commit

Permalink
Implement asymetric cryptography.
Browse files Browse the repository at this point in the history
  • Loading branch information
nickpalmer committed Dec 13, 2016
1 parent 1266098 commit e4e523e
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 41 deletions.
82 changes: 82 additions & 0 deletions asymetric.go
@@ -0,0 +1,82 @@
package ezcrypt

import (
"fmt"
"io"

"golang.org/x/crypto/nacl/box"
)

func checkAsym(m []byte, k Key, p Pair) error {
err := checkEncrypt(m, k)

if err != nil {
return err
}

if p == nil {
return fmt.Errorf("Pair is missing.")
}

if p.private() == nil {
return fmt.Errorf("Pair is missing private key.")
}

if p.private().Bytes() == nil {
return fmt.Errorf("Private key is missing data.")
}

return nil
}

func encryptAsym(m []byte, k Key, p Pair, in io.Reader) ([]byte, error) {
err := checkAsym(m, k, p)

if err != nil {
return nil, err
}

n, err := generateNonce(in)

if err != nil {
return nil, err
}

ret := box.Seal(n.Slice(), m, n.Bytes(), k.Bytes(), p.private().Bytes())

return ret, nil
}

func checkDecryptAsym(m []byte, k Key, p Pair) error {
err := checkAsym(m, k, p)

if err != nil {
return err
}

if len(m) <= overhead {
return fmt.Errorf("Message is too short.")
}

return nil
}

func decryptAsym(m []byte, k Key, p Pair) ([]byte, error) {
err := checkDecryptAsym(m, k, p)

if err != nil {
return nil, err
}

n := newNonce(m)

b := make([]byte, 0, len(m)-overhead)

ret, ok := box.Open(b, m[nonceSize:], n.Bytes(), k.Bytes(), p.private().Bytes())

if !ok {
return nil, fmt.Errorf("Decryption failed.")
}

return ret, nil
}
225 changes: 225 additions & 0 deletions asymetric_test.go
@@ -0,0 +1,225 @@
package ezcrypt

import (
"bytes"
"crypto/rand"
"io"
"testing"
)

var (
nilPriv = &pair{
priv: nil,
}
nilPrivData = &pair{
priv: &badKey{},
}
)

func TestAsymetricEncrypt(t *testing.T) {
p, err := GeneratePair(rand.Reader)

if err != nil {
t.Fatalf("GeneratePair Failed: %s", err)
}

tcs := []struct {
t string
m []byte
k Key
p Pair
r io.Reader
ok bool
}{
{
t: "ok",
m: m,
k: p.Public(),
p: p,
r: rand.Reader,
ok: true,
},
{
t: "nil message",
k: p.Public(),
p: p,
r: rand.Reader,
},
{
t: "nil public",
m: m,
p: p,
r: rand.Reader,
},
{
t: "bad public",
m: m,
k: &badKey{},
p: p,
r: rand.Reader,
},
{
t: "nil pair",
m: m,
k: p.Public(),
r: rand.Reader,
},
{
t: "nil private",
m: m,
k: p.Public(),
p: nilPriv,
r: rand.Reader,
},
{
t: "nil private data",
m: m,
k: p.Public(),
p: nilPrivData,
r: rand.Reader,
},
{
t: "nil rand",
m: m,
k: p.Public(),
p: p,
},
}

for _, tc := range tcs {
ct, err := encryptAsym(tc.m, tc.k, tc.p, tc.r)

if tc.ok {
if err != nil {
t.Errorf("Error: %s : %s", tc.t, err)
} else {
if bytes.Equal(m, ct) {
t.Fatalf("WTF?")
}
}
} else {
if err == nil {
t.Errorf("No Error: %s", tc.t)
}
}
}
}

func TestAsymetricDecrypt(t *testing.T) {
ap, err := GeneratePair(rand.Reader)

if err != nil {
t.Fatalf("GeneratePair Failed: %s", err)
}

bp, err := GeneratePair(rand.Reader)

if err != nil {
t.Fatalf("GeneratePair Failed: %s", err)
}

cp, err := GeneratePair(rand.Reader)

if err != nil {
t.Fatalf("GeneratePair Failed: %s", err)
}

ct, err := encryptAsym(m, ap.Public(), bp, rand.Reader)

if err != nil {
t.Errorf("Encrypt failed: %s", err)
}

if bytes.Equal(m, ct) {
t.Fatalf("WTF?")
}

tcs := []struct {
t string
m []byte
k Key
p Pair
ok bool
}{
{
t: "ok",
m: ct,
k: bp.Public(),
p: ap,
ok: true,
},
{
t: "nil message",
k: bp.Public(),
p: ap,
},
{
t: "short message",
m: []byte("short"),
k: bp.Public(),
p: ap,
},
{
t: "nil public",
m: ct,
p: ap,
},
{
t: "nil public data",
m: ct,
k: &badKey{},
p: ap,
},
{
t: "nil pair",
m: ct,
k: bp.Public(),
},
{
t: "nil private",
m: ct,
k: bp.Public(),
p: nilPriv,
},
{
t: "nil private data",
m: ct,
k: bp.Public(),
p: nilPrivData,
},
{
t: "wrong private",
m: ct,
k: bp.Public(),
p: cp,
},
{
t: "wrong public",
m: ct,
k: cp.Public(),
p: ap,
},
}

for _, tc := range tcs {
d, err := decryptAsym(tc.m, tc.k, tc.p)

if tc.ok {
if err != nil {
t.Errorf("Error: %s : %s", tc.t, err)
} else {
if !bytes.Equal(m, d) {
t.Errorf("Decrypt Failed: %s : %s : %s", tc.t, m, d)
}
}
} else {
if err == nil {
t.Errorf("No error: %s", tc.t)
} else {
if bytes.Equal(m, d) {
t.Errorf("WTF?: %s", tc.t)
}
}
}
}
}
12 changes: 11 additions & 1 deletion keys.go
Expand Up @@ -30,12 +30,14 @@ type Key interface {
// Abstracts a public private key pair.
type Pair interface {
Public() Key
Encrypt(data []byte, dest Key, in io.Reader) ([]byte, error)
Decrypt(data []byte, source Key) ([]byte, error)
Store(public, private string) error
private() Key
}

// Constructs a new key pair.
func NewPair(rand io.Reader) (Pair, error) {
func GeneratePair(rand io.Reader) (Pair, error) {
var err error

publicKey, privateKey, err := box.GenerateKey(rand)
Expand Down Expand Up @@ -111,6 +113,14 @@ func (p *pair) private() Key {
return p.priv
}

func (p *pair) Encrypt(data []byte, dest Key, in io.Reader) ([]byte, error) {
return encryptAsym(data, dest, p, in)
}

func (p *pair) Decrypt(data []byte, source Key) ([]byte, error) {
return decryptAsym(data, source, p)
}

func (p *pair) Store(public, private string) error {
err := writeKey(p.pub, public)

Expand Down
30 changes: 25 additions & 5 deletions keys_test.go
Expand Up @@ -87,15 +87,19 @@ func TestKey(t *testing.T) {
t.Fatalf("Loaded invalid key!")
}

bytes, err := k.Encrypt([]byte(pubFile), rand.Reader)
ct, err := k.Encrypt(m, rand.Reader)

if err != nil {
t.Fatalf("Failed to Encrypt: %s", err)
}

dec, err := k2.Decrypt(bytes)
if bytes.Equal(m, ct) {
t.Fatalf("WTF!")
}

dec, err := k2.Decrypt(ct)

if pubFile != string(dec) {
if !bytes.Equal(m, dec) {
t.Fatalf("Decrypt failed: expected: %s != %s", pubFile, dec)
}

Expand Down Expand Up @@ -173,18 +177,34 @@ func TestPair(t *testing.T) {
t.Fatalf("Failed to write invalid key for test.")
}

_, err = NewPair(&errReader{})
_, err = GeneratePair(&errReader{})

if err == nil {
t.Fatalf("Failed to bork with bad rand source.")
}

pair, err := NewPair(rand.Reader)
pair, err := GeneratePair(rand.Reader)

if err != nil {
t.Fatalf("Failed to make pair: %s", err)
}

ct, err := pair.Encrypt(m, pair.Public(), rand.Reader)

if err != nil {
t.Fatalf("Encrypt failed: %s", err)
}

dt, err := pair.Decrypt(ct, pair.Public())

if err != nil {
t.Fatalf("Decrypt failed: %s", err)
}

if !bytes.Equal(m, dt) {
t.Fatalf("Decrypted message wrong: %s", dt)
}

err = pair.Store(temp, priv)

if err == nil {
Expand Down

0 comments on commit e4e523e

Please sign in to comment.