生成与openssh兼容的ed25519密钥对。

huangapple go评论83阅读模式
英文:

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 &quot;github.com/mikesmitty/edkey&quot;

pubKey, privKey, _ := ed25519.GenerateKey(rand.Reader)
publicKey, _ := ssh.NewPublicKey(pubKey)

pemKey := &amp;pem.Block{
	Type:  &quot;OPENSSH PRIVATE KEY&quot;,
	Bytes: edkey.MarshalED25519PrivateKey(privKey),  // &lt;- marshals ed25519 correctly
}
privateKey := pem.EncodeToMemory(pemKey)
authorizedKey := ssh.MarshalAuthorizedKey(publicKey)

_ = ioutil.WriteFile(&quot;id_ed25519&quot;, privateKey, 0600)
_ = ioutil.WriteFile(&quot;id_ed25519.pub&quot;, authorizedKey, 0644)

huangapple
  • 本文由 发表于 2022年4月13日 07:19:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/71850135.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定