3

I have created the public and private key . The public and private key generated from php code :

<?php
    require __DIR__ . '/vendor/autoload.php';
    use phpseclib\Crypt\RSA;
    $rsa = new RSA();
    extract($rsa->createKey()); 
    $rsa->setPrivateKeyFormat(RSA::PRIVATE_FORMAT_PKCS8);
    $rsa->setPublicKeyFormat(RSA::PUBLIC_FORMAT_PKCS8);

    file_put_contents("privateKey.pem",$privatekey);
    file_put_contents("publicKey.pem", $publickey);

The java source code to read those keys:

    import java.io.*;
    import java.security.*;
    import java.security.spec.*;

    public class PublicKeyReader {

    public static PublicKey get(String filename)
        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();

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

   public static void main (String [] args) throws Exception {
    PublicKeyReader publicKeyReader = new PublicKeyReader();
    PublicKey publicKey = publicKeyReader.get("key/testPub.pem");
    System.out.println(publicKey);
   }
   }

It produces java.security.InvalidKeyException: invalid key format.

Need help on this. Thanks in advance.

Xihar
  • 103
  • 1
  • 12
  • Could you include the "PKCS#8 encoded" public key? Because there is *no such thing* as a PKCS#8 encoded public key; the PKCS#8 is for private / secret keys only (actually ,the title of [the standard](https://tools.ietf.org/html/rfc5208) is "Private-Key Information Syntax Specification Version 1.2"). So this is another instance where PHP decides to "just make something of it" rather than to simply *fail* because the code is *incorrect*. – Maarten Bodewes Dec 10 '19 at 12:56
  • @Maarten-reinstateMonica - what PKCS#8 is referring to, in this case, is a key that uses the following ASN.1 format: https://pastebin.com/4Gy0p9Qw Sure, PKCS#8 may not be the best description, but idk what would be. Such keys start off with `-----BEGIN PUBLIC KEY-----`. This is in contrast to what Xihar's library refers to as PKCS#1 keys, which start off with `-----BEGIN RSA PUBLIC KEY-----` or `-----BEGIN EC PUBLIC KEY-----` or whatever. And I get it - PKCS#1 only talks about RSA and not EC public keys but what else are you going to call it? – neubert Dec 10 '19 at 18:07
  • @Maarten-reinstateMonica - none-the-less, https://pastebin.com/c03kGJjh is, I expect, a key in the format that the OP (Xihar) is talking about. – neubert Dec 10 '19 at 18:08
  • 1
    @neubert That last one is a structure called `SubjectPublicKeyInfo` and it is part of the X.509 certificate format (therefore `X509EncodedKeySpec` in Java). – Maarten Bodewes Dec 10 '19 at 18:14
  • @Maarten-reinstateMonica - what constitutes an optimal name is a bit subjective. For private keys PKCS#8 is ultimately a wrapper format that contains the algorithm specific information as an OCTET STRING that needs to be decoded separately. Spiritually, this is the same thing as Java's `X509EncodedKeySpec` and in some ways I feel it may be a better name because `X509EncodedKeySpec` might conjure up images of the whole X.509 spec when it ought not. – neubert Dec 10 '19 at 18:25
  • Better read my answer then... sorry, it is defined in that spec, and nowhere else. There is nothing subjective about it, I didn't make it up. – Maarten Bodewes Dec 10 '19 at 18:35
  • @neubert Thanks for providing the output by the way, I don't have that many environments setup, and the runtime configs change per question sometimes. – Maarten Bodewes Dec 10 '19 at 18:42
  • @Maarten-reinstateMonica - maybe a better name would be `SubjectPublicKeyInfo` then instead of `X509EncodedKeySpec`. Maybe both Java and the PHP library have got it wrong. But since neither of them are naming it "correctly" I still stand by my assertion that PKCS1 is a decent enough "name" - just as much so as "X509EncodedKeySpec". As I've already stated, it is spiritually the same thing as a PKCS8 private key - both are OCTET STRINGs (well, SubjectPublicKeyInfo is a BIT STRING but whatever) wrapped by an overarching ASN.1 defined structure. – neubert Dec 10 '19 at 19:17
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/204058/discussion-between-maarten-reinstate-monica-and-neubert). – Maarten Bodewes Dec 11 '19 at 13:32

1 Answers1

3

First of all, as noted in the comments, there is no such thing as a PKCS#8 public key. That means that the PHP library doesn't know what it is talking about. Instead, what you seem to get, if neubert is correct, is a structure defined for X.509 certificates called X509EncodedKeySpec. And in the Java code, you are indeed trying to use that to read in the public key.

However, what you forget is that X509EncodedKeySpec is a binary format, specified in ASN.1 DER. What you receive is a PEM encoded key that uses ASCII armor. In other words, the binary has been encoded to base64 and a header and footer line has been added. This is done to make it compatible with text interfaces such as mail (Privacy Enhanced Mail or PEM).

So what you do is to remove the armor. You can best do this using a PEM reader such as the one provided by Bouncy Castle.

PemReader reader = new PemReader(new FileReader("spki.pem"));
PemObject readPemObject = reader.readPemObject();
String type = readPemObject.getType();
byte[] subjectPublicKey = readPemObject.getContent();

System.out.println(type);

X509EncodedKeySpec spec = new X509EncodedKeySpec(subjectPublicKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(spec);
System.out.println(pubKey);

which prints

PUBLIC KEY

followed by

Sun RSA public key, 1024 bits
  params: null
  modulus: 119445732379544598056145200053932732877863846799652384989588303737527328743970559883211146487286317168142202446955508902936035124709397221178664495721428029984726868375359168203283442617134197706515425366188396513684446494070223079865755643116690165578452542158755074958452695530623055205290232290667934914919
  public exponent: 65537

For the skeptics - hi neubert ;) - here is the definition of SubjectPublicKeyInfo from the X.509 specification:

SubjectPublicKeyInfo  ::=  SEQUENCE  {
     algorithm            AlgorithmIdentifier,
     subjectPublicKey     BIT STRING  }

where subjectPublicKey contains the encoded public key in PKCS#1 format - in the case of an RSA public key, of course.

And here is the decoded version of neubert's key so you can compare. The parsed key in Java is the same key.

Community
  • 1
  • 1
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263