Runtime verified

Syntax

EncryptSymmetric(value, algorithm, passwordExternalKey, password, saltExternalKey, salt, ivExternalKey, iv)  →  string
8 arguments — exactly

Parameters

Name Type Required Description
value string Yes The value to encrypt
algorithm string Yes Cipher name, optionally followed by semicolon-separated mode and padding settings
passwordExternalKey string Yes External key of a Key Management customer key holding the passphrase, or empty when the passphrase is supplied inline
password string Yes The passphrase itself, or empty when an external key is used
saltExternalKey string Yes External key holding the salt, or empty when the salt is supplied inline
salt string Yes The salt as a hex string, or empty when an external key is used
ivExternalKey string Yes External key holding the initialization vector, or empty when the IV is supplied inline
iv string Yes The initialization vector as a hex string, or empty when an external key is used

All eight arguments must be present. The three external-key positions and the three inline positions form pairs: fill one side of each pair and leave the other empty.

Example

%%[
  VAR @cipher
  SET @cipher = EncryptSymmetric(
    "SFMC probe 2026", "aes",
    @noKey, "zzThrowawayPhrase2026",
    @noKey, "0011223344556677",
    @noKey, "000102030405060708090a0b0c0d0e0f")
]%%
%%=v(@cipher)=%%

Renders Ig8oL30Et8hO0sELCyVakw== — 24 Base64 characters for a 15-character input.

@noKey is simply never assigned. An undeclared variable is how you say “no external key” inline; an empty string literal in the same position does exactly the same thing.

Round-tripping is the normal use, and both halves need the same four settings:

%%[
  VAR @plain, @cipher, @back
  SET @plain = AttributeValue("EmailAddress")
  SET @cipher = EncryptSymmetric(@plain, "aes", @noKey, @pw, @noKey, @salt, @noKey, @iv)
  SET @back   = DecryptSymmetric(@cipher, "aes", @noKey, @pw, @noKey, @salt, @noKey, @iv)
]%%

Never hard-code a real passphrase in a CloudPage the way the example above does with a throwaway value — use a Key Management customer key.

Return value

string — the ciphertext, Base64-encoded.

There is no sentinel value to test for. A rejected argument aborts the page rather than returning an error token, so a branch that renders nothing at all is the failure signal.

Behaviour

The round trip is exact, including non-ASCII. Encrypting a fixed ASCII string and decrypting it again in the same render returned the original byte for byte, and so did a string containing é and . Nothing in the pair is lossy.

The output is Base64, and its length follows the cipher’s block size rather than the input length. A 15-character plaintext produced 24 Base64 characters — 16 bytes, exactly one AES block, so a short input is padded up to the block boundary.

The ciphertext is deterministic. Two calls with byte-identical arguments in the same render produced the identical string. The initialization vector comes from the argument you pass, not from a fresh random value per call — which means equal plaintexts encrypt to equal ciphertexts. If you store these values, they are linkable: anyone who can see the column can tell which rows share a plaintext, without decrypting anything.

More cipher names work than the sources list. aes, des and tripledes were all accepted and all round-tripped, and the name is case-insensitive — AES behaves exactly like aes.

The algorithm argument also takes a compound form. A cipher name followed by semicolon-separated settings, such as des;mode=ecb;padding=zeros, is accepted — and the padding choice is visible in the result: under padding=zeros the decrypted value comes back with trailing padding characters, so the caller has to strip them.

An empty string and an omitted external key are interchangeable. Passing "" in the three external-key positions produced the same ciphertext as passing an undeclared variable.

All eight arguments are required, and a wrong count is a compile-time error. Seven and nine arguments each abort the page — and unlike a bad argument value, a wrong argument count kills every branch of the page, including ones that never run. You cannot hide an arity mistake behind a condition.

The named-key form is not covered here. Supplying a Key Management customer key in the external-key positions requires a key configured in Setup, which was not available on the business unit used for these checks. Everything above was proven with inline values only.

Show test script
%%[
  VAR @b, @asc, @non, @pw, @salt, @iv
  VAR @e1, @e1b, @d1, @e2, @d2
  SET @b = RequestParameter("b")
  SET @asc = "SFMC probe 2026"
  SET @non = Concat("caf", Char(233), Char(8364))
  SET @pw = "zzThrowawayPhrase2026"
  SET @salt = "0011223344556677"
  SET @iv = "000102030405060708090a0b0c0d0e0f"

  /* known-good control: renders on every request, so a run of HTTP 422s
     can be told apart from a broken deploy */
  OutputLine(Concat("CTRL=[", Base64Encode("Man"), "]"))

  /* round trip for ASCII and non-ASCII, ciphertext shape and length, and
     whether two identical calls produce the identical ciphertext */
  IF @b == "safe" THEN
    OutputLine(Concat("--- safe start ---"))
    SET @e1 = EncryptSymmetric(@asc, "aes", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    SET @e1b = EncryptSymmetric(@asc, "aes", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    SET @d1 = DecryptSymmetric(@e1, "aes", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    SET @e2 = EncryptSymmetric(@non, "aes", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    SET @d2 = DecryptSymmetric(@e2, "aes", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    OutputLine(Concat("E1=[", @e1, "] LEN=[", Length(@e1), "]"))
    OutputLine(Concat("DETERMINISTIC=[", IIF(@e1 == @e1b, "yes", "no"), "]"))
    OutputLine(Concat("ROUNDTRIP_ASCII=[", IIF(@d1 == @asc, "yes", "no"), "]"))
    OutputLine(Concat("ROUNDTRIP_NONASCII=[", IIF(@d2 == @non, "yes", "no"), "]"))
    OutputLine(Concat("--- safe done ---"))
  ENDIF

  /* the cipher name is case-insensitive */
  IF @b == "aesu" THEN
    OutputLine(Concat("--- aesu start ---"))
    SET @e1 = EncryptSymmetric(@asc, "AES", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    SET @d1 = DecryptSymmetric(@e1, "AES", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    OutputLine(Concat("AESU=[", @d1, "]"))
    OutputLine(Concat("--- aesu done ---"))
  ENDIF

  /* other accepted cipher names */
  IF @b == "des" THEN
    OutputLine(Concat("--- des start ---"))
    SET @e1 = EncryptSymmetric(@asc, "des", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    SET @d1 = DecryptSymmetric(@e1, "des", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    OutputLine(Concat("DES=[", @e1, "] BACK=[", @d1, "]"))
    OutputLine(Concat("--- des done ---"))
  ENDIF

  IF @b == "tdes" THEN
    OutputLine(Concat("--- tdes start ---"))
    SET @e1 = EncryptSymmetric(@asc, "tripledes", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    SET @d1 = DecryptSymmetric(@e1, "tripledes", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    OutputLine(Concat("TDES=[", @e1, "] BACK=[", @d1, "]"))
    OutputLine(Concat("--- tdes done ---"))
  ENDIF

  /* the compound cipher;mode;padding form - note the padding residue in
     the decrypted value */
  IF @b == "desmode" THEN
    OutputLine(Concat("--- desmode start ---"))
    SET @e1 = EncryptSymmetric(@asc, "des;mode=ecb;padding=zeros", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    SET @d1 = DecryptSymmetric(@e1, "des;mode=ecb;padding=zeros", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    OutputLine(Concat("DESMODE=[", @e1, "] BACK=[", @d1, "] BACKLEN=[", Length(@d1), "]"))
    OutputLine(Concat("--- desmode done ---"))
  ENDIF

  /* empty strings in the external-key positions behave like omitting them */
  IF @b == "emptyext" THEN
    OutputLine(Concat("--- emptyext start ---"))
    SET @e1 = EncryptSymmetric(@asc, "aes", "", @pw, "", @salt, "", @iv)
    SET @d1 = DecryptSymmetric(@e1, "aes", "", @pw, "", @salt, "", @iv)
    OutputLine(Concat("EMPTYEXT=[", @e1, "] BACK=[", @d1, "]"))
    OutputLine(Concat("--- emptyext done ---"))
  ENDIF
]%%

Availability

Platform Available
Marketing Cloud Engagement Yes
Marketing Cloud Next No

See also