Why Does EncryptSymmetric() in AMPScript Produce Different AES Results?

Question

We are trying to encrypt and encode URL parameters in Salesforce Marketing Cloud using the EncryptSymmetric() function with the AES algorithm. Following the documentation, we used the following AMPScript:

%%[SET @encData=EncryptSymmetric("test", "AES", @null, "1111", @null, "0000000000000000", @null, "00000000000000000000000000000000")
]%%
AES: %%=v(@encData)=%%

The function returned:

AT1r0irnzM+Ax1j8zN+zAw==

However, decrypting this value using an online AES tool resulted in an error. Encrypting the same string with an online AES-128 tool produced a different result:

l4Yo3sFofFD1EMmtoh397w==

This suggests that Salesforce’s AES implementation differs from standard AES encryption. How does EncryptSymmetric() handle AES? What are the key differences, and how can we ensure compatibility with external tools?

Answer

AES Encryption

The difference arises due to how Salesforce Marketing Cloud implements AES encryption in the EncryptSymmetric() function. Unlike standard AES encryption, Salesforce uses specific parameters that need to be correctly configured to match external encryption/decryption tools.

To ensure compatibility, use the following parameters when implementing AES encryption:

  • Block size: 16 bytes
  • Key size: 32 bytes
  • Key derivation: PBKDF2 with 1000 iterations
  • Padding: PKCS7

Here’s a Python implementation that correctly replicates the AES encryption used by EncryptSymmetric() in AMPScript:

import base64
from pprint import pprint
from Cryptodome.Cipher import AES
from Cryptodome.Protocol.KDF import PBKDF2
from Cryptodome.Util.Padding import pad

data = b'Example'
password = b'password'
salt = bytes.fromhex('0000000000000000')
iv = bytes.fromhex('00000000000000000000000000000000')

if __name__ == '__main__':
    block_size = 16
    key_size = 32
    key = PBKDF2(password, salt, key_size)  # PBKDF2 defaults to 1000 iterations

    cipher = AES.new(key, AES.MODE_CBC, iv)
    ct_bytes = cipher.encrypt(pad(data, block_size))  # pad defaults to PKCS7

    ct_b64 = base64.b64encode(ct_bytes).decode('utf-8')

    result = {
        'data': data.decode('utf-8'),
        'password': password.decode('utf-8'),
        'salt': salt.hex(),
        'iv': iv.hex(),
        'ciphertext': ct_b64,
    }
    print('Expected ciphertext: L2pjkUH92JSH4KyVY0jGxw==')
    pprint(result)

Explanation of the AES Encryption Code

This Python script performs AES encryption using the CBC (Cipher Block Chaining) mode and the PBKDF2 key derivation function. Below is a breakdown of its key components and how they work:

1. Importing Required Modules

import base64
from pprint import pprint
from Cryptodome.Cipher import AES
from Cryptodome.Protocol.KDF import PBKDF2
from Cryptodome.Util.Padding import pad

base64: Used to encode the encrypted data in a Base64 format for easy representation.pprint: Pretty prints dictionaries for better readability.Cryptodome.Cipher.AES: Provides AES encryption functionality.Cryptodome.Protocol.KDF.PBKDF2: Implements PBKDF2 (Password-Based Key Derivation Function 2) to generate a secure encryption key.Cryptodome.Util.Padding.pad: Applies PKCS7 padding to ensure the plaintext fits the AES block size.

2. Defining Input Data

data = b'Example'  
password = b'password'  
salt = bytes.fromhex('0000000000000000')  
iv = bytes.fromhex('00000000000000000000000000000000')  

data = b'Example': The plaintext data that will be encrypted (“Example”).password = b'password': The password used for key derivation.salt: A fixed 8-byte salt, represented as a hexadecimal string. It is used in PBKDF2 to add randomness and prevent dictionary attacks.iv: A 16-byte Initialization Vector (IV), represented as a hexadecimal string. IV is crucial in CBC mode to ensure different ciphertexts for the same plaintext.

3. Performing AES Encryption

block_size = 16  
key_size = 32  
key = PBKDF2(password, salt, key_size)  # PBKDF2 defaults to 1000 iterations  

block_size = 16: AES operates on 16-byte (128-bit) blocks.

key_size = 32: The key length is set to 32 bytes (256 bits) for AES-256 encryption.

PBKDF2(password, salt, key_size): Derives a 32-byte encryption key using PBKDF2 with 1000 iterations by default.

cipher = AES.new(key, AES.MODE_CBC, iv)  
ct_bytes = cipher.encrypt(pad(data, block_size))  # pad defaults to PKCS7  

AES.new(key, AES.MODE_CBC, iv): Creates an AES cipher object in CBC mode using the derived key and IV.pad(data, block_size): Ensures that data is properly padded using PKCS7 padding before encryption.cipher.encrypt(...): Encrypts the padded plaintext, producing raw ciphertext (ct_bytes).

ct_b64 = base64.b64encode(ct_bytes).decode('utf-8')  

Converts the ciphertext into a Base64-encoded string for easy storage and transmission.

4. Printing the Results

result = {  
    'data': data.decode('utf-8'),  
    'password': password.decode('utf-8'),  
    'salt': salt.hex(),  
    'iv': iv.hex(),  
    'ciphertext': ct_b64,  
}  

print('Expected ciphertext: L2pjkUH92JSH4KyVY0jGxw==')  
pprint(result)  

A dictionary result is created to store all relevant encryption details, including the plaintext, password, salt, IV, and the final ciphertext.The expected ciphertext (L2pjkUH92JSH4KyVY0jGxw==) is printed to verify correctness.pprint(result): Prints the dictionary in a readable format.

Final Output Example

When executed, the script outputs something like this:

Expected ciphertext: L2pjkUH92JSH4KyVY0jGxw==
{'ciphertext': 'L2pjkUH92JSH4KyVY0jGxw==',
 'data': 'Example',
 'iv': '00000000000000000000000000000000',
 'password': 'password',
 'salt': '0000000000000000'}

The critical components here are:

  1. Using PBKDF2 for key derivation, as EncryptSymmetric() implicitly derives the key using PBKDF2 with 1000 iterations.
  2. Setting the key size to 32 bytes (256-bit encryption).
  3. Ensuring the use of CBC mode with a 16-byte IV.
  4. Applying PKCS7 padding, which is required for block ciphers like AES.

By following these parameters, you can achieve encryption and decryption that is compatible with Salesforce Marketing Cloud’s EncryptSymmetric() function.

Job-Oriented Salesforce Training with 100% Money Back Assurance

Our Salesforce course is designed to provide an in-depth understanding of the Salesforce platform, equipping you with the essential skills to succeed in the CRM industry. The program covers fundamental modules like Salesforce Admin, Developer, and AI, combining theoretical learning with hands-on experience. Through real-world projects and practical exercises, you’ll develop the expertise to address complex business challenges using Salesforce solutions. Our experienced instructors ensure you gain both technical proficiency and industry knowledge to thrive in the Salesforce ecosystem.

In addition to technical training, our Salesforce training in Hyderabad offers personalized mentorship, certification support, and interview preparation to enhance your career prospects. You’ll benefit from comprehensive study materials, hands-on project experience, and dedicated guidance throughout the course. By the end of the program, you’ll be fully prepared for certification exams and real-world applications, possessing the problem-solving skills that employers value. Begin your Salesforce journey today and unlock exciting career opportunities. Sign up for a Free Demo now!

0
Would love your thoughts, please comment.x
()
x