github.com/influx6/npkg@v0.8.8/ncrypt/ssh/ssh.go (about) 1 package ssh 2 3 import ( 4 "crypto/md5" 5 "crypto/rand" 6 "crypto/rsa" 7 "crypto/x509" 8 "encoding/base64" 9 "encoding/pem" 10 "errors" 11 "fmt" 12 "io" 13 "os" 14 "runtime" 15 16 gosh "golang.org/x/crypto/ssh" 17 ) 18 19 // nerror 20 var ( 21 ErrKeyGeneration = errors.New("Unable to generate key") 22 ErrValidation = errors.New("Unable to validate key") 23 ErrPublicKey = errors.New("Unable to convert public key") 24 ErrUnableToWriteFile = errors.New("Unable to write file") 25 ) 26 27 type KeyPair struct { 28 PrivateKey []byte 29 PublicKey []byte 30 } 31 32 // NewKeyPair generates a new SSH keypair 33 // This will return a private & public key encoded as DER. 34 func NewKeyPair() (keyPair *KeyPair, err error) { 35 priv, err := rsa.GenerateKey(rand.Reader, 2048) 36 if err != nil { 37 return nil, ErrKeyGeneration 38 } 39 40 if err := priv.Validate(); err != nil { 41 return nil, ErrValidation 42 } 43 44 privDer := x509.MarshalPKCS1PrivateKey(priv) 45 46 pubSSH, err := gosh.NewPublicKey(&priv.PublicKey) 47 if err != nil { 48 return nil, ErrPublicKey 49 } 50 51 return &KeyPair{ 52 PrivateKey: privDer, 53 PublicKey: gosh.MarshalAuthorizedKey(pubSSH), 54 }, nil 55 } 56 57 // WriteToFile writes keypair to files 58 func (kp *KeyPair) WriteToFile(privateKeyPath string, publicKeyPath string) error { 59 files := []struct { 60 File string 61 Type string 62 Value []byte 63 }{ 64 { 65 File: privateKeyPath, 66 Value: pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Headers: nil, Bytes: kp.PrivateKey}), 67 }, 68 { 69 File: publicKeyPath, 70 Value: kp.PublicKey, 71 }, 72 } 73 74 for _, v := range files { 75 f, err := os.Create(v.File) 76 if err != nil { 77 return ErrUnableToWriteFile 78 } 79 80 if _, err := f.Write(v.Value); err != nil { 81 return ErrUnableToWriteFile 82 } 83 84 // windows does not support chmod 85 switch runtime.GOOS { 86 case "darwin", "linux", "freebsd": 87 if err := f.Chmod(0600); err != nil { 88 return err 89 } 90 } 91 } 92 93 return nil 94 } 95 96 // Fingerprint calculates the fingerprint of the public key 97 func (kp *KeyPair) Fingerprint() string { 98 b, _ := base64.StdEncoding.DecodeString(string(kp.PublicKey)) 99 h := md5.New() 100 101 io.WriteString(h, string(b)) 102 103 return fmt.Sprintf("%x", h.Sum(nil)) 104 } 105 106 // GenerateSSHKey generates SSH keypair based on path of the private key 107 // The public key would be generated to the same path with ".pub" added 108 func GenerateSSHKey(path string) error { 109 if _, err := os.Stat(path); err != nil { 110 if !os.IsNotExist(err) { 111 return fmt.Errorf("Desired directory for SSH keys does not exist: %s", err) 112 } 113 114 kp, err := NewKeyPair() 115 if err != nil { 116 return fmt.Errorf("Error generating key pair: %s", err) 117 } 118 119 if err := kp.WriteToFile(path, fmt.Sprintf("%s.pub", path)); err != nil { 120 return fmt.Errorf("Error writing keys to file(s): %s", err) 121 } 122 } 123 124 return nil 125 }