如何从 Java 生成与 ssh 兼容的 id_rsa(.pub)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3706177/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to generate ssh compatible id_rsa(.pub) from Java
提问by Carsten
I'm looking for a way to programmatically create ssh compatible id_rsa and id_rsa.pub files in Java.
我正在寻找一种在 Java 中以编程方式创建与 ssh 兼容的 id_rsa 和 id_rsa.pub 文件的方法。
I got as far as creating the KeyPair:
我已经创建了 KeyPair:
KeyPairGenerator generator;
generator = KeyPairGenerator.getInstance("RSA");
// or: generator = KeyPairGenerator.getInstance("DSA");
generator.initialize(2048);
keyPair = generator.genKeyPair();
I can't figure out however how to create the String representation of the PrivateKey and PublicKey in the KeyPair.
但是,我不知道如何在 KeyPair 中创建 PrivateKey 和 PublicKey 的字符串表示。
回答by Jcs
The key format used by ssh is defined in the RFC #4253. The format for RSA public key is the following :
ssh 使用的密钥格式在RFC #4253 中定义。RSA 公钥的格式如下:
string "ssh-rsa"
mpint e /* key public exponent */
mpint n /* key modulus */
All data type encoding is defined in the section #5 of RFC #4251. string and mpint (multiple precision integer) types are encoded this way :
所有数据类型编码都在RFC #4251 的#5 部分中定义。string 和 mpint(多精度整数)类型以这种方式编码:
4-bytes word: data length (unsigned big-endian 32 bits integer)
n bytes : binary representation of the data
for instance, the encoding of the string "ssh-rsa" is:
例如,字符串“ssh-rsa”的编码是:
byte[] data = new byte[] {0, 0, 0, 7, 's', 's', 'h', '-', 'r', 's', 'a'};
To encode the public :
对公众进行编码:
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);
}
To have a string représentation of the key just encode the returned byte array in Base64.
要获得密钥的字符串表示,只需在 Base64 中对返回的字节数组进行编码。
For the private key encoding there is two cases:
对于私钥编码,有两种情况:
- the private key is not protected by a password. In that case the private key is encoded according to the PKCS#8 standard and then encoded with Base64. It is possible to get the PKCS8 encoding of the private key by calling
getEncoded
onRSAPrivateKey
. - the private key is protected by a password. In that case the key encoding is an OpenSSH dedicated format. I don't know if there is any documentation on this format (except the OpenSSH source code of course)
- 私钥不受密码保护。在这种情况下,私钥根据 PKCS#8 标准进行编码,然后使用 Base64 进行编码。它可以通过打电话来获得私钥的PKCS8编码
getEncoded
上RSAPrivateKey
。 - 私钥受密码保护。在这种情况下,密钥编码是 OpenSSH 专用格式。不知道有没有关于这种格式的文档(当然OpenSSH源代码除外)
回答by ymnk
As Carsten has mentioned, JSch can generate those keypair easily. Refer to its example, KeyGen.java
正如 Carsten 所提到的,JSch 可以轻松生成这些密钥对。参考它的例子,KeyGen.java
回答by user314104
gotoalberto's answer(quoted below) for a different question works for both RSA and DSA keys:
gotoalberto对不同问题的回答(引用如下)适用于 RSA 和 DSA 密钥:
If you want reverse the process, i.e. encode a
PublicKey
Java object to a Linuxauthorized_keys
entry format, one can use this code:/** * 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
即将 Java 对象编码为 Linuxauthorized_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()); } }
回答by Raul Santelices
The generic solution for any PublicKey
type (RSA, DSA, etc.) is a one-liner using SSHJ:
任何PublicKey
类型(RSA、DSA 等)的通用解决方案是使用 SSHJ 的单行解决方案:
byte[] b = new Buffer.PlainBuffer().putPublicKey(key).getCompactData()
and then encode using Base64.getEncoder().encodeToString(b)
.
然后使用Base64.getEncoder().encodeToString(b)
.