如何从Java生成ssh兼容的id_rsa(.pub)

我正在寻找一种以Java编程方式创建ssh兼容的id_rsa和id_rsa.pub文件的方法。

我创建了KeyPair:

KeyPairGenerator generator; generator = KeyPairGenerator.getInstance("RSA"); // or: generator = KeyPairGenerator.getInstance("DSA"); generator.initialize(2048); keyPair = generator.genKeyPair(); 

我无法弄清楚如何在KeyPair中创建PrivateKey和PublicKey的String表示。

ssh使用的密钥格式在RFC#4253中定义。 RSA公钥的格式如下:

  string "ssh-rsa" mpint e /* key public exponent */ mpint n /* key modulus */ 

所有数据类型编码都在RFC#4251的 #5部分中定义。 string和mpint(多个精度整数)类型以这种方式编码:

  4-bytes word: data length (unsigned big-endian 32 bits integer) n bytes : binary representation of the data 

例如,字符串“ssh-rsa”的编码是:

  byte[] data = new byte[] {0, 0, 0, 7, 's', 's', 'h', '-', 'r', 's', 'a'}; 

对公众进行编码:

  public byte[] encodePublicKey(RSAPublicKey key) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); /* encode the "ssh-rsa" string */ byte[] sshrsa = new byte[] {0, 0, 0, 7, 's', 's', 'h', '-', 'r', 's', 'a'}; out.write(sshrsa); /* Encode the public exponent */ BigInteger e = key.getPublicExponent(); byte[] data = e.toByteArray(); encodeUInt32(data.length, out); out.write(data); /* Encode the modulus */ BigInteger m = key.getModulus(); data = m.toByteArray(); encodeUInt32(data.length, out); out.write(data); return out.toByteArray(); } public void encodeUInt32(int value, OutputStream out) throws IOException { byte[] tmp = new byte[4]; tmp[0] = (byte)((value >>> 24) & 0xff); tmp[1] = (byte)((value >>> 16) & 0xff); tmp[2] = (byte)((value >>> 8) & 0xff); tmp[3] = (byte)(value & 0xff); out.write(tmp); } 

要有一个字符串représentation键只是在Base64中编码返回的字节数组。

对于私钥编码,有两种情况:

  1. 私钥不受密码保护。 在这种情况下,私钥根据PKCS#8标准进行编码,然后使用Base64进行编码。 通过在RSAPrivateKey上调用getEncodedRSAPrivateKey私钥的PKCS8编码。
  2. 私钥受密码保护。 在这种情况下,密钥编码是OpenSSH专用格式。 我不知道是否有关于此格式的任何文档(当然除了OpenSSH源代码)

gotoalberto的答案 (引用如下)引用了一个不同的问题,适用于RSA和DSA密钥:

如果要反转该过程,即将PublicKey Java对象编码为Linux authorized_keys条目格式,可以使用以下代码:

  /** * Encode PublicKey (DSA or RSA encoded) to authorized_keys like string * * @param publicKey DSA or RSA encoded * @param user username for output authorized_keys like string * @return authorized_keys like string * @throws IOException */ public static String encodePublicKey(PublicKey publicKey, String user) throws IOException { String publicKeyEncoded; if(publicKey.getAlgorithm().equals("RSA")){ RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; ByteArrayOutputStream byteOs = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(byteOs); dos.writeInt("ssh-rsa".getBytes().length); dos.write("ssh-rsa".getBytes()); dos.writeInt(rsaPublicKey.getPublicExponent().toByteArray().length); dos.write(rsaPublicKey.getPublicExponent().toByteArray()); dos.writeInt(rsaPublicKey.getModulus().toByteArray().length); dos.write(rsaPublicKey.getModulus().toByteArray()); publicKeyEncoded = new String( Base64.encodeBase64(byteOs.toByteArray())); return "ssh-rsa " + publicKeyEncoded + " " + user; } else if(publicKey.getAlgorithm().equals("DSA")){ DSAPublicKey dsaPublicKey = (DSAPublicKey) publicKey; DSAParams dsaParams = dsaPublicKey.getParams(); ByteArrayOutputStream byteOs = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(byteOs); dos.writeInt("ssh-dss".getBytes().length); dos.write("ssh-dss".getBytes()); dos.writeInt(dsaParams.getP().toByteArray().length); dos.write(dsaParams.getP().toByteArray()); dos.writeInt(dsaParams.getQ().toByteArray().length); dos.write(dsaParams.getQ().toByteArray()); dos.writeInt(dsaParams.getG().toByteArray().length); dos.write(dsaParams.getG().toByteArray()); dos.writeInt(dsaPublicKey.getY().toByteArray().length); dos.write(dsaPublicKey.getY().toByteArray()); publicKeyEncoded = new String( Base64.encodeBase64(byteOs.toByteArray())); return "ssh-dss " + publicKeyEncoded + " " + user; } else{ throw new IllegalArgumentException( "Unknown public key encoding: " + publicKey.getAlgorithm()); } } 

任何PublicKey类型(RSA,DSA等)的通用解决方案都是使用SSHJ的单线程:

 byte[] b = new Buffer.PlainBuffer().putPublicKey(key).getCompactData() 

然后使用Base64.getEncoder().encodeToString(b)进行编码。

正如Carsten所提到的,JSch可以轻松生成这些密钥对。 请参阅其示例KeyGen.java