Decrypting salesforce Apex (AES with managed IV) using C#

Securing Your Data

In Salesforce, you can secure your data by using the methods provided by the Crypto class. The methods in the Crypto class provide standard algorithms for creating digests, message authentication codes, and signatures, as well as encrypting and decrypting information. These can be used for securing content in Salesforce, or for integrating with external services such as Google or Amazon WebServices (AWS) to securely exchange data with your partners at transfer, at rest, or any other requirement mandates encryption.

In this example, we are going to use AES 256 encryption algorithm. In Crypto class, we are going to use this method:

encryptWithManagedIV(algorithmName, privateKey, clearText)

Salesforce implementation of AES encryption is following the industry-standard Advanced Encryption Standard (AES) algorithms with different size keys. They use cipher block chaining (CBC) and PKCS7 padding.

The length of privateKey must match the specified algorithm: 128 bits, 192 bits, or 256 bits, which is 16 bytes, 24 bytes, or 32 bytes, respectively.

Initialization Vector

Since Apex Crypto AES is using CBC mode, CBC requires a unique binary sequence, often called an initialization vector (IV), for each encryption operation. The IV has to be non-repeating and, for some modes, random as well. The initialization vector is used to ensure distinct ciphertexts are produced even when the same plaintext is encrypted multiple times independently with the same key. More details here.

The initialization vector will always be 128 bits (16 bytes.). Don’t mix the IV with the key length. The key length could vary depends on the chosen algorithm while the IV is always 128 bytes no matter how long the key is.

When you use Crypto.encryptWithManagedIV(), you are asking Apex to create a random IV for you and include this in the first 16 bytes of the ciphertext. However, you can always choose an IV of your choice and use it all the time. Notice that this is highly not recommended for confidential data. The main consequence of reusing the IV is that if two messages begin with the same sequence of bytes then the encrypted messages will also be identical for a few blocks. This leaks data and opens the possibility of some attacks. One can manually specify their own IV using Crypto.encrypt() method.


If you are going to decrypt the ciphertext in Salesforce, this is piece of cake, since the decryption methods are already included in the crypto class. However, the challenge starts when you want to exchange the ciphertext with your partners, other systems, or platforms that are not running on salesforce. In this case, these systems have to implement their own version of decrypting the AES encrypted ciphertext.

One could use decrypt(algorithmName, privateKey, initializationVector, cipherText) if you manually specified you IV at Salesforce end or the encryption takes place at third-party premises and they share the ciphertext, encryption key, and IV with you.

“ Decrypts the Blob cipherText using the specified algorithm, private key, and initialization vector. Use this method to decrypt blobs encrypted using a third party application or the encrypt method.”

On the other hand, one can use decryptWithManagedIV(algorithmName, privateKey, IVAndCipherText) to decrypt the Blob IVAndCipherText using the specified algorithm and private key. Use this method to decrypt blobs encrypted using a third-party application or the encryptWithManagedIV method.

The use-case

In this example, the Salesforce team is going to encrypt a JSON object using encryptWithManagedIV(algorithmName, privateKey, clearText) to generate random IV for every encryption process to leverage strong protection for the shared data. This data will be shared with a third-party who is going to Decrypt it using C# at their end.

- Assumptions:

  • Salesforce teams share the ciphertext with the third-party team.
  • The cipher blob is transferred in base64 format.

1- SalesForce Team encrypts the data

Blob key = Crypto.generateAesKey(256);// Generate the data to be encrypted.Blob data = Blob.valueOf('{"name":"Anna", "age":31, "email":""}');// Encrypt and decrypt the dataBlob encryptedData = Crypto.encryptWithManagedIV('AES128', key, data)// Generate an encrypted form of the data using base64 encodingString b64EncryptedData = EncodingUtil.base64Encode(encryptedData);

2- Third-party team writes the decryption class.

  • Retrieve IV

The first thing we need to do is to retrieve the IV from the ciphertext. As mentioned earlier, the IV will be the first 128 bits (16 bytes.) of the ciphertext. Since the ciphertext we received is Base-64 we need to figure how to get the first 16 bytes in this format. You need to dust off your math skills to do so.

In base-64 each character is used to represent 6 bits (log2(64) = 6).

Therefore 4 chars are used to represent 4 * 6 = 24 bits = 3 bytes.

So you need 4*(n/3) chars to represent n bytes and this needs to be rounded up to a multiple of 4.

We will need the first 16 bytes but 16 is not divisible by 3. Therefore, we will get the first 18 (18 devisable by 3) and then ignore the last 2 bytes. So, our equation would be (4*18)/3 = 24.

As you see here, we get the first 16 bytes only and ignore the last 2.

Array.Copy(cipher_binary, 0, iv, 0, 16);

For the ciphertext, we will get everything after the first 16 bytes (IV).

This is following Microsoft documentation.

Here is a screenshot of my result.

Thank you for reading.