Safeguard
Application Security•

ASVS 5.0 V11.3.5: Use Encrypt Then MAC Order

ASVS V11.3.5 requires that any encryption plus MAC combination runs in encrypt then MAC order. Prefer AEAD so you never choose the order yourself.

Safeguard Security Team
2 min read

ASVS 5.0 V11.3.5 (Level 3) requires that when you combine an encryption algorithm with a separate MAC, you encrypt first and then compute the MAC over the ciphertext. Verify the MAC before you attempt to decrypt.

Why it matters

MAC then encrypt, or MAC of the plaintext, forces the receiver to decrypt before checking integrity. That opens the door to padding oracles and other chosen ciphertext attacks.

How to implement it

The best fix is to avoid the question: use an AEAD mode such as AES GCM or ChaCha20 Poly1305, which does the right thing internally. If you must compose primitives:

import hmac, hashlib
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

def seal(enc_key, mac_key, iv, padded):
    ct = Cipher(algorithms.AES(enc_key), modes.CBC(iv)).encryptor()
    body = iv + ct.update(padded) + ct.finalize()
    tag = hmac.new(mac_key, body, hashlib.sha256).digest()
    return body + tag

On receipt, split off the tag, compare with hmac.compare_digest, and only then decrypt. Use separate keys for encryption and MAC.

How to test it

Review the code path: is the MAC input the ciphertext (including IV)? Does decryption happen only after a successful compare? Tamper with one ciphertext byte and confirm no decryption is attempted.

Common mistakes

  • MAC over plaintext
  • Omitting the IV from the MAC input
  • One key for both operations

Quick check

What is the simplest way to meet V11.3.5?

Use an AEAD cipher so the ordering is handled for you.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.