如何在Java中读取RSA公钥文件?

6

我有一个类似于以下内容的RSA公钥文件:

-----BEGIN RSA PUBLIC KEY-----
this is content
-----END RSA PUBLIC KEY-----

我使用Java来读取它:

KeyFactory factory = KeyFactory.getInstance("RSA");
KeySpec spec = new X509EncodedKeySpec(bytesFromThisFile); // bytesFromThisFile is created and filled correctly 
PublicKey publicKey = factory.generatePublic(spec);

然后我遇到了一个异常:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format

如何正确读取文件?有没有办法将这个rsa公钥文件转换为Java可读格式?


1
你要求人们假设bytesFromThisFile已经被正确地创建和填充。你应该创建一个[mcve]。 - Gimby
@Gimby 的 bytesFromThisFile 已经被正确地创建并填充。 - HongyanShen
2个回答

8
尝试以下方法:

 /**
 * reads a public key from a file
 * @param filename name of the file to read
 * @param algorithm is usually RSA
 * @return the read public key
 * @throws Exception
 */
public  PublicKey getPemPublicKey(String filename, String algorithm) throws Exception {
      File f = new File(filename);
      FileInputStream fis = new FileInputStream(f);
      DataInputStream dis = new DataInputStream(fis);
      byte[] keyBytes = new byte[(int) f.length()];
      dis.readFully(keyBytes);
      dis.close();

      String temp = new String(keyBytes);
      String publicKeyPEM = temp.replace("-----BEGIN PUBLIC KEY-----\n", "");
      publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");


      BASE64Decoder b64 = new BASE64Decoder();
      byte[] decoded = b64.decodeBuffer(publicKeyPEM);

      X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
      KeyFactory kf = KeyFactory.getInstance(algorithm);
      return kf.generatePublic(spec);
}

来源: 从文件加载RSA公钥


3
我可以建议您改进您的回答,通过删除对BASE64Decoder的依赖,并使用java.util.Base64中的基于64位编码解码器来完成。如果需要,我可以帮您进行更改。 - President James K. Polk
当然,那太好了。 - Krystian G

4

这是我的实现方式,可以读取 PEM 格式的密钥或证书。 仅在 Java11 中测试过。


  /**
   * reads a public key from a file
   * @param f file to read
   * @return the read public key
   * @throws Exception
   */
  public static PublicKey getPublicKeyFromPem(File f)
     throws Exception
  {
    byte[] keyBytes = Files.readAllBytes(f.toPath());

    String temp = new String(keyBytes);
    String publicKeyPEM = temp;

    if(temp.contains("-----BEGIN PUBLIC KEY-----"))
    {
      publicKeyPEM = temp
         .replace("-----BEGIN PUBLIC KEY-----\n", "")
         .replace("-----END PUBLIC KEY-----", "")
         .trim();
    }
    else if(temp.contains("-----BEGIN RSA PUBLIC KEY-----"))
    {
      publicKeyPEM = temp
         .replace("-----BEGIN RSA PUBLIC KEY-----\n", "")
         .replace("-----END RSA PUBLIC KEY-----", "")
         .trim();
    }
    else if(temp.contains("-----BEGIN CERTIFICATE-----"))
    {
      CertificateFactory fact = CertificateFactory.getInstance("X.509");
      try (FileInputStream is = new FileInputStream(f))
      {
        X509Certificate cer = (X509Certificate) fact.generateCertificate(is);
        return cer.getPublicKey();
      }
    }

    Base64.Decoder b64 = Base64.getDecoder();
    byte[] decoded = b64.decode(publicKeyPEM);

    X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePublic(spec);
  }

它对我有用,但是有点令人困惑的是我们在 X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded); 中传递了解码后的密钥,而构造函数中的参数名称为 X509EncodedKeySpec(byte[] encodedKey)。我错过了什么吗? - Dhruvam Gupta
这只是字节数组的名称而已。你可以随意命名它们。构造函数需要一个字节数组。在PEM格式中,字节数组以Base64编码。代码从Base64字符串中提取字节数组,然后将其传递给构造函数。 - Nicola De Nisco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接