2

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!

Dennis Kriechel
  • 3,719
  • 14
  • 40
  • 62
Brian T Hannan
  • 3,925
  • 18
  • 56
  • 96

1 Answers1

1

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.

Dennis Kriechel
  • 3,719
  • 14
  • 40
  • 62
  • This is weird to me because when I get the encrypted data it has a type associated with it and it's AES 128 CBC encryption. When I sent the request to a web service I sent them my public key. They used the public key to encrypt the data and now I have to decrypt using the private key associated with the key pair of the public key. This would indicate that it should be asymmetric encryption, right? – Brian T Hannan Dec 11 '15 at 16:16
  • **ENCRYPTED DATA WOULD BE HERE BUT I REMOVED** – Brian T Hannan Dec 11 '15 at 16:19
  • Indeed this is strange. The xml indicates that it's `symmetric` but the workflow you described would be `asymmetric`. If the data is required in `AES` you won't have two keys, so you can't send your `public key` because there is only one key. However for `AES` you have to send **the** key to the other site in order to let them decrypt your files. I can think of two ways here: 1. Change the Algorithm attribute (if possible) 2. Use an AES-Key instead of RSA and use this key for encryption and send it to the webservice. – Dennis Kriechel Dec 11 '15 at 16:22
  • The data is required to be AES because that is what the web service returns it as. I don't own that web service so I can't change what they send back. If they encrypt using the public key in AES 128 CBS would that mean I decrypt it using the public key as well since it's symmetric? – Brian T Hannan Dec 11 '15 at 16:35
  • it won't be called public key then any more but yes you both would use the same key. Here is an example for AES: http://stackoverflow.com/a/22445878/2546444 – Dennis Kriechel Dec 11 '15 at 16:49
  • That was actually the first way that I tried and it didn't work. – Brian T Hannan Dec 11 '15 at 17:14
  • I'm sorry then, I guess I can't help you any further. One last idea, maybe you can already change the algorithm the webservice is using in your request, the moment when you sent your key to the server. – Dennis Kriechel Dec 11 '15 at 17:23
  • I found this link which explains what the response SOAP message is like and how encryption is being used. Maybe this help explain: http://wso2.com/library/knowledge-base/how-does-soap-message-encryption-work/ – Brian T Hannan Dec 11 '15 at 17:44