4

I am using this code to generate a private key from RSA key

public class ReadPKCS8Pem {
    private final static String PRIVATE_KEY = Keys.PRIVATE_KEY;

    public static PrivateKey getKey(){
        try{
            // Read in the key into a String
            StringBuilder pkcs8Lines = new StringBuilder();
            BufferedReader rdr = new BufferedReader(new StringReader(PRIVATE_KEY));
            String line;
            while ((line = rdr.readLine()) != null) {
                pkcs8Lines.append(line);
            }

            // Remove the "BEGIN" and "END" lines, as well as any whitespace

            String pkcs8Pem = pkcs8Lines.toString();
            pkcs8Pem = pkcs8Pem.replace("-----BEGIN RSA PRIVATE KEY-----", "");
            pkcs8Pem = pkcs8Pem.replace("-----END RSA PRIVATE KEY-----", "");
            pkcs8Pem = pkcs8Pem.replaceAll("\\s+","");

            // Base64 decode the result

            byte [] pkcs8EncodedBytes = Base64.decode(pkcs8Pem, Base64.DEFAULT);

            // extract the private key

            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8EncodedBytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            PrivateKey privKey = kf.generatePrivate(keySpec);
            System.out.println(privKey);

            return privKey;
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return null;
    }
}

In the line:

PrivateKey privKey = kf.generatePrivate(keySpec);

I am getting the exception:

java.lang.RuntimeException: error:0c0890ba:ASN.1 encoding routines:asn1_check_tlen:WRONG_TAG
  • I get this exception in my marshmallow device but in my Oreo device, it works fine and i am able to generate the private key successfully
  • How to resolve this
Devrath
  • 42,072
  • 54
  • 195
  • 297

1 Answers1

1

The header -----BEGIN RSA PRIVATE KEY----- in the PEM file means it contains a PKCS#1 key, but Java (and Android )does not support pkcs1, so you need to convert the key from pkcs1 to pcks8 using a tool like openssl

# openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in pkcs1.key -out pkcs8.key

Alternatively you can load the key using Bouncycastle. See Read RSA private key of format PKCS1 in JAVA


I do not know why it works in Oreo, it could be that the underliying provider will support the conversion even if it is not documented https://developer.android.com/reference/java/security/spec/PKCS8EncodedKeySpec

pedrofb
  • 37,271
  • 5
  • 94
  • 142
  • 1
    I researched this issue before and discovered that, yes, the Bouncycastle will silently accept PKCS1 RSAPrivateKey, so it's like Oreo uses Bouncycastle by default for this operation and marshmallow probably uses the openssl provider by default. – President James K. Polk Jan 21 '19 at 17:57
  • 1
    Good point @JamesKPolk , it was the only reasonable explanation. – pedrofb Jan 21 '19 at 18:35