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

发布于 2024-09-18 15:21:30 字数 342 浏览 13 评论 0原文

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

我已经创建了密钥对:

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

但是我不知道如何在密钥对中创建私钥和公钥的字符串表示形式。

I'm looking for a way to programmatically create ssh compatible id_rsa and id_rsa.pub files in Java.

I got as far as creating the 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

深海夜未眠 2024-09-25 15:21:30

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

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

所有数据类型编码均在 RFC 的第 #5 节中定义#4251。 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 编码返回的字节数组。

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

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

The key format used by ssh is defined in the RFC #4253. The format for RSA public key is the following :

  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 :

  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:

  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.

For the private key encoding there is two cases:

  1. 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 on RSAPrivateKey.
  2. 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)
夜夜流光相皎洁 2024-09-25 15:21:30

gotoalberto答案(下面引用)针对另一个问题,适用于 RSA 和 DSA 密钥:

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

<前><代码> /**
*将公钥(DSA或RSA编码)编码为authorized_keys,如字符串
*
* @param publicKey DSA 或 RSA 编码
* @param user 用户名用于输出authorized_keys之类的字符串
* @returnauthorized_keys 类似字符串
* @抛出IOException
*/
公共静态字符串encodePublicKey(公共密钥公钥,字符串用户)
抛出 IOException {
字符串公钥编码;
if(publicKey.getAlgorithm().equals("RSA")){
RSAPublicKey rsaPublicKey = (RSAPublicKey) 公钥;
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());
公钥编码 = 新字符串(
Base64.encodeBase64(byteOs.toByteArray()));
返回“ssh-rsa”+publicKeyEncoded+“”+用户;
}
否则 if(publicKey.getAlgorithm().equals("DSA")){
DSAPublicKey dsaPublicKey = (DSAPublicKey) 公钥;
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());
公钥编码 = 新字符串(
Base64.encodeBase64(byteOs.toByteArray()));
返回“ssh-dss”+publicKeyEncoded+“”+用户;
}
别的{
抛出新的 IllegalArgumentException(
“未知的公钥编码:” + publicKey.getAlgorithm());
}
}

gotoalberto's answer (quoted below) for a different question works for both RSA and DSA keys:

If you want reverse the process, i.e. encode a PublicKey Java object
to a Linux authorized_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());
        }
    }
嗫嚅 2024-09-25 15:21:30

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

As Carsten has mentioned, JSch can generate those keypair easily.
Refer to its example, KeyGen.java

音盲 2024-09-25 15:21:30

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

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

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

The generic solution for any PublicKey type (RSA, DSA, etc.) is a one-liner using SSHJ:

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

and then encode using Base64.getEncoder().encodeToString(b).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文