From 5af207437fd8f84c51c48ca8bfdf626f9e720ec5 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 2 May 2017 10:04:54 +0200 Subject: Rename key package --- key/key.go | 148 ++++++++++++++++++++++++++++++++++++++++++++ key/key_test.go | 69 +++++++++++++++++++++ key/testdata/dim13.pub | 2 + key/testdata/dim13.sec | 2 + key/testdata/isc.txt.gz | Bin 0 -> 501 bytes key/testdata/isc.txt.gz.sig | Bin 0 -> 775 bytes key/testdata/kdf.pub | 2 + key/testdata/kdf.sec | 2 + key/testdata/kdf.txt | 1 + key/testdata/key.pub | 2 + key/testdata/key.sec | 2 + key/testdata/key.txt | 1 + key/testdata/key.txt.sig | 3 + key/testdata/test | 1 + key/testdata/test.sig | 3 + 15 files changed, 238 insertions(+) create mode 100644 key/key.go create mode 100644 key/key_test.go create mode 100644 key/testdata/dim13.pub create mode 100644 key/testdata/dim13.sec create mode 100644 key/testdata/isc.txt.gz create mode 100644 key/testdata/isc.txt.gz.sig create mode 100644 key/testdata/kdf.pub create mode 100644 key/testdata/kdf.sec create mode 100644 key/testdata/kdf.txt create mode 100644 key/testdata/key.pub create mode 100644 key/testdata/key.sec create mode 100644 key/testdata/key.txt create mode 100644 key/testdata/key.txt.sig create mode 100644 key/testdata/test create mode 100644 key/testdata/test.sig (limited to 'key') diff --git a/key/key.go b/key/key.go new file mode 100644 index 0000000..57978e0 --- /dev/null +++ b/key/key.go @@ -0,0 +1,148 @@ +package key + +import ( + "bytes" + "crypto/rand" + "crypto/sha512" + "encoding/binary" + "errors" + + "dim13.org/signify/bhash" + + "golang.org/x/crypto/ed25519" +) + +const DefaultRounds = 42 + +var ( + ErrInvalidPK = errors.New("unsupported format") + ErrInvalidKDF = errors.New("unsupported KDF") + ErrPassphrase = errors.New("incorrect passphrase") + ErrInvalidKey = errors.New("invalid key") + ErrKeyNum = errors.New("verification failed: checked against wrong key") + ErrInvalidSig = errors.New("signature verfication failed") +) + +var ( + pkAlg = [2]byte{'E', 'd'} + kdfAlg = [2]byte{'B', 'K'} +) + +type Sig struct { + PKAlg [2]byte + KeyNum [8]byte + Sig [ed25519.SignatureSize]byte +} + +type Pub struct { + PKAlg [2]byte + KeyNum [8]byte + Key [ed25519.PublicKeySize]byte +} + +type Enc struct { + PKAlg [2]byte + KDFAlg [2]byte + KDFRounds uint32 + Salt [16]byte + Checksum [8]byte + KeyNum [8]byte + Key [ed25519.PrivateKeySize]byte +} + +func (v *Sig) Check() error { + if v.PKAlg != pkAlg { + return ErrInvalidPK + } + return nil +} + +func (v *Pub) Check() error { + if v.PKAlg != pkAlg { + return ErrInvalidPK + } + return nil +} + +func (v *Pub) Verify(message []byte, sig *Sig) error { + if v.KeyNum != sig.KeyNum { + return ErrKeyNum + } + if !ed25519.Verify(ed25519.PublicKey(v.Key[:]), message, sig.Sig[:]) { + return ErrInvalidSig + } + return nil +} + +func (v *Enc) Sign(message []byte) *Sig { + sig := &Sig{PKAlg: v.PKAlg, KeyNum: v.KeyNum} + copy(sig.Sig[:], ed25519.Sign(ed25519.PrivateKey(v.Key[:]), message)) + return sig +} + +func (v *Enc) Check() error { + if v.PKAlg != pkAlg { + return ErrInvalidPK + } + if v.KDFAlg != kdfAlg { + return ErrInvalidKDF + } + sum := sha512.Sum512(v.Key[:]) + if !bytes.Equal(sum[:len(v.Checksum)], v.Checksum[:]) { + return ErrInvalidKey + } + return nil +} + +func (e *Enc) Kdf(ask func() (string, error)) error { + if e.KDFRounds == 0 { + return nil + } + pass, err := ask() + if err != nil { + return err + } + xor := bhash.Pbkdf([]byte(pass), e.Salt[:], int(e.KDFRounds), len(e.Key)) + for i := range xor { + e.Key[i] ^= xor[i] + } + return e.Check() +} + +func Unmarshal(b []byte, v interface{}) error { + buf := bytes.NewReader(b) + if err := binary.Read(buf, binary.BigEndian, v); err != nil { + return err + } + return nil +} + +func Marshal(v interface{}) ([]byte, error) { + buf := new(bytes.Buffer) + if err := binary.Write(buf, binary.BigEndian, v); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func NewKey() (Pub, Enc, error) { + pub, sec, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return Pub{}, Enc{}, err + } + + pubKey := Pub{PKAlg: pkAlg} + encKey := Enc{PKAlg: pkAlg, KDFAlg: kdfAlg, KDFRounds: DefaultRounds} + + copy(pubKey.Key[:], pub) + copy(encKey.Key[:], sec) + + checkSum := sha512.Sum512(sec) + copy(encKey.Checksum[:], checkSum[:len(encKey.Checksum)]) + + rand.Read(encKey.Salt[:]) + rand.Read(encKey.KeyNum[:]) + pubKey.KeyNum = encKey.KeyNum + + return pubKey, encKey, nil +} diff --git a/key/key_test.go b/key/key_test.go new file mode 100644 index 0000000..ef1c09c --- /dev/null +++ b/key/key_test.go @@ -0,0 +1,69 @@ +package key + +import ( + "bytes" + "encoding/base64" + "testing" +) + +func decode(s string) ([]byte, error) { + return base64.StdEncoding.DecodeString(s) +} + +func TestUnmarshalSig(t *testing.T) { + raw, err := decode("RWRbOC0bBf7abaGwGtq45KLDK63tgcF7CO4qTZSlTKCSbZTYlDfFm/DISQ60u+/jEzrk22suvXXAEsxQTe2xUOfV90get1YRGQo=") + if err != nil { + t.Fatal(err) + } + v := new(Sig) + Unmarshal(raw, v) + out, _ := Marshal(v) + if !bytes.Equal(raw, out) { + t.Errorf("want %v, got %v", raw, out) + } +} + +func TestUnmarshalPub(t *testing.T) { + raw, err := decode("RWRbOC0bBf7abfanaXuTYfCa6+YO69Kxyz8RD5nL/3Ta7umY6iOwnBrG") + if err != nil { + t.Fatal(err) + } + v := new(Pub) + Unmarshal(raw, v) + out, _ := Marshal(v) + if !bytes.Equal(raw, out) { + t.Errorf("want %v, got %v", raw, out) + } +} + +func TestUnmarshalEnc(t *testing.T) { + raw, err := decode("RWRCSwAAAACzJBN2gC5//jVvDiV76rs4m2aKXkljqDpbOC0bBf7abZhV/Zygr6b0KIbSI56JQutwzsQeouxnnHuVTZp3IW4M9qdpe5Nh8Jrr5g7r0rHLPxEPmcv/dNru6ZjqI7CcGsY=") + if err != nil { + t.Fatal(err) + } + v := new(Enc) + Unmarshal(raw, v) + out, _ := Marshal(v) + if !bytes.Equal(raw, out) { + t.Errorf("want %v, got %v", raw, out) + } + if err := v.Kdf(func() (string, error) { return "", nil }); err != nil { + t.Error(err) + } +} + +func TestUnmarshalEncKDF(t *testing.T) { + raw, err := decode("RWRCSwAAACoXv4r2lp3RYYLEWZRsY+1Z+1mJtEScNBaKdOKcMdhUHrztnf8a4sUNGY19MoV3wX2cyW2Mn1MduKxi9s3Se070TGF0IZG/hH4SKiNUYi+yi1mandWAwmhY3ahIHApigTk=") + if err != nil { + t.Fatal(err) + } + v := new(Enc) + Unmarshal(raw, v) + out, _ := Marshal(v) + if !bytes.Equal(raw, out) { + t.Errorf("want %v, got %v", raw, out) + } + if err := v.Kdf(func() (string, error) { return "test", nil }); err != nil { + t.Error(err) + } +} diff --git a/key/testdata/dim13.pub b/key/testdata/dim13.pub new file mode 100644 index 0000000..0efc253 --- /dev/null +++ b/key/testdata/dim13.pub @@ -0,0 +1,2 @@ +untrusted comment: dim13.org public key +RWRbOC0bBf7abfanaXuTYfCa6+YO69Kxyz8RD5nL/3Ta7umY6iOwnBrG diff --git a/key/testdata/dim13.sec b/key/testdata/dim13.sec new file mode 100644 index 0000000..51e0d28 --- /dev/null +++ b/key/testdata/dim13.sec @@ -0,0 +1,2 @@ +untrusted comment: dim13.org secret key +RWRCSwAAAACzJBN2gC5//jVvDiV76rs4m2aKXkljqDpbOC0bBf7abZhV/Zygr6b0KIbSI56JQutwzsQeouxnnHuVTZp3IW4M9qdpe5Nh8Jrr5g7r0rHLPxEPmcv/dNru6ZjqI7CcGsY= diff --git a/key/testdata/isc.txt.gz b/key/testdata/isc.txt.gz new file mode 100644 index 0000000..9800c17 Binary files /dev/null and b/key/testdata/isc.txt.gz differ diff --git a/key/testdata/isc.txt.gz.sig b/key/testdata/isc.txt.gz.sig new file mode 100644 index 0000000..0b2ab0e Binary files /dev/null and b/key/testdata/isc.txt.gz.sig differ diff --git a/key/testdata/kdf.pub b/key/testdata/kdf.pub new file mode 100644 index 0000000..abc3893 --- /dev/null +++ b/key/testdata/kdf.pub @@ -0,0 +1,2 @@ +untrusted comment: signify public key +RWSKdOKcMdhUHtD9TWgPRZnRRTwl2WTeRpEZLCjtf4TTS24EfqT7uoPz diff --git a/key/testdata/kdf.sec b/key/testdata/kdf.sec new file mode 100644 index 0000000..b69b5e8 --- /dev/null +++ b/key/testdata/kdf.sec @@ -0,0 +1,2 @@ +untrusted comment: signify secret key +RWRCSwAAACoXv4r2lp3RYYLEWZRsY+1Z+1mJtEScNBaKdOKcMdhUHrztnf8a4sUNGY19MoV3wX2cyW2Mn1MduKxi9s3Se070TGF0IZG/hH4SKiNUYi+yi1mandWAwmhY3ahIHApigTk= diff --git a/key/testdata/kdf.txt b/key/testdata/kdf.txt new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/key/testdata/kdf.txt @@ -0,0 +1 @@ +test diff --git a/key/testdata/key.pub b/key/testdata/key.pub new file mode 100644 index 0000000..07f9107 --- /dev/null +++ b/key/testdata/key.pub @@ -0,0 +1,2 @@ +untrusted comment: signify public key +RWTkgMtoLot+Y1KOfKO8Q4JMnmMp40AwMqkSU++oUOVVloMtv/Y0tDbe diff --git a/key/testdata/key.sec b/key/testdata/key.sec new file mode 100644 index 0000000..32abaed --- /dev/null +++ b/key/testdata/key.sec @@ -0,0 +1,2 @@ +untrusted comment: signify secret key +RWRCSwAAACpjn/Y5du0k4LT23ConAYrBM6A/ML4cEQrkgMtoLot+YyzUwyr5f1hUz8W0pkzPx+wZz51Z2oyM6gf/PaG7KPzyO/6VC0l29ZzLUfQGVoOGGKZxuPA6k8iMHvqONFGQ7hA= diff --git a/key/testdata/key.txt b/key/testdata/key.txt new file mode 100644 index 0000000..1a4db74 --- /dev/null +++ b/key/testdata/key.txt @@ -0,0 +1 @@ +Password: test diff --git a/key/testdata/key.txt.sig b/key/testdata/key.txt.sig new file mode 100644 index 0000000..c8326bd --- /dev/null +++ b/key/testdata/key.txt.sig @@ -0,0 +1,3 @@ +untrusted comment: verify with key.pub +RWTkgMtoLot+Y4mRk5LYyq04fwaGaMeFxbvyZLEA+xxv0TmHQzpmirMxTgSp9D9jT+rtW2d1X9VKK3mBoIKZNMatkdBsU1gKCgc= +Password: test diff --git a/key/testdata/test b/key/testdata/test new file mode 100644 index 0000000..557db03 --- /dev/null +++ b/key/testdata/test @@ -0,0 +1 @@ +Hello World diff --git a/key/testdata/test.sig b/key/testdata/test.sig new file mode 100644 index 0000000..1a1bdf0 --- /dev/null +++ b/key/testdata/test.sig @@ -0,0 +1,3 @@ +untrusted comment: verify with dim13.pub +RWRbOC0bBf7abaGwGtq45KLDK63tgcF7CO4qTZSlTKCSbZTYlDfFm/DISQ60u+/jEzrk22suvXXAEsxQTe2xUOfV90get1YRGQo= +Hello World -- cgit v1.2.3