[SalesForce] Encrypting and/or decrypting ciphertext with the provided Initialization Vector (IV)

I had given an cipher text (of JSON string), an IV and a key. I tried decrypting using Apex Crypto class's method:

decryptWithManagedIV(algorithmName, privateKey, IVAndCipherText)

  //Sample code
  Blob key = Blob.valueOf(decryptionKey);
  Blob encryptedDatafor = EncodingUtil.base64Decode(bodystring);
  Blob decryptedData = Crypto.decryptwithManagedIV('AES128', key, encryptedDatafor);

  cipher = decryptedData.toString();
  System.debug('Encrypted BodyString: ' +cipher);

and I was able to decrypt the cipher successfully. But when I use the provided IV with the following method:

decrypt(algorithmName, privateKey, initializationVector, cipherText)

 //Sample code
 Blob exampleIV = Blob.valueOf('HSDlUkhrmfEo7SgM'); //provided IV 
 Blob key = Blob.valueOf(decryptionKey);
 Blob encryptedDatafor = EncodingUtil.base64Decode(bodystring);
 Blob decryptedDataIV = Crypto.decrypt('AES128', key, exampleIV, encryptedDatafor);

 cipher = EncodingUtil.base64Encode(decryptedDataIV );
 System.debug('Encrypted BodyString: ' +cipher);

I get some string which looks like, it is still in the encrypted form (different from the encrypted string I have passed).

Update:
I have tried the below code-snippet based on the suggestion from @identigral, but I am still unable to decrypt the cipher using the IV:

Blob exampleIV = Blob.valueOf('HSDlUkhrmfEo7SgM'); //provided IV 
Blob key = Blob.valueOf(decryptionKey);
Blob encryptedDatafor = EncodingUtil.base64Decode(bodystring);

String encodedCipherTextAndIV = EncodingUtil.convertToHex(encryptedDatafor);
String encodedCipherText = encodedCipherTextAndIV.substring(32);
String finCipher = encodedCipherText.difference(encodedCipherTextAndIV);
Blob ciphertext = EncodingUtil.convertFromHex(finCipher); 

Blob decryptedDataIV = Crypto.decrypt('AES128', key, exampleIV, ciphertext);

decryptStg = EncodingUtil.base64Encode(decryptedDataIV );
System.debug('Decrypted BodyString: ' +decryptStg);

Best Answer

You can't decrypt the same ciphertext (bodystring) in your example with both decryptWithManagedIV and decrypt methods, only one of them will work. decryptWithManagedIV assumes that the ciphertext includes an initialization vector. If this is indeed the case, then bodystring consists of an IV (first 16 bytes), then the rest of it is actual stuff that was originally encrypted. Using decrypt on the same ciphertext will only work if you remove the IV from bodystring.

To remove the first 16 bytes from a binary Blob, you have to manipulate its hex representation. From this answer:

Use EncodingUtil.convertToHex() to get a hexadecimal (base 16) representation of the blob. So the first two characters in the hexadecimal string will represent the first byte of the encryptedData. To get the first 16 bytes you will need the first 32 hexadecimal characters.

Example with a complete roundtrip:

String text = 'The quick brown fox jumps over 13 lazy dogs.';
Blob key = Crypto.generateAesKey(128);
Blob data = Blob.valueOf(text);
String b64Data = EncodingUtil.base64Encode(data);

Blob ciphertextAndIV = Crypto.encryptWithManagedIV('AES128', key, data);
Blob plaintext = Crypto.decryptWithManagedIV('AES128', key, ciphertextAndIV);
String b64Decrypted = EncodingUtil.base64Encode(plaintext);
System.debug('Text = plaintext: ' + (text == plaintext.toString()));
System.debug('Base64-text = Base64-plaintext: ' + (b64Decrypted == b64Data));

String encodedCiphertextAndIV = EncodingUtil.convertToHex(ciphertextAndIV);
String encodedCiphertext = encodedCiphertextAndIV.substring(32);
String encodedIV = encodedCiphertextAndIV.substring(0,32);
Blob ciphertext = EncodingUtil.convertFromHex(encodedCiphertext);
Blob IV = EncodingUtil.convertFromHex(encodedIV);
Blob plaintext2 = Crypto.decrypt('AES128', key, IV, ciphertext);
String b64Decrypted2 = EncodingUtil.base64Encode(plaintext2);
System.debug('Text = plaintext: ' + (text == plaintext2.toString()));
System.debug('Base64-text = Base64-plaintext: ' + (b64Decrypted2 == b64Data));
Related Topic