Runtime verified

Syntax

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

Parameters

Name Type Required Description
encryptedValue string Yes The Base64 ciphertext to decrypt
algorithm string Yes Cipher name, optionally followed by semicolon-separated mode and padding settings; must match what was used to encrypt
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, and all four settings — algorithm, passphrase, salt and IV — must match the ones used to encrypt.

Example

%%[
  VAR @plain
  SET @plain = DecryptSymmetric(
    "Ig8oL30Et8hO0sELCyVakw==", "aes",
    @noKey, "zzThrowawayPhrase2026",
    @noKey, "0011223344556677",
    @noKey, "000102030405060708090a0b0c0d0e0f")
]%%
%%=v(@plain)=%%

Renders SFMC probe 2026. The ciphertext is a plain transportable string, so it can be stored, passed through a link, or hard-coded like this — it is not an in-render handle.

The usual shape is decrypting something that arrived from outside the page:

%%[
  VAR @token, @plain
  SET @token = RequestParameter("t")
  SET @plain = DecryptSymmetric(@token, "aes", @noKey, @pw, @noKey, @salt, @noKey, @iv)
]%%

@noKey is simply never assigned — an undeclared variable is how you say “no external key” inline, and an empty string literal does the same thing.

Return value

string — the decrypted plain text.

There is no sentinel value to test for. A branch that renders nothing at all is the failure signal.

Behaviour

The round trip is exact, including non-ASCII. A fixed ASCII string and a string containing é and each came back byte for byte identical to the original when encrypted and decrypted in the same render with the same arguments.

The cipher names accepted match the encrypt side, and the name is case-insensitive. aes, AES, des and tripledes each returned the original plaintext, every one exercised through an actual DecryptSymmetric call rather than assumed from its inverse.

The compound form works, and the padding scheme is visible in the result. des;mode=ecb;padding=zeros decrypted successfully, but the returned string carried trailing padding characters instead of ending at the original plaintext — measure the length rather than trusting that the value ends where you expect.

An empty string and an omitted external key are interchangeable. Passing "" in the three external-key positions returned the same plaintext 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 takes down every branch of the page, including ones that are never selected. An arity mistake cannot be hidden behind a condition.

What happens on bad input is not established here. Decrypting with a wrong passphrase, a wrong salt, or a malformed or truncated ciphertext could not be pinned down: those cases sat in a page that was already aborting for an unrelated compile-time reason, so their failures say nothing about the function. Treat the outcome as unknown and validate the input before you rely on it.

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, @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 in the same render */
  IF @b == "safe" THEN
    OutputLine(Concat("--- safe start ---"))
    SET @e1 = 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("D1=[", @d1, "]"))
    OutputLine(Concat("ROUNDTRIP_ASCII=[", IIF(@d1 == @asc, "yes", "no"), "]"))
    OutputLine(Concat("ROUNDTRIP_NONASCII=[", IIF(@d2 == @non, "yes", "no"), "]"))
    OutputLine(Concat("--- safe done ---"))
  ENDIF

  /* the ciphertext is a plain transportable string, not an in-render handle:
     this is the value the safe branch printed, hard-coded */
  IF @b == "literal" THEN
    OutputLine(Concat("--- literal start ---"))
    SET @d1 = DecryptSymmetric("Ig8oL30Et8hO0sELCyVakw==", "aes", @noKey, @pw, @noKey, @salt, @noKey, @iv)
    OutputLine(Concat("LITERAL=[", @d1, "]"))
    OutputLine(Concat("--- literal done ---"))
  ENDIF

  /* the cipher name is case-insensitive on the decrypt side too */
  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_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_BACK=[", @d1, "]"))
    OutputLine(Concat("--- tdes done ---"))
  ENDIF

  /* the compound cipher;mode;padding form - the padding residue shows up in
     the decrypted value, so compare BACKLEN against the plaintext length */
  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_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_BACK=[", @d1, "]"))
    OutputLine(Concat("--- emptyext done ---"))
  ENDIF
]%%

Availability

Platform Available
Marketing Cloud Engagement Yes
Marketing Cloud Next No

See also