如何从 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 03:04:34  来源:igfitidea点击:

How to generate ssh compatible id_rsa(.pub) from Java

javasshpublic-key-encryptionopenssh

提问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:

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

  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 getEncodedon 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)
  1. 私钥不受密码保护。在这种情况下,私钥根据 PKCS#8 标准进行编码,然后使用 Base64 进行编码。它可以通过打电话来获得私钥的PKCS8编码getEncodedRSAPrivateKey
  2. 私钥受密码保护。在这种情况下,密钥编码是 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 PublicKeyJava object to a Linux authorized_keysentry 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 PublicKeytype (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).