1

I have been given an RSA public Key and an RSA private key with OAEP SHA-256 padding. I am attempting to simply encrypt a random string and then decrypt it to assert the result is equalt to the original.

This is the public key i have been given:

-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq8tiBtDmkeS/ruY3rrkq
dz6Lc6XWFRbI/GjPtIokrtpM+Ujyv6wX8TBqY8e03gzh+eE7VUyEVPapDnceAqgJ
ZQah2h+N5AEQKqNDM4/1to1V0F+m1ISR7CIUU8dvU+bPk67DU5VkEtLxf+mW8/es
hy0u6oSB04WCDPNnh+9GDF7tN7lOzBH1FxKPWIb5Gqg6GoXS+KgvQhYEk0TajIBk
+mefzTv1D4HJlhFYybgY+/p3k4P2kM5HnbEtoVpz/PL9+94YVp5RBHTQHmk/3SAX
RkPP34IjY6LZqTJGWQGxc64Qci54ZJsq4wSTXvfdHgUWz7eX+v1jA+GLjFExNcYZ
nQIDAQAB
-----END RSA PUBLIC KEY-----

This is the private key I have been given:

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAUQiHdHuMBCnF
P/7RQoRWrp62dGWQLDLP9l+3KUMlSPheN2R5jHDZ/WEGJGF2WYKxaQvv5XCocdnt
uxVZTNM1PVyduokJaJzrSIj+jGWDd4hTWvVoS3vhds8u6W0jD3M4ayrF6c7NYuHc
tE5YLLIgK1DTn+ZZCr3VGbScISDJ/WPx3+1YTNQDvm+T7MfjhetJqqzWIsunMUiw
nQOQvkdjCVWpk+L10SaMrezixtIS5wfpOTjGIZ0w5VunvtsPxg1TkuvGURa9S3rS
7D3uhDPY+V8UDMpBPso3j7TGD5axlBJcpavWeF8qde3sWztmqUFQ3JDypZWGSAe2
d8e4mY65AgMBAAECggEAal8nwYxbHZnb5L892U7aVfuly7Nbzb+0pzRVwsBu5DuV
LL+kslpMvTYZqUUMJ2LhF/HLaXhVtMWsTYLSDx+gHu1+wbtAOtUDHlxzcaAEMhA2
dix0WqiNr6qAdCkmdWMBTu5vrSJigVW1KdcNElY+e+6ZeUQTK6L2Vt0t+cGVGkM4
K5PdHcGLR1BiAf3k4BguHE4TGGnqN9dF5Rn9nPP6C7QihWzGn15efD2dAXn3Kbho
dMIRgyYiO7uXPm2LrIjtldYb8tPus+V9SWT4hcgnJZrtd9atkqZrJ3dhQf9ZetGs
UwTCzHJ169NNbVyrjCbcy4Uht8Na+t/94Im9hI8n0QKBgQDO6tYnwh1hPg3E+4DY
xCiDAp7v3afJIvC9a1sBtif8KkzZTYH31ww+PRcfDPQUlk/MIDie0u6xIawnBYkC
oN1u9erojcvQbBP0GFylP5hNxYZbI7gPA/7AiGRxyezZPOiVMwdd5fCM7Wv4kucr
c1JCcvtPoDQcFFZOfI+wqqdWnQKBgQDt745Pvckt7/XL7wbfv4BV+cwpLNjc4/3k
ajOLtasgpT8mc0gUH2ejHhpkuhjSUpSTrlFB8EN1kAwmBYy0GOoO9967hm6twmqk
Q5L3OHJ96pYkf1rbyXNE1N7inh5Z3M1H5ONIaliAYLHXOzKsZvI5eUdKAJdSqFLo
uvVCwr4PzQKBgG6W3rzDJ9a4Rr24OgYg2RIkTXQgALQko4xpm2tPwxEoPoiJv2QK
ILYHCpuC3dU+/Qk5U2m3jPFI8OyuLask9RSABPwkBQGxMfztJF8BnVI7tvJxJceI
uBiJDT4v0RHOVvSfIFnUMnvvzRw+z6TObvGq6JyHIDK9v98U/etLWkKVAoGAIIxF
lmjqzUrm/8ep1A+5OYmbQQKug8D4aTeR54mpaCTSt6rLcF0/axPiHmdKn/LF+lG9
MdzxDXLwBn952OUTl4qWwGZKW6Cdv+yyfPkOyGS/tyxovGoZR5ArESr6Eebfefc4
lB5gDuerTDr/2o+WkQAjHV9pU9hMxyNUC5biMv0CgYEAiDlw8lBf3cQs6FxNXs9t
whWpfL0yY7WAONvhfFB0Dpsz52gGDCYRvJekGRz6jOlKDuXJ+Mm1AX4BaufMETI5
QseZxtVPIn+BXm0A1x8w/DifmE1JqQZmPCQPOh3eLx5nSn9LKGIbMgd17mfH3HhU
8WX2mzWjmRA3C/CzdGfCKSk=
-----END PRIVATE KEY-----

I am reading this key from a pem file "crypt_pkcs8.pem" but recive the public key as a byte array from a gRPC call.

Here is my Java code:

public class Encryption{
public static void main(String args){
    ByteString publicKey = client.getPublicKey(nonce).getRSAEncryptionKey();

    String strKeyPEM = "";
    BufferedReader br = new BufferedReader(new FileReader("crypt_pkcs8.pem"));
    String line;
    while ((line = br.readLine()) != null) {
        strKeyPEM += line+"\n";
    }
    br.close();
    byte[] pt;
    try {
        pt = "h".getBytes("UTF-8");
        byte[] ct =encrypt(publicKey, pt);
        byte[] response= decrypt(strKeyPEM, ct);

        assertEquals(pt, response);
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
public static byte[] encrypt(ByteString rawKey ,byte[] message){
    String strippedKey=stripKey(rawKey.toStringUtf8());

    byte[] keyBytes = Base64.getDecoder().decode(strippedKey);
    System.out.println(keyBytes.length);

    Cipher cipher_RSA;
    try {
        cipher_RSA = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        PublicKey pk = keyFactory.generatePublic(spec);
        System.out.println(pk.getAlgorithm()+" format : "+pk.getFormat());

        cipher_RSA.init(Cipher.ENCRYPT_MODE, pk); 
        return cipher_RSA.doFinal(message);
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
            BadPaddingException | InvalidKeyException | InvalidKeySpecException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return null;
    }

}

public static byte[] decrypt(String rawKey ,byte[] message){
    String strippedKey=stripPrivateKey(rawKey);

    byte[] keyBytes = Base64.getDecoder().decode(strippedKey);
    System.out.println(keyBytes.length);

    Cipher cipher_RSA;
    try {
        cipher_RSA = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        PrivateKey pk = keyFactory.generatePrivate(spec);
        System.out.println(pk.getAlgorithm()+" format : "+pk.getFormat());

        cipher_RSA.init(Cipher.DECRYPT_MODE, pk); 
        return cipher_RSA.doFinal(message);
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
            BadPaddingException | InvalidKeyException | InvalidKeySpecException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return null;
    }
}
public static String stripKey(String key){
    key = key.replace("-----BEGIN RSA PUBLIC KEY-----\n", "");
    key = key.replace("-----END RSA PUBLIC KEY-----", "");
    key = key.replace("\n", "");
    return key;
}

public static String stripPrivateKey(String key){
    key = key.replace("-----BEGIN PRIVATE KEY-----", "");
    key = key.replace("-----END PRIVATE KEY-----", "");
    key = key.replace("\n", "");
    return key;
}


}

I cannot find anything obviously wrong with my actaul code so I believe this is to do with the keys not matching.

I also notice the header/footer is different on the public key and private key. From looking online this is because the public key is in PKCS#8 format.

Will I need to change the public key to pkcs#8 format as well? If so what is the easiest way to do this?

I have also been told I should be able to extract the public key (in pkcs8 format) from the private key given above. Can this be done easily?

Dom Fraise
  • 360
  • 1
  • 4
  • 12
  • Your public key is not in pkcs8 format. You have it in pkcs1 format. Use openssl to convert it to pkcs8. – Johann Apr 01 '20 at 06:36

1 Answers1

2

If you can get a valid public key then the key is not in PKCS#8 format, it will be in X.509 (SubjectPublicKeyInfo) format as Java expects. However, your public and private keys do indeed not match. You can use the answer here to create the correct public key file from the private key file.


Java doesn't directly contain code to retrieve the public exponent from an RSAPrivateKey without CRT parameters. However, if you want a Java only solution you could cast the PrivateKey even further to RSAPrivateCrtKey which does contain a getPublicExponent method to retrieve the public exponent. Then you can use an RSA KeyFactory to generate a public key using RSAPublicKeySpec.


You could also parse the PEM file to retrieve the public key in Java using e.g. the Bouncy Castle API. But expect a steep learning curve if you do.

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