5

I have a RSA public key file like this:

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

and i use java to read it:

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

then i get an exception:

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format

How to read the file properly? Is there a way to convert this rsa public key file to a java-readable format?

HongyanShen
  • 1,435
  • 2
  • 14
  • 23

2 Answers2

8

Try this method:

 /**
 * 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);
}

source: Load RSA public key from file

President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
Krystian G
  • 2,842
  • 3
  • 11
  • 25
3

This is my implementation; can read PEM with key or certificate. Tested only in 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);
  }
  • it worked for me but it is a bit confusing that we are passing decoded key in `X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);` and the parameter name in the constructor is `X509EncodedKeySpec(byte[] encodedKey)`. Am i missing something here? – Dhruvam Gupta Feb 18 '22 at 08:43
  • It's just the name of the byte array. You can call them how you want. The constructor need a byte array. In the PEM format the byte array is encoded in base64. The code extract byte array from the string base 64 the pass them to the constructor. – Nicola De Nisco Jul 26 '23 at 17:53