@@ -2,8 +2,11 @@ package main
22
33import (
44 "context"
5+ "crypto/ecdsa"
56 "crypto/ed25519"
7+ "crypto/elliptic"
68 "crypto/rand"
9+ "crypto/x509"
710 "encoding/hex"
811 "encoding/json"
912 "fmt"
@@ -21,18 +24,34 @@ import (
2124// Identity struct to store node metadata
2225type InitiatorIdentity struct {
2326 NodeName string `json:"node_name"`
27+ Algorithm string `json:"algorithm,omitempty"`
2428 PublicKey string `json:"public_key"`
2529 CreatedAt string `json:"created_at"`
2630 CreatedBy string `json:"created_by"`
2731 MachineOS string `json:"machine_os"`
2832 MachineName string `json:"machine_name"`
2933}
3034
35+ // KeyData holds the generated key information
36+ type KeyData struct {
37+ PublicKeyHex string
38+ PrivateKeyHex string
39+ }
40+
3141func generateInitiatorIdentity (ctx context.Context , c * cli.Command ) error {
3242 nodeName := c .String ("node-name" )
3343 outputDir := c .String ("output-dir" )
3444 encrypt := c .Bool ("encrypt" )
3545 overwrite := c .Bool ("overwrite" )
46+ algorithm := c .String ("algorithm" )
47+
48+ if algorithm == "" {
49+ algorithm = "ed25519"
50+ }
51+
52+ if algorithm != "ed25519" && algorithm != "p256" {
53+ return fmt .Errorf ("invalid algorithm: %s. Must be 'ed25519' or 'p256'" , algorithm )
54+ }
3655
3756 // Create output directory if it doesn't exist
3857 if err := os .MkdirAll (outputDir , 0750 ); err != nil {
@@ -46,7 +65,10 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
4665
4766 // Check for existing identity file
4867 if _ , err := os .Stat (identityPath ); err == nil && ! overwrite {
49- return fmt .Errorf ("identity file already exists: %s (use --overwrite to force)" , identityPath )
68+ return fmt .Errorf (
69+ "identity file already exists: %s (use --overwrite to force)" ,
70+ identityPath ,
71+ )
5072 }
5173
5274 // Check for existing key files
@@ -56,19 +78,26 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
5678
5779 if encrypt {
5880 if _ , err := os .Stat (encKeyPath ); err == nil && ! overwrite {
59- return fmt .Errorf ("encrypted key file already exists: %s (use --overwrite to force)" , encKeyPath )
81+ return fmt .Errorf (
82+ "encrypted key file already exists: %s (use --overwrite to force)" ,
83+ encKeyPath ,
84+ )
6085 }
6186 }
6287
63- // Generate Ed25519 keypair
64- pubKey , privKeyFull , err := ed25519 .GenerateKey (rand .Reader )
65- if err != nil {
66- return fmt .Errorf ("failed to generate Ed25519 keypair: %w" , err )
88+ // Generate keys based on algorithm
89+ var keyData KeyData
90+ var err error
91+
92+ if algorithm == "ed25519" {
93+ keyData , err = generateEd25519Keys ()
94+ } else {
95+ keyData , err = generateP256Keys ()
6796 }
6897
69- // Extract 32-byte seed
70- privKeySeed := privKeyFull . Seed ( )
71- privHex := hex . EncodeToString ( privKeySeed )
98+ if err != nil {
99+ return fmt . Errorf ( "failed to generate %s keys: %w" , algorithm , err )
100+ }
72101
73102 // Get current user
74103 currentUser , err := user .Current ()
@@ -85,7 +114,8 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
85114 // Create Identity object
86115 identity := InitiatorIdentity {
87116 NodeName : nodeName ,
88- PublicKey : hex .EncodeToString (pubKey ),
117+ Algorithm : algorithm ,
118+ PublicKey : keyData .PublicKeyHex ,
89119 CreatedAt : time .Now ().UTC ().Format (time .RFC3339 ),
90120 CreatedBy : currentUser .Username ,
91121 MachineOS : runtime .GOOS ,
@@ -136,7 +166,7 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
136166 }
137167
138168 // Write the encrypted private key
139- if _ , err := identityWriter .Write ([]byte (privHex )); err != nil {
169+ if _ , err := identityWriter .Write ([]byte (keyData . PrivateKeyHex )); err != nil {
140170 return fmt .Errorf ("failed to write encrypted private key: %w" , err )
141171 }
142172
@@ -152,7 +182,7 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
152182 fmt .Println ("WARNING: You are generating the private key without encryption." )
153183 fmt .Println ("This is less secure. Consider using --encrypt flag for better security." )
154184
155- if err := os .WriteFile (keyPath , []byte (privHex ), 0600 ); err != nil {
185+ if err := os .WriteFile (keyPath , []byte (keyData . PrivateKeyHex ), 0600 ); err != nil {
156186 return fmt .Errorf ("failed to save private key: %w" , err )
157187 }
158188 }
@@ -162,3 +192,42 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
162192 fmt .Println ("- Identity JSON:" , identityPath )
163193 return nil
164194}
195+
196+ // generateEd25519Keys generates Ed25519 keypair
197+ func generateEd25519Keys () (KeyData , error ) {
198+ pubKey , privKeyFull , err := ed25519 .GenerateKey (rand .Reader )
199+ if err != nil {
200+ return KeyData {}, err
201+ }
202+
203+ privKeySeed := privKeyFull .Seed ()
204+ return KeyData {
205+ PublicKeyHex : hex .EncodeToString (pubKey ),
206+ PrivateKeyHex : hex .EncodeToString (privKeySeed ),
207+ }, nil
208+ }
209+
210+ // generateP256Keys generates P-256 keypair
211+ func generateP256Keys () (KeyData , error ) {
212+ privateKey , err := ecdsa .GenerateKey (elliptic .P256 (), rand .Reader )
213+ if err != nil {
214+ return KeyData {}, err
215+ }
216+
217+ // Convert private key to PEM format
218+ privateKeyBytes , err := x509 .MarshalECPrivateKey (privateKey )
219+ if err != nil {
220+ return KeyData {}, err
221+ }
222+
223+ // Convert public key to DER format
224+ publicKeyBytes , err := x509 .MarshalPKIXPublicKey (& privateKey .PublicKey )
225+ if err != nil {
226+ return KeyData {}, err
227+ }
228+
229+ return KeyData {
230+ PublicKeyHex : hex .EncodeToString (publicKeyBytes ),
231+ PrivateKeyHex : hex .EncodeToString (privateKeyBytes ),
232+ }, nil
233+ }
0 commit comments