From 380623aad94f8d95754e1baac6d684e4bf35fa4f Mon Sep 17 00:00:00 2001 From: horvski Date: Tue, 7 Nov 2023 14:44:00 -0700 Subject: [PATCH 1/6] Add support for Ed25519 --- crypto/eddsa.go | 82 ++++++++++++++++++++++++++++++++++++++++++++ crypto/eddsa_test.go | 41 ++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 crypto/eddsa.go create mode 100644 crypto/eddsa_test.go diff --git a/crypto/eddsa.go b/crypto/eddsa.go new file mode 100644 index 000000000..1cec7609f --- /dev/null +++ b/crypto/eddsa.go @@ -0,0 +1,82 @@ +package crypto + +import ( + "bytes" + "crypto/ed25519" + "crypto/rand" + "crypto/x509" + "encoding/pem" + "fmt" +) + +// EDDSAGenerateKey returns a random PEM encoded Ed25519 Private Key. +func EDDSAGenerateKey() ([]byte, error) { + _, secret, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf("failed to generate EDDSA private key: %w", err) + } + return pemEncodeEdPrivateKey(secret) +} + +// EDDSAGenerateKeyFromSeed returns a PEM encoded Ed25519 Private Key from given +// seed. Panics if len(seed) is not SeedSize. +func EDDSAGenerateKeyFromSeed(seed []byte) ([]byte, error) { + secret := ed25519.NewKeyFromSeed(seed) // Panics + return pemEncodeEdPrivateKey(secret) +} + +// EDDSADerivePublicKey returns an EDDSA Public Key from a PEM encoded EDDSA +// Private key. +func EDDSADerivePublicKey(privatekey []byte) ([]byte, error) { + secret, err := edDSADecodeFromPEM(privatekey) + if err != nil { + return nil, fmt.Errorf("EDDSADerivePublicKey: could not decode private key") + } + b, err := x509.MarshalPKIXPublicKey(secret.Public()) + if err != nil { + return nil, fmt.Errorf("EDDSADerivePublicKey: failed to marshal PKIX public key: %w", err) + } + + return pem.EncodeToMemory(&pem.Block{ + Type: "PUBLIC KEY", + Bytes: b, + }), nil +} + +func pemEncodeEdPrivateKey(secret ed25519.PrivateKey) ([]byte, error) { + der, err := x509.MarshalPKCS8PrivateKey(secret) + if err != nil { + return nil, fmt.Errorf("pemEncodeEdPrivateKey: failed to marshal ECDSA 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("pemEncodeEdPrivateKey: failed to encode generated EDDSA private key: pem encoding failed: %w", err) + } + + return buf.Bytes(), nil +} + +// edDSADecodeFromPEM . +func edDSADecodeFromPEM(privatekey []byte) (ed25519.PrivateKey, error) { + block, _ := pem.Decode(privatekey) + if block == nil { + return nil, fmt.Errorf("edDSADecodeFromPEM: failed to read key: no key found") + } + + priv, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("edDSADecodeFromPEM: invalid private key: %w", err) + } + secret, ok := priv.(ed25519.PrivateKey) + if !ok { + return nil, fmt.Errorf("edDSADecodeFromPEM: invalid private key: %w", err) + } + return secret, nil +} diff --git a/crypto/eddsa_test.go b/crypto/eddsa_test.go new file mode 100644 index 000000000..1bd381ac9 --- /dev/null +++ b/crypto/eddsa_test.go @@ -0,0 +1,41 @@ +package crypto + +import ( + "crypto/x509" + "encoding/pem" + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestEDDSAGenerateKey(t *testing.T) { + key, err := EDDSAGenerateKey() + 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 TestEDDSADerivePublicKey(t *testing.T) { + _, err := EDDSADerivePublicKey(nil) + assert.Error(t, err) + _, err = EDDSADerivePublicKey([]byte(`-----BEGIN FOO----- + -----END FOO-----`)) + assert.Error(t, err) + + priv, err := EDDSAGenerateKey() + require.NoError(t, err) + pub, err := EDDSADerivePublicKey(priv) + require.NoError(t, err) + block, _ := pem.Decode(pub) + assert.True(t, block != nil) + secret, err := edDSADecodeFromPEM(priv) + require.NoError(t, err) + p, err := x509.ParsePKIXPublicKey(block.Bytes) + require.NoError(t, err) + assert.True(t, fmt.Sprintf("%x", p) == fmt.Sprintf("%x", secret.Public())) +} From 259c4532aa73c5213a5b6a078286625b74c1ffce Mon Sep 17 00:00:00 2001 From: horvski Date: Fri, 10 Nov 2023 16:18:42 -0700 Subject: [PATCH 2/6] Amended naming and added additional testing --- crypto/eddsa.go | 40 ++++++++++++++++++---------------------- crypto/eddsa_test.go | 22 ++++++++++++++-------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/crypto/eddsa.go b/crypto/eddsa.go index 1cec7609f..7f0e368ef 100644 --- a/crypto/eddsa.go +++ b/crypto/eddsa.go @@ -9,26 +9,25 @@ import ( "fmt" ) -// EDDSAGenerateKey returns a random PEM encoded Ed25519 Private Key. -func EDDSAGenerateKey() ([]byte, error) { +// 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("failed to generate EDDSA private key: %w", err) + return nil, fmt.Errorf("Ed25519GenerateKey: failed to generate EDDSA private key: %w", err) } return pemEncodeEdPrivateKey(secret) } -// EDDSAGenerateKeyFromSeed returns a PEM encoded Ed25519 Private Key from given -// seed. Panics if len(seed) is not SeedSize. -func EDDSAGenerateKeyFromSeed(seed []byte) ([]byte, error) { - secret := ed25519.NewKeyFromSeed(seed) // Panics - return pemEncodeEdPrivateKey(secret) +// Ed25519GenerateKeyFromSeed returns a PEM encoded Ed25519 Private Key from +// `seed`. Panics if len(seed) is not SeedSize. +func Ed25519GenerateKeyFromSeed(seed []byte) ([]byte, error) { + return pemEncodeEdPrivateKey(ed25519.NewKeyFromSeed(seed)) // Panics } -// EDDSADerivePublicKey returns an EDDSA Public Key from a PEM encoded EDDSA -// Private key. -func EDDSADerivePublicKey(privatekey []byte) ([]byte, error) { - secret, err := edDSADecodeFromPEM(privatekey) +// 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("EDDSADerivePublicKey: could not decode private key") } @@ -36,47 +35,44 @@ func EDDSADerivePublicKey(privatekey []byte) ([]byte, error) { if err != nil { return nil, fmt.Errorf("EDDSADerivePublicKey: 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("pemEncodeEdPrivateKey: failed to marshal ECDSA 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("pemEncodeEdPrivateKey: failed to encode generated EDDSA private key: pem encoding failed: %w", err) } - return buf.Bytes(), nil } -// edDSADecodeFromPEM . -func edDSADecodeFromPEM(privatekey []byte) (ed25519.PrivateKey, error) { +// 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("edDSADecodeFromPEM: failed to read key: no key found") + return nil, fmt.Errorf("ed25519DecodeFromPEM: failed to read key: no key found") } - priv, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { - return nil, fmt.Errorf("edDSADecodeFromPEM: invalid private key: %w", err) + return nil, fmt.Errorf("ed25519DecodeFromPEM: invalid private key: %w", err) } secret, ok := priv.(ed25519.PrivateKey) if !ok { - return nil, fmt.Errorf("edDSADecodeFromPEM: invalid private key: %w", err) + return nil, fmt.Errorf("ed25519DecodeFromPEM: invalid private key: %w", err) } return secret, nil } diff --git a/crypto/eddsa_test.go b/crypto/eddsa_test.go index 1bd381ac9..027c4697a 100644 --- a/crypto/eddsa_test.go +++ b/crypto/eddsa_test.go @@ -1,6 +1,7 @@ package crypto import ( + "crypto/ed25519" "crypto/x509" "encoding/pem" "fmt" @@ -11,8 +12,8 @@ import ( "github.com/stretchr/testify/require" ) -func TestEDDSAGenerateKey(t *testing.T) { - key, err := EDDSAGenerateKey() +func TestEd25519GenerateKey(t *testing.T) { + key, err := Ed25519GenerateKey() require.NoError(t, err) assert.True(t, strings.HasPrefix(string(key), "-----BEGIN PRIVATE KEY-----")) @@ -20,22 +21,27 @@ func TestEDDSAGenerateKey(t *testing.T) { "-----END PRIVATE KEY-----\n")) } -func TestEDDSADerivePublicKey(t *testing.T) { - _, err := EDDSADerivePublicKey(nil) +func TestEd25519DerivePublicKey(t *testing.T) { + _, err := Ed25519DerivePublicKey(nil) assert.Error(t, err) - _, err = EDDSADerivePublicKey([]byte(`-----BEGIN FOO----- + _, err = Ed25519DerivePublicKey([]byte(`-----BEGIN FOO----- -----END FOO-----`)) assert.Error(t, err) - priv, err := EDDSAGenerateKey() + priv, err := Ed25519GenerateKey() require.NoError(t, err) - pub, err := EDDSADerivePublicKey(priv) + pub, err := Ed25519DerivePublicKey(priv) require.NoError(t, err) block, _ := pem.Decode(pub) assert.True(t, block != nil) - secret, err := edDSADecodeFromPEM(priv) + 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)) } From 89db97cabbabc0b1d0d21c1d360c1dab88561749 Mon Sep 17 00:00:00 2001 From: horvski Date: Tue, 14 Nov 2023 13:51:16 -0700 Subject: [PATCH 3/6] Added changes from Dave's review --- crypto/eddsa.go | 21 ++++++----- docs-src/content/functions/crypto.yml | 51 +++++++++++++++++++++++++++ funcs/crypto.go | 49 +++++++++++++++++++++++++ funcs/crypto_test.go | 50 ++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 9 deletions(-) diff --git a/crypto/eddsa.go b/crypto/eddsa.go index 7f0e368ef..fcb5dd816 100644 --- a/crypto/eddsa.go +++ b/crypto/eddsa.go @@ -19,9 +19,12 @@ func Ed25519GenerateKey() ([]byte, error) { } // Ed25519GenerateKeyFromSeed returns a PEM encoded Ed25519 Private Key from -// `seed`. Panics if len(seed) is not SeedSize. +// `seed`. Returns error if len(seed) is not ed25519.SeedSize (32). func Ed25519GenerateKeyFromSeed(seed []byte) ([]byte, error) { - return pemEncodeEdPrivateKey(ed25519.NewKeyFromSeed(seed)) // Panics + if len(seed) != ed25519.SeedSize { + return nil, fmt.Errorf("Ed25519GenerateKeyFromSeed: 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 @@ -29,11 +32,11 @@ func Ed25519GenerateKeyFromSeed(seed []byte) ([]byte, error) { func Ed25519DerivePublicKey(privatekey []byte) ([]byte, error) { secret, err := ed25519DecodeFromPEM(privatekey) if err != nil { - return nil, fmt.Errorf("EDDSADerivePublicKey: could not decode private key") + 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("EDDSADerivePublicKey: failed to marshal PKIX public key: %w", err) + return nil, fmt.Errorf("MarshalPKIXPublicKey: failed to marshal PKIX public key: %w", err) } return pem.EncodeToMemory(&pem.Block{ Type: "PUBLIC KEY", @@ -45,7 +48,7 @@ func Ed25519DerivePublicKey(privatekey []byte) ([]byte, error) { func pemEncodeEdPrivateKey(secret ed25519.PrivateKey) ([]byte, error) { der, err := x509.MarshalPKCS8PrivateKey(secret) if err != nil { - return nil, fmt.Errorf("pemEncodeEdPrivateKey: failed to marshal ECDSA private key: %w", err) + return nil, fmt.Errorf("MarshalPKCS8PrivateKey: failed to marshal ed25519 private key: %w", err) } block := &pem.Block{ Type: "PRIVATE KEY", @@ -54,7 +57,7 @@ func pemEncodeEdPrivateKey(secret ed25519.PrivateKey) ([]byte, error) { buf := &bytes.Buffer{} err = pem.Encode(buf, block) if err != nil { - return nil, fmt.Errorf("pemEncodeEdPrivateKey: failed to encode generated EDDSA private key: pem encoding failed: %w", err) + return nil, fmt.Errorf("Encode: failed to encode generated ed25519 private key: PEM encoding failed: %w", err) } return buf.Bytes(), nil } @@ -64,15 +67,15 @@ func pemEncodeEdPrivateKey(secret ed25519.PrivateKey) ([]byte, error) { func ed25519DecodeFromPEM(privatekey []byte) (ed25519.PrivateKey, error) { block, _ := pem.Decode(privatekey) if block == nil { - return nil, fmt.Errorf("ed25519DecodeFromPEM: failed to read key: no key found") + return nil, fmt.Errorf("Decode: failed to read key") } priv, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { - return nil, fmt.Errorf("ed25519DecodeFromPEM: invalid private key: %w", err) + return nil, fmt.Errorf("ParsePKCS8PrivateKey: invalid private key: %w", err) } secret, ok := priv.(ed25519.PrivateKey) if !ok { - return nil, fmt.Errorf("ed25519DecodeFromPEM: invalid private key: %w", err) + return nil, fmt.Errorf("ed25519DecodeFromPEM: invalid ed25519 Private Key - given type: %T", priv) } return secret, nil } diff --git a/docs-src/content/functions/crypto.yml b/docs-src/content/functions/crypto.yml index f7640baf3..233c7c666 100644 --- a/docs-src/content/functions/crypto.yml +++ b/docs-src/content/functions/crypto.yml @@ -158,6 +158,57 @@ funcs: +hIz6+EUt/Db51awO7iCuRly5L4TZ+CnMAsIbtUOqsqwSQDtv0AclAuogmCst75o aztsmrD79OXXnhUlURI= -----END PUBLIC KEY----- + - name: crypto.Ed25519GenerateKey + experimental: true + released: v3.11.5 + description: | + Generate a new Ed25519 Private Key and output in + PEM-encoded PKCS#8 ASN.1 DER form. + pipeline: true + examples: + - | + $ gomplate -i '{{ crypto.Ed25519GenerateKey }}' + -----BEGIN PRIVATE KEY----- + ... + - name: crypto.Ed25519GenerateKeyFromSeed + experimental: true + released: v3.11.5 + description: | + Generate a new Ed25519 Private Key from a random seed and output in + PEM-encoded PKCS#8 ASN.1 DER form. + pipeline: true + arguments: + - name: encoding + required: true + description: the encoding that the seed is in (`hex` or `base64`) + - name: seed + reqruired: true + description: the random seed encoded in either base64 or hex + examples: + - | + $ gomplate -i '{{ crypto.Ed25519GenerateKeyFromSeed base64 MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA= }}' + -----BEGIN PRIVATE KEY----- + ... + - name: crypto.Ed25519DerivePublicKey + experimental: true + released: v3.11.5 + description: | + Derive a public key from an Ed25519 private key and output in PKIX + ASN.1 DER form. + pipeline: true + arguments: + - name: key + required: true + description: the private key to derive a public key from + examples: + - | + $ gomplate -i '{{ crypto.Ed25519GenerateKey | crypto.Ed25519DerivePublicKey }}' + -----BEGIN PUBLIC KEY----- + ... + - | + $ gomplate -d key=priv.pem -i '{{ crypto.Ed25519DerivePublicKey (include "key") }}' + -----BEGIN PUBLIC KEY----- + ...PK - name: crypto.PBKDF2 released: v2.3.0 description: | diff --git a/funcs/crypto.go b/funcs/crypto.go index 41c752c78..e3628fadf 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 90f6bdff5..4d1b56608 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() From a27b507ed74e1f73c2f9e56b608af2f8945f7164 Mon Sep 17 00:00:00 2001 From: horvski Date: Wed, 29 Nov 2023 12:07:27 -0700 Subject: [PATCH 4/6] Next review: Fixed casing on error messages for linter | Fixed version number --- crypto/{eddsa.go => ed25519.go} | 14 +++++++------- crypto/{eddsa_test.go => ed25519_test.go} | 0 docs-src/content/functions/crypto.yml | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) rename crypto/{eddsa.go => ed25519.go} (78%) rename crypto/{eddsa_test.go => ed25519_test.go} (100%) diff --git a/crypto/eddsa.go b/crypto/ed25519.go similarity index 78% rename from crypto/eddsa.go rename to crypto/ed25519.go index fcb5dd816..a6630ad79 100644 --- a/crypto/eddsa.go +++ b/crypto/ed25519.go @@ -13,7 +13,7 @@ import ( func Ed25519GenerateKey() ([]byte, error) { _, secret, err := ed25519.GenerateKey(rand.Reader) if err != nil { - return nil, fmt.Errorf("Ed25519GenerateKey: failed to generate EDDSA private key: %w", err) + return nil, fmt.Errorf("generateKey: %w", err) } return pemEncodeEdPrivateKey(secret) } @@ -22,7 +22,7 @@ func Ed25519GenerateKey() ([]byte, error) { // `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("Ed25519GenerateKeyFromSeed: incorrect seed size - given: %d wanted %d", 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)) } @@ -36,7 +36,7 @@ func Ed25519DerivePublicKey(privatekey []byte) ([]byte, error) { } b, err := x509.MarshalPKIXPublicKey(secret.Public()) if err != nil { - return nil, fmt.Errorf("MarshalPKIXPublicKey: failed to marshal PKIX public key: %w", err) + return nil, fmt.Errorf("marshalPKIXPublicKey: failed to marshal PKIX public key: %w", err) } return pem.EncodeToMemory(&pem.Block{ Type: "PUBLIC KEY", @@ -48,7 +48,7 @@ func Ed25519DerivePublicKey(privatekey []byte) ([]byte, error) { 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) + return nil, fmt.Errorf("marshalPKCS8PrivateKey: failed to marshal ed25519 private key: %w", err) } block := &pem.Block{ Type: "PRIVATE KEY", @@ -57,7 +57,7 @@ func pemEncodeEdPrivateKey(secret ed25519.PrivateKey) ([]byte, error) { buf := &bytes.Buffer{} err = pem.Encode(buf, block) if err != nil { - return nil, fmt.Errorf("Encode: failed to encode generated ed25519 private key: PEM encoding failed: %w", err) + return nil, fmt.Errorf("encode: PEM encoding: %w", err) } return buf.Bytes(), nil } @@ -67,11 +67,11 @@ func pemEncodeEdPrivateKey(secret ed25519.PrivateKey) ([]byte, error) { func ed25519DecodeFromPEM(privatekey []byte) (ed25519.PrivateKey, error) { block, _ := pem.Decode(privatekey) if block == nil { - return nil, fmt.Errorf("Decode: failed to read key") + 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) + return nil, fmt.Errorf("parsePKCS8PrivateKey: invalid private key: %w", err) } secret, ok := priv.(ed25519.PrivateKey) if !ok { diff --git a/crypto/eddsa_test.go b/crypto/ed25519_test.go similarity index 100% rename from crypto/eddsa_test.go rename to crypto/ed25519_test.go diff --git a/docs-src/content/functions/crypto.yml b/docs-src/content/functions/crypto.yml index 233c7c666..2f263ab0b 100644 --- a/docs-src/content/functions/crypto.yml +++ b/docs-src/content/functions/crypto.yml @@ -160,7 +160,7 @@ funcs: -----END PUBLIC KEY----- - name: crypto.Ed25519GenerateKey experimental: true - released: v3.11.5 + released: v4.0.0 description: | Generate a new Ed25519 Private Key and output in PEM-encoded PKCS#8 ASN.1 DER form. @@ -172,7 +172,7 @@ funcs: ... - name: crypto.Ed25519GenerateKeyFromSeed experimental: true - released: v3.11.5 + released: v4.0.0 description: | Generate a new Ed25519 Private Key from a random seed and output in PEM-encoded PKCS#8 ASN.1 DER form. @@ -191,7 +191,7 @@ funcs: ... - name: crypto.Ed25519DerivePublicKey experimental: true - released: v3.11.5 + released: v4.0.0 description: | Derive a public key from an Ed25519 private key and output in PKIX ASN.1 DER form. From dc2444a321a4fefb4a552f215409e404b3d03f7a Mon Sep 17 00:00:00 2001 From: horvski Date: Thu, 30 Nov 2023 12:54:22 -0700 Subject: [PATCH 5/6] Added Dave's suggestions in docs and updated built docs --- docs-src/content/functions/crypto.yml | 11 ++-- docs/content/functions/crypto.md | 94 +++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/docs-src/content/functions/crypto.yml b/docs-src/content/functions/crypto.yml index 2f263ab0b..33ba6976d 100644 --- a/docs-src/content/functions/crypto.yml +++ b/docs-src/content/functions/crypto.yml @@ -160,11 +160,10 @@ funcs: -----END PUBLIC KEY----- - name: crypto.Ed25519GenerateKey experimental: true - released: v4.0.0 + # released: v4.0.0 description: | Generate a new Ed25519 Private Key and output in PEM-encoded PKCS#8 ASN.1 DER form. - pipeline: true examples: - | $ gomplate -i '{{ crypto.Ed25519GenerateKey }}' @@ -172,7 +171,7 @@ funcs: ... - name: crypto.Ed25519GenerateKeyFromSeed experimental: true - released: v4.0.0 + # released: v4.0.0 description: | Generate a new Ed25519 Private Key from a random seed and output in PEM-encoded PKCS#8 ASN.1 DER form. @@ -182,16 +181,16 @@ funcs: required: true description: the encoding that the seed is in (`hex` or `base64`) - name: seed - reqruired: true + required: true description: the random seed encoded in either base64 or hex examples: - | - $ gomplate -i '{{ crypto.Ed25519GenerateKeyFromSeed base64 MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA= }}' + $ gomplate -i '{{ crypto.Ed25519GenerateKeyFromSeed "base64" MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA= }}' -----BEGIN PRIVATE KEY----- ... - name: crypto.Ed25519DerivePublicKey experimental: true - released: v4.0.0 + # released: v4.0.0 description: | Derive a public key from an Ed25519 private key and output in PKIX ASN.1 DER form. diff --git a/docs/content/functions/crypto.md b/docs/content/functions/crypto.md index 1720d5055..1a446c056 100644 --- a/docs/content/functions/crypto.md +++ b/docs/content/functions/crypto.md @@ -245,6 +245,100 @@ aztsmrD79OXXnhUlURI= -----END PUBLIC KEY----- ``` +## `crypto.Ed25519GenerateKey`_(unreleased)_ _(experimental)_ +**Unreleased:** _This function is in development, and not yet available in released builds of gomplate._ +**Experimental:** This function is [_experimental_][experimental] and may be enabled with the [`--experimental`][experimental] flag. + +[experimental]: ../config/#experimental + +Generate a new Ed25519 Private Key and output in +PEM-encoded PKCS#8 ASN.1 DER form. + +### Usage + +``` +crypto.Ed25519GenerateKey +``` + + +### Examples + +```console +$ gomplate -i '{{ crypto.Ed25519GenerateKey }}' +-----BEGIN PRIVATE KEY----- +... +``` + +## `crypto.Ed25519GenerateKeyFromSeed`_(unreleased)_ _(experimental)_ +**Unreleased:** _This function is in development, and not yet available in released builds of gomplate._ +**Experimental:** This function is [_experimental_][experimental] and may be enabled with the [`--experimental`][experimental] flag. + +[experimental]: ../config/#experimental + +Generate a new Ed25519 Private Key from a random seed and output in +PEM-encoded PKCS#8 ASN.1 DER form. + +### Usage + +``` +crypto.Ed25519GenerateKeyFromSeed encoding seed +``` +``` +seed | crypto.Ed25519GenerateKeyFromSeed encoding +``` + +### Arguments + +| name | description | +|------|-------------| +| `encoding` | _(required)_ the encoding that the seed is in (`hex` or `base64`) | +| `seed` | _(required)_ the random seed encoded in either base64 or hex | + +### Examples + +```console +$ gomplate -i '{{ crypto.Ed25519GenerateKeyFromSeed "base64" MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA= }}' +-----BEGIN PRIVATE KEY----- +... +``` + +## `crypto.Ed25519DerivePublicKey`_(unreleased)_ _(experimental)_ +**Unreleased:** _This function is in development, and not yet available in released builds of gomplate._ +**Experimental:** This function is [_experimental_][experimental] and may be enabled with the [`--experimental`][experimental] flag. + +[experimental]: ../config/#experimental + +Derive a public key from an Ed25519 private key and output in PKIX +ASN.1 DER form. + +### Usage + +``` +crypto.Ed25519DerivePublicKey key +``` +``` +key | crypto.Ed25519DerivePublicKey +``` + +### Arguments + +| name | description | +|------|-------------| +| `key` | _(required)_ the private key to derive a public key from | + +### Examples + +```console +$ gomplate -i '{{ crypto.Ed25519GenerateKey | crypto.Ed25519DerivePublicKey }}' +-----BEGIN PUBLIC KEY----- +... +``` +```console +$ gomplate -d key=priv.pem -i '{{ crypto.Ed25519DerivePublicKey (include "key") }}' +-----BEGIN PUBLIC KEY----- +...PK +``` + ## `crypto.PBKDF2` Run the Password-Based Key Derivation Function #2 as defined in From 114c702789021c498df82a3043802fa04b9d5c95 Mon Sep 17 00:00:00 2001 From: horvski Date: Fri, 8 Dec 2023 16:19:19 -0700 Subject: [PATCH 6/6] Final push from Dave's review | Wrap crypto example in docs in quotes --- docs-src/content/functions/crypto.yml | 2 +- docs/content/functions/crypto.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs-src/content/functions/crypto.yml b/docs-src/content/functions/crypto.yml index 33ba6976d..3e5754fbb 100644 --- a/docs-src/content/functions/crypto.yml +++ b/docs-src/content/functions/crypto.yml @@ -185,7 +185,7 @@ funcs: description: the random seed encoded in either base64 or hex examples: - | - $ gomplate -i '{{ crypto.Ed25519GenerateKeyFromSeed "base64" MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA= }}' + $ gomplate -i '{{ crypto.Ed25519GenerateKeyFromSeed "base64" "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA=" }}' -----BEGIN PRIVATE KEY----- ... - name: crypto.Ed25519DerivePublicKey diff --git a/docs/content/functions/crypto.md b/docs/content/functions/crypto.md index 1a446c056..9f6393f17 100644 --- a/docs/content/functions/crypto.md +++ b/docs/content/functions/crypto.md @@ -297,7 +297,7 @@ seed | crypto.Ed25519GenerateKeyFromSeed encoding ### Examples ```console -$ gomplate -i '{{ crypto.Ed25519GenerateKeyFromSeed "base64" MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA= }}' +$ gomplate -i '{{ crypto.Ed25519GenerateKeyFromSeed "base64" "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA=" }}' -----BEGIN PRIVATE KEY----- ... ```