github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/crypto/ed25519.go (about)

     1  package crypto
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ed25519"
     6  	"crypto/rand"
     7  	"crypto/x509"
     8  	"encoding/pem"
     9  	"fmt"
    10  )
    11  
    12  // Ed25519GenerateKey returns a random PEM encoded Ed25519 Private Key.
    13  func Ed25519GenerateKey() ([]byte, error) {
    14  	_, secret, err := ed25519.GenerateKey(rand.Reader)
    15  	if err != nil {
    16  		return nil, fmt.Errorf("generateKey: %w", err)
    17  	}
    18  	return pemEncodeEdPrivateKey(secret)
    19  }
    20  
    21  // Ed25519GenerateKeyFromSeed returns a PEM encoded Ed25519 Private Key from
    22  // `seed`. Returns error if len(seed) is not ed25519.SeedSize (32).
    23  func Ed25519GenerateKeyFromSeed(seed []byte) ([]byte, error) {
    24  	if len(seed) != ed25519.SeedSize {
    25  		return nil, fmt.Errorf("generateKeyFromSeed: incorrect seed size - given: %d wanted %d", len(seed), ed25519.SeedSize)
    26  	}
    27  	return pemEncodeEdPrivateKey(ed25519.NewKeyFromSeed(seed))
    28  }
    29  
    30  // Ed25519DerivePublicKey returns an ed25519 Public Key from given PEM encoded
    31  // `privatekey`.
    32  func Ed25519DerivePublicKey(privatekey []byte) ([]byte, error) {
    33  	secret, err := ed25519DecodeFromPEM(privatekey)
    34  	if err != nil {
    35  		return nil, fmt.Errorf("ed25519DecodeFromPEM: could not decode private key: %w", err)
    36  	}
    37  	b, err := x509.MarshalPKIXPublicKey(secret.Public())
    38  	if err != nil {
    39  		return nil, fmt.Errorf("marshalPKIXPublicKey: failed to marshal PKIX public key: %w", err)
    40  	}
    41  	return pem.EncodeToMemory(&pem.Block{
    42  		Type:  "PUBLIC KEY",
    43  		Bytes: b,
    44  	}), nil
    45  }
    46  
    47  // pemEncodeEdPrivateKey is a convenience function for PEM encoding `secret`.
    48  func pemEncodeEdPrivateKey(secret ed25519.PrivateKey) ([]byte, error) {
    49  	der, err := x509.MarshalPKCS8PrivateKey(secret)
    50  	if err != nil {
    51  		return nil, fmt.Errorf("marshalPKCS8PrivateKey: failed to marshal ed25519 private key: %w", err)
    52  	}
    53  	block := &pem.Block{
    54  		Type:  "PRIVATE KEY",
    55  		Bytes: der,
    56  	}
    57  	buf := &bytes.Buffer{}
    58  	err = pem.Encode(buf, block)
    59  	if err != nil {
    60  		return nil, fmt.Errorf("encode: PEM encoding: %w", err)
    61  	}
    62  	return buf.Bytes(), nil
    63  }
    64  
    65  // ed25519DecodeFromPEM returns an ed25519.PrivateKey from given PEM encoded
    66  // `privatekey`.
    67  func ed25519DecodeFromPEM(privatekey []byte) (ed25519.PrivateKey, error) {
    68  	block, _ := pem.Decode(privatekey)
    69  	if block == nil {
    70  		return nil, fmt.Errorf("decode: failed to read key")
    71  	}
    72  	priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
    73  	if err != nil {
    74  		return nil, fmt.Errorf("parsePKCS8PrivateKey: invalid private key: %w", err)
    75  	}
    76  	secret, ok := priv.(ed25519.PrivateKey)
    77  	if !ok {
    78  		return nil, fmt.Errorf("ed25519DecodeFromPEM: invalid ed25519 Private Key - given type: %T", priv)
    79  	}
    80  	return secret, nil
    81  }