Go语言 生成与openssh兼容的ed25519密钥对

t40tm48m  于 2023-02-06  发布在  Go
关注(0)|答案(1)|浏览(410)

我想在go中使用ed25519生成一个与openssh兼容的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 PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEINV+5Hyey1xTblwsVGfGmDCMdZgKQdhf1ublkGO2Qaf+
-----END PRIVATE KEY-----

我怎么会得到这样的结果:

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAxIu+ndqJXpEJLk5c2qsjPvUybP8OANZlSqLaOau9ZCQAAAKCocC5dqHAu
[...]
AAAEChVq8FJPCYbKnNFFuISac83mzF+DDFCDrLd9Xva9fQ2zEi76d2olekQkuTlzaqyM+9
TJs/w4A1mVKoto5q71kJAAAAFnlvdXJfZW1haWxAZXhhbXBsZS5jb20BAgMEBQYH
-----END OPENSSH PRIVATE KEY-----
1yjd4xko

1yjd4xko1#

是的,我也遇到过这种情况。
x509包不支持以openssh使用的格式编组ed25519密钥类型,因此,正如您所发现的,这段代码--它与其他密钥类型一起工作--对ed25519密钥失败:

bytes, err := x509.MarshalPKCS8PrivateKey(privateKey)  // produces invalid output for ed25519 keys

有一个repo(github.com/mikesmitty/edkey),它带有一个helper函数edkey.MarshalED25519PrivateKey来解决这个问题:
/* 将ed 25519私钥写入新的OpenSSH私钥格式。我不知道为什么这还没有在任何地方实现,除了以OpenSSH私钥格式将其写入磁盘之外,您似乎可以做任何事情。*/
它看起来是以openssh源代码为模型的:sshkey.c sshkey私有目标对象二进制大对象
因此,要么将该helper函数复制到代码中(建议使用2017中的repo,因为它已经存在了好几年),要么将其作为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)

相关问题