如何从 Java 生成 ssh 兼容的 id_rsa(.pub)
Posted
技术标签:
【中文标题】如何从 Java 生成 ssh 兼容的 id_rsa(.pub)【英文标题】:How to generate ssh compatible id_rsa(.pub) from Java 【发布时间】:2011-04-11 23:51:51 【问题描述】:我正在寻找一种在 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 的字符串表示形式。
【问题讨论】:
Given a Java ssh-rsa PublicKey, how can I build an SSH2 public key?的可能重复 【参考方案1】: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);
要对键进行字符串表示,只需在 Base64 中编码返回的字节数组。
对于私钥编码有两种情况:
-
私钥不受密码保护。在这种情况下,私钥根据 PKCS#8 标准进行编码,然后使用 Base64 进行编码。可以通过在
RSAPrivateKey
上调用getEncoded
来获取私钥的PKCS8编码。
私钥受密码保护。在这种情况下,密钥编码是 OpenSSH 专用格式。不知道有没有这种格式的文档(当然除了OpenSSH源代码)
【讨论】:
非常感谢。我还找到了 jsch (jcraft.com/jsch),一个提供此功能的免费库。 看来使用起来会更简单:MessageDigest.getInstance("MD5").digest(key.getEncoded())。 有没有办法以编程方式将Jsch 生成的ssh rsa-keys 转换回Java Cipher 可用于加密的格式?据我所知that requires openssh commands。openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key_file -nocrypt > pkcs8_key
但如果您无法访问 openssh 怎么办?
@MarkMikofski 您应该创建一个新问题以提高其知名度。【参考方案2】:
gotoalberto 的answer(以下引用)针对不同的问题适用于 RSA 和 DSA 密钥:
如果你想反转这个过程,即编码一个
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());
【讨论】:
就我个人而言,我更喜欢@ymnk 的回答,即使 gotoalberto 的解决方案更容易获得。为最有用的 Java 库之一点赞!【参考方案3】:正如 Carsten 所提到的,JSch 可以轻松生成这些密钥对。 参考它的例子,KeyGen.java
【讨论】:
【参考方案4】:任何PublicKey
类型(RSA、DSA 等)的通用解决方案是使用 SSHJ 的单线:
byte[] b = new Buffer.PlainBuffer().putPublicKey(key).getCompactData()
然后使用Base64.getEncoder().encodeToString(b)
进行编码。
【讨论】:
以上是关于如何从 Java 生成 ssh 兼容的 id_rsa(.pub)的主要内容,如果未能解决你的问题,请参考以下文章
gitlab HTTP Basic: Access denied问题解决方法