-
-
Notifications
You must be signed in to change notification settings - Fork 190
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add support for Ed25519 * Amended naming and added additional testing * Added changes from Dave's review * Next review: Fixed casing on error messages for linter | Fixed version number * Added Dave's suggestions in docs and updated built docs * Final push from Dave's review | Wrap crypto example in docs in quotes
- Loading branch information
Showing
6 changed files
with
371 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package crypto | ||
|
||
import ( | ||
"bytes" | ||
"crypto/ed25519" | ||
"crypto/rand" | ||
"crypto/x509" | ||
"encoding/pem" | ||
"fmt" | ||
) | ||
|
||
// Ed25519GenerateKey returns a random PEM encoded Ed25519 Private Key. | ||
func Ed25519GenerateKey() ([]byte, error) { | ||
_, secret, err := ed25519.GenerateKey(rand.Reader) | ||
if err != nil { | ||
return nil, fmt.Errorf("generateKey: %w", err) | ||
} | ||
return pemEncodeEdPrivateKey(secret) | ||
} | ||
|
||
// Ed25519GenerateKeyFromSeed returns a PEM encoded Ed25519 Private Key from | ||
// `seed`. Returns error if len(seed) is not ed25519.SeedSize (32). | ||
func Ed25519GenerateKeyFromSeed(seed []byte) ([]byte, error) { | ||
if len(seed) != ed25519.SeedSize { | ||
return nil, fmt.Errorf("generateKeyFromSeed: incorrect seed size - given: %d wanted %d", len(seed), ed25519.SeedSize) | ||
} | ||
return pemEncodeEdPrivateKey(ed25519.NewKeyFromSeed(seed)) | ||
} | ||
|
||
// Ed25519DerivePublicKey returns an ed25519 Public Key from given PEM encoded | ||
// `privatekey`. | ||
func Ed25519DerivePublicKey(privatekey []byte) ([]byte, error) { | ||
secret, err := ed25519DecodeFromPEM(privatekey) | ||
if err != nil { | ||
return nil, fmt.Errorf("ed25519DecodeFromPEM: could not decode private key: %w", err) | ||
} | ||
b, err := x509.MarshalPKIXPublicKey(secret.Public()) | ||
if err != nil { | ||
return nil, fmt.Errorf("marshalPKIXPublicKey: failed to marshal PKIX public key: %w", err) | ||
} | ||
return pem.EncodeToMemory(&pem.Block{ | ||
Type: "PUBLIC KEY", | ||
Bytes: b, | ||
}), nil | ||
} | ||
|
||
// pemEncodeEdPrivateKey is a convenience function for PEM encoding `secret`. | ||
func pemEncodeEdPrivateKey(secret ed25519.PrivateKey) ([]byte, error) { | ||
der, err := x509.MarshalPKCS8PrivateKey(secret) | ||
if err != nil { | ||
return nil, fmt.Errorf("marshalPKCS8PrivateKey: failed to marshal ed25519 private key: %w", err) | ||
} | ||
block := &pem.Block{ | ||
Type: "PRIVATE KEY", | ||
Bytes: der, | ||
} | ||
buf := &bytes.Buffer{} | ||
err = pem.Encode(buf, block) | ||
if err != nil { | ||
return nil, fmt.Errorf("encode: PEM encoding: %w", err) | ||
} | ||
return buf.Bytes(), nil | ||
} | ||
|
||
// ed25519DecodeFromPEM returns an ed25519.PrivateKey from given PEM encoded | ||
// `privatekey`. | ||
func ed25519DecodeFromPEM(privatekey []byte) (ed25519.PrivateKey, error) { | ||
block, _ := pem.Decode(privatekey) | ||
if block == nil { | ||
return nil, fmt.Errorf("decode: failed to read key") | ||
} | ||
priv, err := x509.ParsePKCS8PrivateKey(block.Bytes) | ||
if err != nil { | ||
return nil, fmt.Errorf("parsePKCS8PrivateKey: invalid private key: %w", err) | ||
} | ||
secret, ok := priv.(ed25519.PrivateKey) | ||
if !ok { | ||
return nil, fmt.Errorf("ed25519DecodeFromPEM: invalid ed25519 Private Key - given type: %T", priv) | ||
} | ||
return secret, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package crypto | ||
|
||
import ( | ||
"crypto/ed25519" | ||
"crypto/x509" | ||
"encoding/pem" | ||
"fmt" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestEd25519GenerateKey(t *testing.T) { | ||
key, err := Ed25519GenerateKey() | ||
require.NoError(t, err) | ||
assert.True(t, strings.HasPrefix(string(key), | ||
"-----BEGIN PRIVATE KEY-----")) | ||
assert.True(t, strings.HasSuffix(string(key), | ||
"-----END PRIVATE KEY-----\n")) | ||
} | ||
|
||
func TestEd25519DerivePublicKey(t *testing.T) { | ||
_, err := Ed25519DerivePublicKey(nil) | ||
assert.Error(t, err) | ||
_, err = Ed25519DerivePublicKey([]byte(`-----BEGIN FOO----- | ||
-----END FOO-----`)) | ||
assert.Error(t, err) | ||
|
||
priv, err := Ed25519GenerateKey() | ||
require.NoError(t, err) | ||
pub, err := Ed25519DerivePublicKey(priv) | ||
require.NoError(t, err) | ||
block, _ := pem.Decode(pub) | ||
assert.True(t, block != nil) | ||
secret, err := ed25519DecodeFromPEM(priv) | ||
require.NoError(t, err) | ||
p, err := x509.ParsePKIXPublicKey(block.Bytes) | ||
require.NoError(t, err) | ||
pubKey, ok := p.(ed25519.PublicKey) | ||
assert.True(t, ok) | ||
assert.True(t, fmt.Sprintf("%x", p) == fmt.Sprintf("%x", secret.Public())) | ||
msg := []byte("ed25519") | ||
sig := ed25519.Sign(secret, msg) // Panics | ||
assert.True(t, ed25519.Verify(pubKey, msg, sig)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.