aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGibheer <gibheer@gmail.com>2015-07-12 17:46:28 +0200
committerGibheer <gibheer@gmail.com>2015-07-12 17:46:28 +0200
commit2cfb28a0cec834be98ef04ba069af8f17d3e0aa6 (patch)
tree2611c2a8faaac31558818afae0f0c4b897669f25
parentedfac4e7244d7c73963c40049c124fa6d955a7d1 (diff)
add ed25519 implementation
This adds the ed25519 implementation. It implements most of the API, apart from three functions. Both MarshalPem methods write the raw bytes to the channel instead of exporting it into ASN.1. Maybe this needs to be fixed. The PrivateKey() function does not return a crypto.PrivateKey at the moment, as the ed25519 private key does not implement that interface.
-rw-r--r--ed25519.go104
1 files changed, 104 insertions, 0 deletions
diff --git a/ed25519.go b/ed25519.go
new file mode 100644
index 0000000..602ac52
--- /dev/null
+++ b/ed25519.go
@@ -0,0 +1,104 @@
+package pki
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/rand"
+ "encoding/pem"
+ "errors"
+ "io"
+
+ "github.com/agl/ed25519"
+)
+
+const (
+ PemLabelEd25519 = "ED25519 PRIVATE KEY" // TODO find correct label
+)
+
+type (
+ Ed25519PrivateKey struct {
+ private_key [ed25519.PrivateKeySize]byte
+ }
+
+ Ed25519PublicKey struct {
+ public_key [ed25519.PublicKeySize]byte
+ }
+)
+
+// Create a new private key of type ed25519.
+func NewPrivateKeyEd25519() (*Ed25519PrivateKey, error) {
+ _, pr_raw, err := ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ return nil, err
+ }
+ return &Ed25519PrivateKey{*pr_raw}, nil
+}
+
+// Restore an ed25519 private key from a raw byte stream.
+// TODO does this have to be asn1? all other functions expect asn1
+func LoadPrivateKeyEd25519(raw []byte) (*Ed25519PrivateKey, error) {
+ var pr_loaded [ed25519.PrivateKeySize]byte
+ length := copy(pr_loaded[:], raw)
+ if length != ed25519.PrivateKeySize {
+ return nil, errors.New("private key length incorrect")
+ }
+ return &Ed25519PrivateKey{pr_loaded}, nil
+}
+
+// TODO implement the raw API for the private key
+func (pr *Ed25519PrivateKey) PrivateKey() crypto.PrivateKey {
+ return nil
+}
+
+// Return the public key for this private key.
+func (pr *Ed25519PrivateKey) Public() PublicKey {
+ buf := bytes.NewBufferString(string(pr.private_key[:])) // create a bytes buffer to read the private key
+ pu_raw, _, err := ed25519.GenerateKey(buf) // use the already built private key again
+ if err != nil {
+ return nil
+ }
+ return &Ed25519PublicKey{*pu_raw}
+}
+
+// Hash the message given the hash algorythm and sign the hash using the private key.
+func (pr *Ed25519PrivateKey) Sign(message []byte, hash crypto.Hash) ([]byte, error) {
+ hashed_message := hash.New()
+ hashed_message.Write(message)
+ result := ed25519.Sign(&pr.private_key, hashed_message.Sum(nil))[:]
+ return result, nil
+}
+
+// Export the private key into the Pem format.
+func (pr Ed25519PrivateKey) MarshalPem() (io.WriterTo, error) {
+ pem_block := pem.Block{Type: PemLabelEd25519, Bytes: pr.private_key[:]}
+ return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
+}
+
+// Load the public key from a raw byte stream.
+// TODO should this be read from ASN.1? All other functions do that.
+func LoadPublicKeyEd25519(raw []byte) (*Ed25519PublicKey, error) {
+ var pu_loaded [ed25519.PublicKeySize]byte
+ length := copy(pu_loaded[:], raw)
+ if length != ed25519.PublicKeySize {
+ return nil, errors.New("public key length incorrect")
+ }
+ return &Ed25519PublicKey{pu_loaded}, nil
+}
+
+// Export the public key into the pem format.
+func (pu Ed25519PublicKey) MarshalPem() (io.WriterTo, error) {
+ pem_block := pem.Block{Type: PemLabelPublic, Bytes: pu.public_key[:]}
+ return marshalledPemBlock(pem.EncodeToMemory(&pem_block)), nil
+}
+
+// Hash the message with the hash algorythm and check the signature against the result.
+func (pu Ed25519PublicKey) Verify(message []byte, signature []byte, hash crypto.Hash) (bool, error) {
+ var sig [ed25519.SignatureSize]byte
+ length := copy(sig[:], signature)
+ if length != ed25519.SignatureSize {
+ return false, errors.New("signature does not fit length")
+ }
+ hashed_message := hash.New()
+ hashed_message.Write(message)
+ return ed25519.Verify(&pu.public_key, hashed_message.Sum(nil), &sig), nil
+}