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 }