Question

In my App I generate a public/private key pair and store them for later usage on disk. Loading and re-initialising the private key works fine but for the private key I get a Unknown KeySpec type: java.security.spec.PKCS8EncodedKeySpec - and I have no idea why.

That's how I create and save the keys (code a bit simplified to be easier to read):

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(4096);
KeyPair keyPair = kpg.generateKeyPair();
privKey =keyPair.getPrivate();
pubKey =keyPair.getPublic();        

DataOutputStream out=new DataOutputStream(ctx.openFileOutput(PRIVKEY_FILE,Context.MODE_PRIVATE));
byte[] data=privKey.getEncoded();
out.write(data);
out.close();

DataOutputStream out=new DataOutputStream(ctx.openFileOutput(PUBKEY_FILE,Context.MODE_PRIVATE));
byte[] data=pubKey.getEncoded();
out.write(data);
out.close();

Next loading of the private key works fine:

DataInputStream in=new DataInputStream(ctx.openFileInput(PRIVKEY_FILE));
byte[] data=new byte[in.available()];
in.readFully(data);

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data);
KeyFactory kf = KeyFactory.getInstance("RSA");
privKey = kf.generatePrivate(keySpec);

decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
decryptCipher.init(Cipher.DECRYPT_MODE, privKey);

Similar code for the public key fails miserably:

DataInputStream in=new DataInputStream(ctx.openFileInput(PUBKEY_FILE));
byte[] data=new byte[in.available()];
in.readFully(data);

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data);
KeyFactory kf = KeyFactory.getInstance("RSA");
pubKey = kf.generatePublic(keySpec); --> here the exception is thrown

encryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, pubKey);             

So what am I doing wrong? What is the proper way of loading a public keys data from disk?

Thanks!

Était-ce utile?

La solution

Public and Private keys are encoded differently. Whilst private keys are encoded in PKCS #8, public keys are not. They are instead encoded in X.509 according to the ASN.1 specifications.

Description from the Key.getFormat() method:

Returns the name of the primary encoding format of this key, or null if this key does not support encoding. The primary encoding format is named in terms of the appropriate ASN.1 data format, if an ASN.1 specification for this key exists. For example, the name of the ASN.1 data format for public keys is SubjectPublicKeyInfo, as defined by the X.509 standard; in this case, the returned format is "X.509". Similarly, the name of the ASN.1 data format for private keys is PrivateKeyInfo, as defined by the PKCS #8 standard; in this case, the returned format is "PKCS#8".

According to this, instead of reading public keys as PKCS #8, you should read it as X.509.

Consider changing your public key reading code from:

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data);

to:

X509EncodedKeySpec keySpec = new X509EncodedKeySpec(data);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top