将OpenSSH公钥转换为SSH2(RFC 4716)格式

7

主要问题就是这个。将 openssh 的公钥解析为符合rfc 4716 格式的密钥。但唯一的问题是,必须使用java实现。

使用ssh-keygen,只需输入一行命令:

ssh-keygen -e -f openssh_key.pub

很遗憾,我找不到其他用Java实现的方法。甚至没有提到转换所需的任何算法或步骤。所有这些方法都围绕着ssh-keygen本身的使用。当然,我可以使用java.exec调用命令,但那是最坏的情况。


例如openssh密钥(为了保留空格/换行符,已将其放入代码格式中):

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDwxgE7D3HYLYddNHLMFK8OfpRwwUSgxiB8fbecvkCUEktSpWikvsWTyCnl5p3uSmsGg/F1lwVPXuuVlQ4VZlYqMuEBEMRF9ADdXWWNxjO/Hd7688ow7ocncxl0xKXsH5Fc9GHvE8yfUh94F8Qm9x8M8Uux+XsNEvPG8KI/QUJWndIsHv+m//3nbEEqUTAlzsyY0mjHW/dPORhXcB5WeGH+cBRAhcp5JGKAq26TOsuNY8H+nrlxX6z03xbUN28HHdXv6uKZfpnVpl6tM0khxbh7F+tLYWeUIZ+nYaDBPINv8Mkd6Duqe/GOLtgVUIR76Adijok4w5oaKlTq27xzMurl kaushik@kaushik-HP

使用ssh-keygen进行解析:

---- BEGIN SSH2 PUBLIC KEY ----
Comment: "2048-bit RSA, converted by kaushik@kaushik-HP from OpenSSH"
AAAAB3NzaC1yc2EAAAADAQABAAABAQDwxgE7D3HYLYddNHLMFK8OfpRwwUSgxiB8fbecvk
CUEktSpWikvsWTyCnl5p3uSmsGg/F1lwVPXuuVlQ4VZlYqMuEBEMRF9ADdXWWNxjO/Hd76
88ow7ocncxl0xKXsH5Fc9GHvE8yfUh94F8Qm9x8M8Uux+XsNEvPG8KI/QUJWndIsHv+m//
3nbEEqUTAlzsyY0mjHW/dPORhXcB5WeGH+cBRAhcp5JGKAq26TOsuNY8H+nrlxX6z03xbU
N28HHdXv6uKZfpnVpl6tM0khxbh7F+tLYWeUIZ+nYaDBPINv8Mkd6Duqe/GOLtgVUIR76A
dijok4w5oaKlTq27xzMurl
---- END SSH2 PUBLIC KEY ----

更新:我已经在gist上创建了此转换的实现,欢迎有类似需求的人参考。


BouncyCastle提供了什么东西,也许是https://code.i-harness.com/en/q/ebddae? - Scary Wombat
@ScaryWombat:有趣的线索。值得进一步调查。我在SO上看到了同样关于C#的问题,所以没有深入探讨。 - Kaushik NP
3个回答

4
两种格式中的Base64数据是相同的--你不需要做任何花哨的事情。要在这些格式之间进行转换,您只需要添加/删除换行符(每70个字符)并更改标题/尾注即可。
请注意,两种格式都有一个注释--在OpenSSH密钥中为kaushik@kaushik-HP,在PEM密钥中以Comment:开头的行。它们都是完全可选的,不需要转换。

我已经想了一段时间了,但不确定。这个是“保证”的吗?我不希望在未来突然遇到某些边角情况并发现所有东西都失败。您能否详细说明一下您所说的“添加/删除换行符(每行70个字符)”-尤其是70个字符是什么意思? - Kaushik NP
你提到了 Base64。如果 openssh 密钥不是这样的话会发生什么?抱歉,我对 SSH 的标准还很陌生,所以需要确认一下。这是可能的吗? - Kaushik NP
是的,这是有保证的。这是这两种格式固有的特性。我能想到的唯一的其他问题是authorized_keys文件中的选项,它们实际上并不是密钥的一部分。 - user149341
1
换行:当转换为PEM格式时,只需要在每70个字符后添加 \n,或者删除换行符以转换为OpenSSH格式。就是这么简单。不需要担心数据是Base64编码;只需将其视为字符串即可。 - user149341
啊哈,好的,我很高兴得到了确认。我希望有其他人能够证实这一点,尤其是那些懂行的人:D 谢谢!在标记为已接受之前,我会等待一段时间的。也许在此期间会出现一些有趣的东西。 - Kaushik NP
已确认它完美运作,至少在目前的使用案例中。 - Kaushik NP

1
我不知道是该笑还是该哭,因为我最终找到了JSch库中所需的确切功能,还找到了许多其他功能。当然,在此之前,我已经自己实现了转换功能,这就是我为什么感到矛盾的原因。但现在,我很高兴在这个过程中学到了新东西。
使用JSch的KeyPair类的一个小例子:
生成私钥-公钥对(RSA):
JSch jSch = new JSch();
KeyPair keyPair = KeyPair.genKeyPair(jSch, KeyPair.RSA);

keyPair.writePrivateKey("privateKey"); //store private key in file - 'privateKey'
keyPair.writePublicKey("publicKey");   //store public key in file - 'publickKey'

将公钥转换为RFC 4716格式。
keyPair.writeSECSHPublicKey("ssh2Key"); //store ssh2 public key in file - 'ssh2Key'

0

基于duskwuff的答案,这是我编写的代码来进行转换:

public String convert(String rsaKey){
    String[] keyParts = rsaKey.split("\\s"); // header + content + comment
    if(keyParts.length < 2 || !keyParts[0].equals("ssh-rsa"))
        throw new IllegalArgumentException("The key "+rsaKey+" is not a properly formatted RSA key.");
    StringBuilder sb = new StringBuilder("---- BEGIN SSH2 PUBLIC KEY ----\n");
    final int rowLength = 70;
    final String keyContent = keyParts[1];
    for(int i=0; i*rowLength < keyContent.length(); i++){
        sb.append(keyContent, i*rowLength, Math.min((i+1)*rowLength, keyContent.length())).append('\n');
    }
    sb.append("---- END SSH2 PUBLIC KEY ----");
    return sb.toString();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接