From 914960f60a3c8ccb56d018b2d3fe8484ee9976d7 Mon Sep 17 00:00:00 2001 From: Jared Horvat Date: Sun, 17 Dec 2023 13:25:56 -0700 Subject: Add support for Ed25519 (#1900) * 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 --- funcs/crypto.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ funcs/crypto_test.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) (limited to 'funcs') diff --git a/funcs/crypto.go b/funcs/crypto.go index 41c752c7..e3628fad 100644 --- a/funcs/crypto.go +++ b/funcs/crypto.go @@ -7,8 +7,11 @@ import ( "crypto/sha1" //nolint: gosec "crypto/sha256" "crypto/sha512" + "encoding/base64" + "encoding/hex" "fmt" "strings" + "unicode/utf8" "golang.org/x/crypto/bcrypt" @@ -287,6 +290,52 @@ func (f *CryptoFuncs) ECDSADerivePublicKey(privateKey string) (string, error) { return string(out), err } +// Ed25519GenerateKey - +// Experimental! +func (f *CryptoFuncs) Ed25519GenerateKey() (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + out, err := crypto.Ed25519GenerateKey() + return string(out), err +} + +// Ed25519GenerateKeyFromSeed - +// Experimental! +func (f *CryptoFuncs) Ed25519GenerateKeyFromSeed(encoding, seed string) (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + if !utf8.ValidString(seed) { + return "", fmt.Errorf("given seed is not valid UTF-8") // Don't print out seed (private). + } + var seedB []byte + var err error + switch encoding { + case "base64": + seedB, err = base64.StdEncoding.DecodeString(seed) + case "hex": + seedB, err = hex.DecodeString(seed) + default: + return "", fmt.Errorf("invalid encoding given: %s - only 'hex' or 'base64' are valid options", encoding) + } + if err != nil { + return "", fmt.Errorf("could not decode given seed: %w", err) + } + out, err := crypto.Ed25519GenerateKeyFromSeed(seedB) + return string(out), err +} + +// Ed25519DerivePublicKey - +// Experimental! +func (f *CryptoFuncs) Ed25519DerivePublicKey(privateKey string) (string, error) { + if err := checkExperimental(f.ctx); err != nil { + return "", err + } + out, err := crypto.Ed25519DerivePublicKey([]byte(privateKey)) + return string(out), err +} + // EncryptAES - // Experimental! func (f *CryptoFuncs) EncryptAES(key string, args ...interface{}) ([]byte, error) { diff --git a/funcs/crypto_test.go b/funcs/crypto_test.go index 90f6bdff..4d1b5660 100644 --- a/funcs/crypto_test.go +++ b/funcs/crypto_test.go @@ -2,6 +2,7 @@ package funcs import ( "context" + "encoding/base64" "strconv" "strings" "testing" @@ -167,6 +168,55 @@ func TestECDSADerivePublicKey(t *testing.T) { "-----END PUBLIC KEY-----\n")) } +func TestEd25519GenerateKey(t *testing.T) { + c := testCryptoNS() + key, err := c.Ed25519GenerateKey() + require.NoError(t, err) + + assert.True(t, strings.HasPrefix(key, + "-----BEGIN PRIVATE KEY-----")) + assert.True(t, strings.HasSuffix(key, + "-----END PRIVATE KEY-----\n")) +} + +func TestEd25519GenerateKeyFromSeed(t *testing.T) { + c := testCryptoNS() + enc := "" + seed := "" + _, err := c.Ed25519GenerateKeyFromSeed(enc, seed) + assert.Error(t, err) + + enc = "base64" + seed = "0000000000000000000000000000000" // 31 bytes, instead of wanted 32. + _, err = c.Ed25519GenerateKeyFromSeed(enc, seed) + assert.Error(t, err) + + seed += "0" // 32 bytes. + b64seed := base64.StdEncoding.EncodeToString([]byte(seed)) + key, err := c.Ed25519GenerateKeyFromSeed(enc, b64seed) + require.NoError(t, err) + + assert.True(t, strings.HasPrefix(key, + "-----BEGIN PRIVATE KEY-----")) + assert.True(t, strings.HasSuffix(key, + "-----END PRIVATE KEY-----\n")) +} + +func TestEd25519DerivePublicKey(t *testing.T) { + c := testCryptoNS() + + _, err := c.Ed25519DerivePublicKey("") + assert.Error(t, err) + + key, _ := c.Ed25519GenerateKey() + pub, err := c.Ed25519DerivePublicKey(key) + require.NoError(t, err) + assert.True(t, strings.HasPrefix(pub, + "-----BEGIN PUBLIC KEY-----")) + assert.True(t, strings.HasSuffix(pub, + "-----END PUBLIC KEY-----\n")) +} + func TestRSACrypt(t *testing.T) { t.Parallel() -- cgit v1.2.3