当前位置: 首页 > 知识库问答 >
问题:

如何使用java 7将ssh rsa公钥转换为PEM PKCS#1公钥格式

西门鹏程
2023-03-14

我的公共在ssh-rsa是:

ssh rsa aaaab3nzac1yc2aaaaaadaqabaababaqclaxt5s/wux04oxbt9r59wcl45omau3m0063lfyja7ovqavr7/2kHtLF/LoCQCXSZMny8RTCGDjoXD7G/tGsyHFDHCI//Y1VDLE06AlDzrlu69DQY91 6gkhghgjh3sf6us5hxlihrbsflf8gwsprvqyuaof 39dnmddhyyygz0ce82ta/N8XPBWCP60 NDEDAYNJOSRGZDJKSUJNFNGJQTL6QKJJ8BW/P5lLJE1nbMm9BQD9G7glJk86qh1I/TJCNIJ6ON0M6KCDZV8Cu3SBGNEB433KJTPXXMJB6Vu5IverhyFPIb4HP9WLKA/LSzW ZIdvl/

我想把它转换成下面的PKCS#1格式

-----开始RSA公钥----MIIBCGKCAQEAOL7K8IJUPFKPDIMIOHXZTN npLzJGHr7QO09Mnz8Q1xFfv9Arr 3Eg2R7LdTMJ V2RK3EDRJWK8CWV5HVH7KXIDRQTW2Ouxy6PK9RXFAVAQ0CF2NI9 Y7VXASDOVNI8YZLW9SVR1EDJPZIH8/WTZ3KCJK5ACR5ACRSAYH6DDVM4PISQAKVBGN NCTPQ94PSPBENSQTPMNPO099VMU9KYB9F9KK9KK9KKK9KK9KKKK9K9KvB9K9K9KKKKbKvKvK9KvKKQVPP8TUTFUGK8NOKE7ABK6NCF8WMB8PHGOKZNZP5MALZPB1F4GBEXST GNIN4LWGRSM56ECEVQHKVRURRM9NODWQIDAQAB

-----结束RSA公钥-----

摘要:我想验证文件通过使用上面的公钥在java 7,因为我面临无效的密钥格式错误为ssh-rsa公钥请让我知道需要做什么。

请查找以下代码片段:

byte[] decoded;
        try {
        decoded = Base64.getDecoder().decode(publickeyStr);
        org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(decoded);
        BigInteger modulus = pkcs1PublicKey.getModulus();
        BigInteger publicExponent = pkcs1PublicKey.getPublicExponent();
        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
        KeyFactory kf;
        kf = KeyFactory.getInstance("RSA");
        PublicKey generatedPublic = kf.generatePublic(keySpec);
        System.out.printf("Modulus: %X%n", modulus);
        System.out.printf("Public exponent: %d ... 17? Why?%n", publicExponent);
        System.out.printf("See, Java class result: %s, is RSAPublicKey: %b%n", generatedPublic.getClass().getName(), generatedPublic instanceof RSAPublicKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

它给予以下例外:

java.lang.IllegalArgumentException: Illegal base64 character 2d
    at java.util.Base64$Decoder.decode0(Base64.java:714)
    at java.util.Base64$Decoder.decode(Base64.java:526)
    at java.util.Base64$Decoder.decode(Base64.java:549)
    at SignVerify.convertPublicPKCS1StrToPKCS8PublicKeyObj(SignVerify.java:136)
    at SignVerify.main(SignVerify.java:184)

共有1个答案

郎言
2023-03-14

我在java中找不到任何工具或解决方案可以做到这一点。所以,我阅读了RFC 4253的公钥格式描述和RFC 4251的mpint描述。RFC 4253的重要部件。第6.6节

 The "ssh-rsa" key format has the following specific encoding:

  string    "ssh-rsa"
  mpint     e
  mpint     n

Here the 'e' and 'n' parameters form the signature key blob.

和RFC 4251中的重要部分

  mpint

  Represents multiple precision integers in two's complement format,
  stored as a string, 8 bits per byte, MSB first.  Negative numbers
  have the value 1 as the most significant bit of the first byte of
  the data partition.  If the most significant bit would be set for
  a positive number, the number MUST be preceded by a zero byte.
  Unnecessary leading bytes with the value 0 or 255 MUST NOT be
  included.  The value zero MUST be stored as a string with zero
  bytes of data.

  By convention, a number that is used in modular computations in
  Z_n SHOULD be represented in the range 0 <= x < n.

     Examples:

     value (hex)        representation (hex)
     -----------        --------------------
     0                  00 00 00 00
     9a378f9b2e332a7    00 00 00 08 09 a3 78 f9 b2 e3 32 a7
     80                 00 00 00 02 00 80
     -1234              00 00 00 02 ed cc
     -deadbeef          00 00 00 05 ff 21 52 41 11

了解所有这些,编写代码将ssh rsa密钥转换为java格式很容易。

private static int SIZEOF_INT = 4;
private static String key1 = "AAAAB3NzaC1yc2EAAAADAQABAAABAQClAxT5S/WuX04OXBt9R59WcL45OmaU3M5U063lfyja7ovqaVR7/2kHtLF/LoCQCXSZMny8RTCGDjoXD7G/tGsyHFDHCI//Y1VDLE06AlDzrlu69DQY91+6gkhGjH3SF6us5hXlihrbSFLfAlSdkEs8gwSrspVQyuaOf+39dnMddhEDYYg+z0ce82ta/n8xPBWCp60nDEDayNjOsRgzDJKSujNfngjQTL1x6qKJj8BW/P5lLJE1nbMm9BQD9G7glJk86qh1I/tJCnij6On0m6KcdzVz8cU3sBgNeB433kGjJtpxXXmJB6Vuu5IverhyfpiB4hP9WlKa/LSzW+ZIdvl/";

@Test
public void convertkey() throws Exception {
    byte[] decoded = java.util.Base64.getDecoder().decode(key1);

    try {
        ByteBuffer byteBuffer = ByteBuffer.wrap(decoded);

        AtomicInteger position = new AtomicInteger();
        //first read algorithm, should be ssh-rsa
        String algorithm = readString(byteBuffer, position);
        System.out.println(algorithm);
        assert "ssh-rsa".equals(algorithm);
        // than read exponent
        BigInteger publicExponent = readMpint(byteBuffer, position);
        System.out.println("publicExponent = " + publicExponent);
        // than read modulus
        BigInteger modulus = readMpint(byteBuffer, position);
        System.out.println("modulus = " + modulus);
        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PublicKey publicKey = kf.generatePublic(keySpec);

        System.out.printf("Modulus: %X%n", modulus);
        System.out.printf("Public exponent: %d ... 17? Why?%n", publicExponent);
        System.out.printf("See, Java class result: %s, is RSAPublicKey: %b%n", publicKey.getClass().getName(), publicKey instanceof RSAPublicKey);

        byte[] pubBytes = publicKey.getEncoded();

        SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(pubBytes);
        ASN1Primitive primitive = spkInfo.parsePublicKey();
        writePEM("pubPkcs1.pem", "RSA PUBLIC KEY", primitive.getEncoded() );
    } catch (Exception e) {
        e.printStackTrace();
    }

}

private BigInteger readMpint(ByteBuffer buffer, AtomicInteger pos){
    byte[] bytes = readBytes(buffer, pos);
    if(bytes.length == 0){
        return BigInteger.ZERO;
    }
    return new BigInteger(bytes);
}

private String readString(ByteBuffer buffer, AtomicInteger pos){
    byte[] bytes = readBytes(buffer, pos);
    if(bytes.length == 0){
        return "";
    }
    return new String(bytes, StandardCharsets.US_ASCII);
}

private byte[] readBytes(ByteBuffer buffer, AtomicInteger pos){
    int len = buffer.getInt(pos.get());
    byte buff[] = new byte[len];
    for(int i = 0; i < len; i++) {
        buff[i] = buffer.get(i + pos.get() + SIZEOF_INT);
    }
    pos.set(pos.get() + SIZEOF_INT + len);
    return buff;
}

private void writePEM(String fileName, String header, byte[] content) throws IOException{
    File f = new File(fileName);
    FileWriter fw = new FileWriter(f);
    PemObject pemObject = new PemObject(header, content);
    PemWriter pemWriter = new PemWriter(fw);
    pemWriter.writeObject(pemObject);
    pemWriter.close();
}

输出

ssh-rsa
publicExponent = 65537
modulus = 20830840075214895520187085209140532093913000825284169131015003256319574044057453999265862514662442478787476545768050679936827456316397871442660366713280574836948529205417590573371022714192162142283026905055750951413644811120376414428742776306570652231542058994893537065648692533801879404176161589597321580633083481631733302249100913607754671673449460161582195402470090670605789220193388312197339358656479303453367386441996440265509774568364904443092245613429875362588897307051303623648237031289817493491475305022256278911859470009225208699382584578527080735302630318546541433464398236590978005758010444925861059033471
Modulus: A50314F94BF5AE5F4E0E5C1B7D479F5670BE393A6694DCCE54D3ADE57F28DAEE8BEA69547BFF6907B4B17F2E8090097499327CBC4530860E3A170FB1BFB46B321C50C7088FFF6355432C4D3A0250F3AE5BBAF43418F75FBA8248468C7DD217ABACE615E58A1ADB4852DF02549D904B3C8304ABB29550CAE68E7FEDFD76731D76110361883ECF471EF36B5AFE7F313C1582A7AD270C40DAC8D8CEB118330C9292BA335F9E08D04CBD71EAA2898FC056FCFE652C91359DB326F41403F46EE094993CEAA87523FB490A78A3E8E9F49BA29C773573F1C537B0180D781E37DE41A326DA715D798907A56EBB922F7AB8727E9881E213FD5A529AFCB4B35BE64876F97F
Public exponent: 65537 ... 17? Why?
See, Java class result: sun.security.rsa.RSAPublicKeyImpl, is RSAPublicKey: true

第二部分-将java对象另存为pkcs1公钥。

如果你写pubkeys.getEncoded()你得到pkcs8公钥,RSA公钥是不同的。RFC 3447附录A.1.1中描述的格式

An RSA public key should be represented with the ASN.1 type
RSAPublicKey:

  RSAPublicKey ::= SEQUENCE {
      modulus           INTEGER,  -- n
      publicExponent    INTEGER   -- e
  }

The fields of type RSAPublicKey have the following meanings:
* modulus is the RSA modulus n.
* publicExponent is the RSA public exponent e.

这个问题,特别是伊恩·博伊德的回答给出了很多细节。

充气城堡已经有类SubjectPublicKeyInfo来处理这种情况。

转换为pkcs8和pkcs1格式的代码

byte[] pubBytes = publicKey.getEncoded();
//writePEM("pubPkcs8.pem", "PUBLIC KEY", pubBytes ); // if you need pkcs8    
SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(pubBytes);
ASN1Primitive primitive = spkInfo.parsePublicKey();
writePEM("pubPkcs1.pem", "RSA PUBLIC KEY", primitive.getEncoded() );

pubPkcs1的内容。质子交换膜

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEApQMU+Uv1rl9ODlwbfUefVnC+OTpmlNzOVNOt5X8o2u6L6mlUe/9p
B7Sxfy6AkAl0mTJ8vEUwhg46Fw+xv7RrMhxQxwiP/2NVQyxNOgJQ865buvQ0GPdf
uoJIRox90herrOYV5Yoa20hS3wJUnZBLPIMEq7KVUMrmjn/t/XZzHXYRA2GIPs9H
HvNrWv5/MTwVgqetJwxA2sjYzrEYMwySkrozX54I0Ey9ceqiiY/AVvz+ZSyRNZ2z
JvQUA/Ru4JSZPOqodSP7SQp4o+jp9JuinHc1c/HFN7AYDXgeN95BoybacV15iQel
bruSL3q4cn6YgeIT/VpSmvy0s1vmSHb5fwIDAQAB
-----END RSA PUBLIC KEY-----

使用openssl检查结果

$ openssl asn1parse -in pubPkcs1.pem 
0:d=0  hl=4 l= 266 cons: SEQUENCE          
4:d=1  hl=4 l= 257 prim: INTEGER           :A50314F94BF5AE5F4E0E5C1B7D479F5670BE393A6694DCCE54D3ADE57F28DAEE8BEA69547BFF6907B4B17F2E8090097499327CBC4530860E3A170FB1BFB46B321C50C7088FFF6355432C4D3A0250F3AE5BBAF43418F75FBA8248468C7DD217ABACE615E58A1ADB4852DF02549D904B3C8304ABB29550CAE68E7FEDFD76731D76110361883ECF471EF36B5AFE7F313C1582A7AD270C40DAC8D8CEB118330C9292BA335F9E08D04CBD71EAA2898FC056FCFE652C91359DB326F41403F46EE094993CEAA87523FB490A78A3E8E9F49BA29C773573F1C537B0180D781E37DE41A326DA715D798907A56EBB922F7AB8727E9881E213FD5A529AFCB4B35BE64876F97F
265:d=1  hl=2 l=   3 prim: INTEGER           :010001
 类似资料:
  • 问题内容: 我有以下格式的公钥 我需要将其转换为以下格式 基本上,问题是我正在使用用Java编写的第三方库。 第三方库使用Java类“ RSAPublicKeySpec”从字符串生成RSAPublicKey类型的实例。 我提供给该第三方库的字符串取自以下格式的文件: 仔细研究一下代码之后,我可以看到,如果我使用java类“ X509EncodedKeySpec”来加载此公共密钥,则代码的签名验证部

  • 这是我生成RSA密钥的代码 现在我想转换DER/ASN.1编码字节,也知道使用Java JCE API生成RSA密钥时使用的默认编码格式是什么。

  • 我有以下公钥(作为示例): 我需要能够将其转换为可以插入ssh known_hosts文件的格式。例如: 谢了!

  • 问:是否可以从Java密钥存储读取RSA密钥对可以从公钥捕获公钥主体标识? 我已经生成了一个带有SHA1 2048位密钥的RSA,使用Java密钥工具并将密钥对存储在JKS文件中。我可以从这里使用代码加载密钥:https://stackoverflow.com/a/26711907/1203182但是我得到的是RSAPublicKey,而不是X509证书。RSA公钥没有从公钥中查找主题标识或DN的

  • 我需要用java生成openssh格式的密钥对。 我使用java中的KeyPairGenerator生成了一个公私密钥对,并将其保存到一个文件中: 但是,如果我尝试使用这个与ssh-keygen我得到一个"失败加载密钥private.key:无效格式" 如何将PKCS#8私钥转换为openssh格式或生成openssh格式的密钥对?

  • 如何在两种公钥格式之间进行转换,一种格式是: 另一种格式是: 例如,我使用ssh-keygen命令生成id_rsa/id_rsa.pub对,我使用id_rsa计算公钥: 然后我再次从id_rsa计算公钥。发布使用: 内容是pub1是: 而pub2的内容是: 根据我的理解,pub1和pub2包含相同的公钥信息,但是它们的格式不同,我想知道如何在两种格式之间转换?有人能给我看一些关于两种格式的简明介绍