diff --git a/userenckey/gen.go b/userenckey/gen.go new file mode 100644 index 0000000000000000000000000000000000000000..f3cb4ceebec5f7b830829e1509f9346d32381c86 --- /dev/null +++ b/userenckey/gen.go @@ -0,0 +1,37 @@ +package userenckey + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "encoding/pem" +) + +func encodePublicKeyToPEM(pub *ecdsa.PublicKey) ([]byte, error) { + der, err := x509.MarshalPKIXPublicKey(pub) + if err != nil { + return nil, err + } + return pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: der}), nil +} + +// GenerateKey generates a new ECDSA key pair, and returns the +// PEM-encoded public and private key (in order). +func GenerateKey() ([]byte, []byte, error) { + pkey, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) + if err != nil { + return nil, nil, err + } + + privBytes, err := encodePrivateKeyToPEM(pkey) + if err != nil { + return nil, nil, err + } + pubBytes, err := encodePublicKeyToPEM(&pkey.PublicKey) + if err != nil { + return nil, nil, err + } + + return pubBytes, privBytes, nil +} diff --git a/userenckey/gen_test.go b/userenckey/gen_test.go new file mode 100644 index 0000000000000000000000000000000000000000..1574845bb7fd995c256e2698389e0951d6af91f3 --- /dev/null +++ b/userenckey/gen_test.go @@ -0,0 +1,20 @@ +package userenckey + +import ( + "bytes" + "testing" +) + +func TestGenerateKey(t *testing.T) { + pub, priv, err := GenerateKey() + if err != nil { + t.Fatal(err) + } + + if !bytes.HasPrefix(pub, []byte("-----BEGIN PUBLIC KEY-----")) { + t.Errorf("bad public key: %s", string(pub)) + } + if !bytes.HasPrefix(priv, []byte("-----BEGIN PRIVATE KEY-----")) { + t.Errorf("bad private key: %s", string(priv)) + } +} diff --git a/userenckey/pkcs8.go b/userenckey/pkcs8.go new file mode 100644 index 0000000000000000000000000000000000000000..f7f61215b15bc33aa338aba28a37c699a85546b8 --- /dev/null +++ b/userenckey/pkcs8.go @@ -0,0 +1,17 @@ +// +build go1.10 + +package userenckey + +import ( + "crypto/ecdsa" + "encoding/pem" +) + +// Encode a private key to PEM-encoded PKCS8. +func encodePrivateKeyToPEM(priv *ecdsa.PrivateKey) ([]byte, error) { + der, err := x509.MarshalPKCS8PrivateKey(priv) + if err != nil { + return nil, err + } + return pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: der}), nil +} diff --git a/userenckey/pkcs8_compat.go b/userenckey/pkcs8_compat.go new file mode 100644 index 0000000000000000000000000000000000000000..a63b6f8621a8910b16f0b774ef41b978f4287544 --- /dev/null +++ b/userenckey/pkcs8_compat.go @@ -0,0 +1,27 @@ +// +build !go1.10 + +package userenckey + +import ( + "bytes" + "crypto/ecdsa" + "crypto/x509" + "encoding/pem" + "os/exec" +) + +// Encode a private key to PEM-encoded PKCS8. +// +// In Go versions prior to 1.10, we must shell out to openssl to +// convert the private key to PKCS8 format. +func encodePrivateKeyToPEM(priv *ecdsa.PrivateKey) ([]byte, error) { + der, err := x509.MarshalECPrivateKey(priv) + if err != nil { + return nil, err + } + pkcs1 := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: der}) + + cmd := exec.Command("/usr/bin/openssl", "pkey") + cmd.Stdin = bytes.NewReader(pkcs1) + return cmd.Output() +}