Java 如何以Putty或Puttygen可读格式导出(PKCS#8?)私钥?

Java 如何以Putty或Puttygen可读格式导出(PKCS#8?)私钥?,java,putty,ssh-keys,Java,Putty,Ssh Keys,我正在编写一个工具,使用AWS Java API创建新的Amazon Web服务服务器。创建服务器时,必须指定AWS存储在帐户中的公钥中要使用的SSH密钥对。您可以自己生成密钥对并导入公钥,也可以让AWS生成密钥对并下载私钥 我试图自己生成密钥对,将公钥导入AWS,使用新注册的密钥对条目启动新服务器,并在本地保存私钥。然后我想使用Putty将ssh连接到我的新服务器中,使用私钥,可能首先通过Puttygen将其转换 到目前为止,我已经生成了我的密钥对,成功地将公钥导入AWS并启动了一个新服务器。

我正在编写一个工具,使用AWS Java API创建新的Amazon Web服务服务器。创建服务器时,必须指定AWS存储在帐户中的公钥中要使用的SSH密钥对。您可以自己生成密钥对并导入公钥,也可以让AWS生成密钥对并下载私钥

我试图自己生成密钥对,将公钥导入AWS,使用新注册的密钥对条目启动新服务器,并在本地保存私钥。然后我想使用Putty将ssh连接到我的新服务器中,使用私钥,可能首先通过Puttygen将其转换

到目前为止,我已经生成了我的密钥对,成功地将公钥导入AWS并启动了一个新服务器。然而,我无法以Putty或Puttygen可以接受的任何格式导出私钥

以下是生成密钥对并保存私钥的代码:

SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
random.nextBytes(new byte[]{}); //toss out the first result to ensure it seeds randomly from the system.

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(KEY_LENGTH, random);
KeyPair keyPair = keyGen.genKeyPair();

BASE64Encoder encoder = new BASE64Encoder();

FileOutputStream out =  null;
File keyPath = new File(_keyStorageDir, "private.pem");
try
{
    out = new FileOutputStream(keyPath);
    out.write(encoder.encode(keyPair.getPrivate().getEncoded()).getBytes());
}
finally
{
    if(out != null)
        out.close();
}
但是,当我尝试在PuttyGen中导入密钥时,我得到“无法加载密钥(不是私钥)”。如果我尝试添加------BEGIN PRIVATE KEY------及其对应的页脚,我会得到“无法加载私钥(无法识别的密钥类型)。如果我尝试RSA私钥,我会得到“无法加载私钥(ASN.1解码失败)”

调用
keyPair.getPrivate().getFormat()
会产生“PKCS#8”。虽然我找到了使用OpenSSL工具将该格式转换为pem格式的参考资料,但我还没有找到任何关于如何在Java中实际实现的信息

如何以pem格式导出密钥,以便Puttygen可以读取它?

啊哈

诀窍是使用Bouncycastle的pem处理类。下面是一个有效的演示:

import org.bouncycastle.openssl.jcajce.JcaPEMWriter;

import java.io.File;
import java.io.FileWriter;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;

public class Main
{
    public static final int KEY_LENGTH = 2048;

    public static void main(String[] args) throws Exception
    {
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
        random.nextBytes(new byte[]{}); //toss out the first result to ensure it seeds randomly from the system.

        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(KEY_LENGTH, random);
        java.security.KeyPair keyPair = keyGen.genKeyPair();

        System.out.println("public format: " + keyPair.getPublic().getFormat());
        System.out.println("public algorithm: " + keyPair.getPublic().getAlgorithm());

        System.out.println("private format: " + keyPair.getPrivate().getFormat());
        System.out.println("private algorithm: " + keyPair.getPrivate().getAlgorithm());

        JcaPEMWriter writer =  null;
        File keyDir = new File("C:/misc/test_key");

        try
        {
            writer = new JcaPEMWriter(new FileWriter(new File(keyDir, "private_bc.pem")));
            writer.writeObject(keyPair.getPrivate());    
        }
        finally
        {
            if(writer != null)
                writer.close();
        }    
    }
}

Puttygen毫无怨言地打开生成的私钥!

现在不需要,但仅供参考或任何其他人使用,Puttygen导入:

  • OpenSSH使用的格式(一直到最近,默认情况下仍然如此) 在OpenSSL实现PKCS#8之前,它定义了哪些原始的aka“遗留”格式 --对于RSA,这是PKCS#1,相当于PKCS#8的一部分

  • 或者“商业”SSH.COM所使用的格式,它完全不同于PKCS#8

这样你就可以 从
RSAPrivateKey.getEncoded()
中获取PKCS#8,解析PKCS#8的字节以获取PKCS#1部分,并对其进行base64/PEMify。这就是您可能发现的使用
openssl rsa-in-pkcs8-out-rsa
的有效建议

但是您发现的方法(使用Bouncy)更简单。如果您想使用这些方法,DSA或ECDSA更容易 (最好仅使用Java 8+,它支持大于1024的DSA大小,符合186-3和当前的良好实践)