/
keyGen.go
176 lines (144 loc) · 4.34 KB
/
keyGen.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package skm
import (
"crypto/ed25519"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"golang.org/x/crypto/ssh"
mrand "math/rand"
)
func (key *Key) genKey() {
}
const (
algRsa = "rsa"
algEd25519 = "ed25519"
)
var algorithms = []string{algRsa, algEd25519}
// genKey 生成密钥对
// 返回值(私钥,公钥,错误信息)
func genKey(alg string) ([]byte, []byte, error) {
if alg == algRsa {
return genRsaKey(3072, "")
} else if alg == algEd25519 {
return genEd25519Key()
}
return nil, nil, errors.New(fmt.Sprintf("No algorithm: %s", alg))
}
// genRsaKey 生成rsa密钥对
// 返回值(私钥,公钥,错误信息)
func genRsaKey(bits int, passphrase string) ([]byte, []byte, error) {
if bits%1024 != 0 {
return nil, nil, errors.New("bits must be a multiple of 1024")
}
//生成私钥和公钥
privateKey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, nil, errors.New("Failed to generate key pair. ")
}
publicKey := &privateKey.PublicKey
//私钥格式化
privateKeyPem := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
}
if passphrase != "" {
privateKeyPem, err = x509.EncryptPEMBlock(rand.Reader, privateKeyPem.Type, privateKeyPem.Bytes, []byte(passphrase), x509.PEMCipherAES256)
if err != nil {
return nil, nil, errors.New("Failed to generate key pair. ")
}
}
privateKeyOutput := pem.EncodeToMemory(privateKeyPem)
//公钥格式化
sshPublicKey, err := ssh.NewPublicKey(publicKey)
publicKeyOutput := ssh.MarshalAuthorizedKey(sshPublicKey)
return privateKeyOutput, publicKeyOutput, nil
}
// genEd25519Key 生成ed25519密钥对
// 返回值(私钥,公钥,错误信息)
func genEd25519Key() ([]byte, []byte, error) {
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, nil, errors.New("Failed to generate key pair. ")
}
//私钥格式化
privateKeyPem := &pem.Block{
Type: "OPENSSH PRIVATE KEY",
Bytes: MarshalED25519PrivateKey(privateKey),
}
privateKeyOutput := pem.EncodeToMemory(privateKeyPem)
//公钥格式化
sshPublicKey, err := ssh.NewPublicKey(publicKey)
if err != nil {
return nil, nil, errors.New("Failed to generate key pair. ")
}
publicKeyOutput := ssh.MarshalAuthorizedKey(sshPublicKey)
return privateKeyOutput, publicKeyOutput, nil
}
// MarshalED25519PrivateKey
// From: https://github.com/mondoohq/cnquery/blob/main/motor/providers/ssh/keypair/edkey.go
func MarshalED25519PrivateKey(key ed25519.PrivateKey) []byte {
// Add our key header (followed by a null byte)
magic := append([]byte("openssh-key-v1"), 0)
var w struct {
CipherName string
KdfName string
KdfOpts string
NumKeys uint32
PubKey []byte
PrivKeyBlock []byte
}
// Fill out the private key fields
pk1 := struct {
Check1 uint32
Check2 uint32
Keytype string
Pub []byte
Priv []byte
Comment string
Pad []byte `ssh:"rest"`
}{}
// Set our check ints
ci := mrand.Uint32()
pk1.Check1 = ci
pk1.Check2 = ci
// Set our key type
pk1.Keytype = ssh.KeyAlgoED25519
// Add the pubkey to the optionally-encrypted block
pk, ok := key.Public().(ed25519.PublicKey)
if !ok {
// fmt.Fprintln(os.Stderr, "ed25519.PublicKey type assertion failed on an ed25519 public key. This should never ever happen.")
return nil
}
pubKey := []byte(pk)
pk1.Pub = pubKey
// Add our private key
pk1.Priv = []byte(key)
// Might be useful to put something in here at some point
pk1.Comment = ""
// Add some padding to match the encryption block size within PrivKeyBlock (without Pad field)
// 8 doesn't match the documentation, but that's what ssh-keygen uses for unencrypted keys. *shrug*
bs := 8
blockLen := len(ssh.Marshal(pk1))
padLen := (bs - (blockLen % bs)) % bs
pk1.Pad = make([]byte, padLen)
// Padding is a sequence of bytes like: 1, 2, 3...
for i := 0; i < padLen; i++ {
pk1.Pad[i] = byte(i + 1)
}
// Generate the pubkey prefix "\0\0\0\nssh-ed25519\0\0\0 "
prefix := []byte{0x0, 0x0, 0x0, 0x0b}
prefix = append(prefix, []byte(ssh.KeyAlgoED25519)...)
prefix = append(prefix, []byte{0x0, 0x0, 0x0, 0x20}...)
// Only going to support unencrypted keys for now
w.CipherName = "none"
w.KdfName = "none"
w.KdfOpts = ""
w.NumKeys = 1
w.PubKey = append(prefix, pubKey...)
w.PrivKeyBlock = ssh.Marshal(pk1)
magic = append(magic, ssh.Marshal(w)...)
return magic
}