英文:
Generate ed25519 key-pair compatible with openssh
问题
我想使用Go语言生成与OpenSSH兼容的ed25519 SSH密钥,以替代rsa.GenerateKey,因为GitHub不再支持它。
它应该等同于:
ssh-keygen -t ed25519 -C "your_email@example.com"
但是我找不到实现的方法。
目前,我有以下代码:
func GenerateSSHKeys() (*ED25519Keys, error) {
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, err
}
publicED25519Key, err := ssh.NewPublicKey(publicKey)
if err != nil {
return nil, err
}
pubKeyBytes := ssh.MarshalAuthorizedKey(publicED25519Key)
bytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return nil, err
}
privBlock := pem.Block{
Type: "PRIVATE KEY",
Headers: nil,
Bytes: bytes,
}
privatePEM := pem.EncodeToMemory(&privBlock)
return &ED25519Keys{
Public: pubKeyBytes,
Private: privatePEM,
}, nil
}
但是似乎私钥长度较短,并且我无法解释在使用它与git或argocd时出现的一些奇怪行为(有时可以工作,但大多数时候不行)。
如何生成类似以下的密钥:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAxIu+ndqJXpEJLk5c2qsjPvUybP8OANZlSqLaOau9ZCQAAAKCocC5dqHAu
[...]
AAAEChVq8FJPCYbKnNFFuISac83mzF+DDFCDrLd9Xva9fQ2zEi76d2olekQkuTlzaqyM+9
TJs/w4A1mVKoto5q71kJAAAAFnlvdXJfZW1haWxAZXhhbXBsZS5jb20BAgMEBQYH
-----END OPENSSH PRIVATE KEY-----
英文:
I want to generate an ssh key compatible with openssh using ed25519 in go to replace
rsa.GenerateKey since github does not support it anymore.
It should be the equivalent of:
ssh-keygen -t ed25519 -C "your_email@example.com"
But I can't find a way to do it.
For now, I have this code:
func GenerateSSHKeys() (*ED25519Keys, error) {
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, err
}
publicED25519Key, err := ssh.NewPublicKey(publicKey)
if err != nil {
return nil, err
}
pubKeyBytes := ssh.MarshalAuthorizedKey(publicED25519Key)
bytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return nil, err
}
privBlock := pem.Block{
Type: "PRIVATE KEY",
Headers: nil,
Bytes: bytes,
}
privatePEM := pem.EncodeToMemory(&privBlock)
return &ED25519Keys{
Public: pubKeyBytes,
Private: privatePEM,
}, nil
}
But it seems that the private key is shorter, and I can't explain some weird behavior that I have using it with git or argocd (sometimes it works, but most of the time no).
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEINV+5Hyey1xTblwsVGfGmDCMdZgKQdhf1ublkGO2Qaf+
-----END PRIVATE KEY-----
How can I end up with something like that :
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAxIu+ndqJXpEJLk5c2qsjPvUybP8OANZlSqLaOau9ZCQAAAKCocC5dqHAu
[...]
AAAEChVq8FJPCYbKnNFFuISac83mzF+DDFCDrLd9Xva9fQ2zEi76d2olekQkuTlzaqyM+9
TJs/w4A1mVKoto5q71kJAAAAFnlvdXJfZW1haWxAZXhhbXBsZS5jb20BAgMEBQYH
-----END OPENSSH PRIVATE KEY-----
答案1
得分: 10
是的,我也遇到了这个问题。
x509
包不支持以openssh
使用的格式对ed25519
密钥类型进行编组,所以正如你发现的那样,对于ed25519
密钥,这段代码会失败:
bytes, err := x509.MarshalPKCS8PrivateKey(privateKey) // 对于ed25519密钥产生无效的输出
有一个仓库(github.com/mikesmitty/edkey)提供了一个辅助函数edkey.MarshalED25519PrivateKey来解决这个问题:
/* 将ed25519私钥写入新的OpenSSH私钥格式。我不知道为什么还没有在任何地方实现这个功能,除了将其写入OpenSSH私钥格式之外,似乎你可以做任何事情。 */
它似乎是基于openssh
源代码的sshkey.c
sshkey_private_to_blob2。
因此,你可以将该辅助函数复制到你的代码中(推荐,因为该仓库的代码来自于2017
年,已经过时了几年),或者将其作为导入引用:
import "github.com/mikesmitty/edkey"
pubKey, privKey, _ := ed25519.GenerateKey(rand.Reader)
publicKey, _ := ssh.NewPublicKey(pubKey)
pemKey := &pem.Block{
Type: "OPENSSH PRIVATE KEY",
Bytes: edkey.MarshalED25519PrivateKey(privKey), // <- 正确地编组ed25519
}
privateKey := pem.EncodeToMemory(pemKey)
authorizedKey := ssh.MarshalAuthorizedKey(publicKey)
_ = ioutil.WriteFile("id_ed25519", privateKey, 0600)
_ = ioutil.WriteFile("id_ed25519.pub", authorizedKey, 0644)
希望对你有所帮助!
英文:
Yes, I've run into this as well.
The x509
package does not support marshaling ed25519
key types in the format used by openssh
, so as you've discovered, this code - which works with other key types - fails for ed25519
keys:
bytes, err := x509.MarshalPKCS8PrivateKey(privateKey) // produces invalid output for ed25519 keys
There is a repo (github.com/mikesmitty/edkey) with a helper function edkey.MarshalED25519PrivateKey to address this:
> /* Writes ed25519 private keys into the new OpenSSH private key
> format. I have no idea why this isn't implemented anywhere yet, you
> can do seemingly everything except write it to disk in the OpenSSH
> private key format. */
it seems to be modeled on the openssh source: sshkey.c
sshkey_private_to_blob2
So either copy that helper function into your code (recommended as repo from 2017
is several years old) or reference it as an import:
import "github.com/mikesmitty/edkey"
pubKey, privKey, _ := ed25519.GenerateKey(rand.Reader)
publicKey, _ := ssh.NewPublicKey(pubKey)
pemKey := &pem.Block{
Type: "OPENSSH PRIVATE KEY",
Bytes: edkey.MarshalED25519PrivateKey(privKey), // <- marshals ed25519 correctly
}
privateKey := pem.EncodeToMemory(pemKey)
authorizedKey := ssh.MarshalAuthorizedKey(publicKey)
_ = ioutil.WriteFile("id_ed25519", privateKey, 0600)
_ = ioutil.WriteFile("id_ed25519.pub", authorizedKey, 0644)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论