Skip to content

Commit

Permalink
Added changes from Dave's review
Browse files Browse the repository at this point in the history
  • Loading branch information
horvski committed Nov 14, 2023
1 parent a4e5328 commit 5a09e14
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 9 deletions.
21 changes: 12 additions & 9 deletions crypto/eddsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,24 @@ 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
// `privatekey`.
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",
Expand All @@ -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",
Expand All @@ -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
}
Expand All @@ -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
}
51 changes: 51 additions & 0 deletions docs-src/content/functions/crypto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down
49 changes: 49 additions & 0 deletions funcs/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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) {
Expand Down
50 changes: 50 additions & 0 deletions funcs/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package funcs

import (
"context"
"encoding/base64"
"strconv"
"strings"
"testing"
Expand Down Expand Up @@ -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()

Expand Down

0 comments on commit 5a09e14

Please sign in to comment.