github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/crypto/ed25519.go (about) 1 // Copyright 2017-2019 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package crypto 6 7 import ( 8 "crypto/rand" 9 "crypto/x509" 10 "encoding/pem" 11 "errors" 12 "os" 13 14 "golang.org/x/crypto/ed25519" 15 ) 16 17 var ( 18 // PubKeyIdentifier is the PEM public key identifier 19 PubKeyIdentifier = "PUBLIC KEY" 20 // PrivKeyIdentifier is the PEM private key identifier 21 PrivKeyIdentifier = "PRIVATE KEY" 22 // PEMCipher is the PEM encryption algorithm 23 PEMCipher = x509.PEMCipherAES256 24 // PubKeyFilePermissions are the public key file perms 25 PubKeyFilePermissions os.FileMode = 0o644 26 // PrivKeyFilePermissions are the private key file perms 27 PrivKeyFilePermissions os.FileMode = 0o600 28 ) 29 30 // LoadPublicKeyFromFile loads PEM formatted ED25519 public key from file. 31 func LoadPublicKeyFromFile(publicKeyPath string) ([]byte, error) { 32 x509PEM, err := os.ReadFile(publicKeyPath) 33 if err != nil { 34 return nil, err 35 } 36 37 // Parse x509 PEM file 38 var block *pem.Block 39 for { 40 block, x509PEM = pem.Decode(x509PEM) 41 if block == nil { 42 return nil, errors.New("can't decode PEM file") 43 } 44 if block.Type == PubKeyIdentifier { 45 break 46 } 47 } 48 49 return block.Bytes, nil 50 } 51 52 // LoadPrivateKeyFromFile loads PEM formatted ED25519 private key from file. 53 func LoadPrivateKeyFromFile(privateKeyPath string, password []byte) ([]byte, error) { 54 x509PEM, err := os.ReadFile(privateKeyPath) 55 if err != nil { 56 return nil, err 57 } 58 59 // Parse x509 PEM file 60 var block *pem.Block 61 for { 62 block, x509PEM = pem.Decode(x509PEM) 63 if block == nil { 64 return nil, errors.New("can't decode PEM file") 65 } 66 if block.Type == PrivKeyIdentifier { 67 break 68 } 69 } 70 71 // Check for encrypted PEM format 72 if x509.IsEncryptedPEMBlock(block) { 73 decryptedKey, err := x509.DecryptPEMBlock(block, password) 74 if err != nil { 75 return nil, err 76 } 77 return decryptedKey, nil 78 } 79 80 return block.Bytes, nil 81 } 82 83 // GeneratED25519Key generates a ED25519 keypair 84 func GeneratED25519Key(password []byte, privateKeyFilePath string, publicKeyFilePath string) error { 85 pubKey, privKey, err := ed25519.GenerateKey(rand.Reader) 86 if err != nil { 87 return err 88 } 89 90 privBlock := &pem.Block{ 91 Type: "PRIVATE KEY", 92 Bytes: privKey, 93 } 94 95 pubBlock := &pem.Block{ 96 Type: "PUBLIC KEY", 97 Bytes: pubKey, 98 } 99 100 var privateKey []byte 101 if len(password) < 1 { 102 encrypted, err := x509.EncryptPEMBlock(rand.Reader, privBlock.Type, privBlock.Bytes, password, PEMCipher) 103 if err != nil { 104 return err 105 } 106 privateKey = pem.EncodeToMemory(encrypted) 107 } else { 108 privateKey = pem.EncodeToMemory(privBlock) 109 } 110 111 if err := os.WriteFile(privateKeyFilePath, privateKey, PrivKeyFilePermissions); err != nil { 112 return err 113 } 114 115 return os.WriteFile(publicKeyFilePath, pem.EncodeToMemory(pubBlock), PubKeyFilePermissions) 116 }