Java – In Java, how to decrypt using the private key from an X509 certificate (public/private key pair) inside a JKS keystore

encryptionjavajksrsa

I created a KeyStore using KeyStore Explorer with a public/private key pair inside it of type RSA, 4096 bytes, and PKCS#8 formatting.

I get an error when my code runs and hits the cipher.init() method :

"Key for algorithm RSA not suitable for symmetric encryption."

This doesn't really make sense to me because I'm using asymmetric key encryption/decryption. I'm not sure where to go from here or what I'm doing wrong.

Here is what I have:

public TransactionData processData(TransactionData data) throws BTHException {
    String keystoreFilePath = manager.getStringValue(KeyStoreFilePath);
    String keystorePassword = manager.getStringValue(KeyStoreFilePassword);
    String privateKeyPassword = manager.getStringValue(KeyStorePrivateKeyPassword);
    String certificateAlias = manager.getStringValue(CertificateAlias);

    org.apache.xml.security.Init.init();

    try {
        InputStream in = data.getDataStream();
        byte[] dataBytes = DataUtil.readBytes(in);
        String encryptedDataStr = new String(dataBytes);

        PrivateKey privateKey = getPrivateKeyFromKeyStore(keystoreFilePath, keystorePassword, certificateAlias, privateKeyPassword);

        decrypt(
            encryptedDataStr,
            privateKey
        );
    }catch(Exception e){
        throw new BTHException(e.getMessage());
    }

    return data;
}

private PrivateKey getPrivateKeyFromKeyStore(String keyStoreFilePath, String keyStorePassword, String privateKeyCertAlias, String privateKeyPassword) throws BTHException {
    PrivateKey privateKey = null;
    try {
        KeyStore keystore = KeyStore.getInstance("JKS");
        BASE64Encoder encoder = new BASE64Encoder();
        keystore.load(new FileInputStream(keyStoreFilePath), keyStorePassword.toCharArray());
        Key key=keystore.getKey(privateKeyCertAlias,keyStorePassword.toCharArray());
        if(key instanceof PrivateKey) {
            Certificate cert=keystore.getCertificate(privateKeyCertAlias);
            PublicKey publicKey=cert.getPublicKey();
            KeyPair keyPair = new KeyPair(publicKey,(PrivateKey)key);
            privateKey = keyPair.getPrivate();
        }
        //privateKeyEncoded = encoder.encode(privateKey.getEncoded());
    } catch (Exception e) {
        throw new BTHException(e.getMessage());
    }
    return privateKey;
}

private String decrypt(String cipherText, PrivateKey privateKey) throws IOException, GeneralSecurityException, BTHException {
    String decryptedValue = null;

    try {
        // 1. Get the cipher ready to start doing the AES transformation
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        // 2. Start the decryption process
        // THIS IS WHERE IT FAILS
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        // 3. Finish the decryption process
        decryptedValue = new String(cipher.doFinal(Base64.decodeBase64(cipherText)), "UTF-8");
    } catch (Exception e) {
        throw new BTHException(e.getMessage());
    }

    return decryptedValue;
}

Any help would be great. Thanks in advance!

Best Answer

You are trying to initialize your cipher as AES/CBC/PKCS5Padding which is an symmetric encryption and that is where the exception originates.

You should use the Cipher like that:

// 1. Get the cipher ready to start doing the RSA transformation
Cipher cipher = Cipher.getInstance("RSA");

// 2. Start the decryption process
cipher.init(Cipher.DECRYPT_MODE, privateKey);

Here you can find a good example for RSA-Encryption and Decryption.

Related Topic