Cryptography Best Practices for Developers

Chapter 2 · Practice 1 of 4

Default to an AEAD: AES-GCM, ChaCha20-Poly1305 or XChaCha20-Poly1305

From Encrypting data with AEAD

Why it matters

An AEAD (authenticated encryption with associated data) encrypts the plaintext and produces a tag that fails verification if a single bit of the ciphertext, the nonce or the associated data changes. OWASP's Cryptographic Storage Cheat Sheet recommends:

  • AES with a key of at least 128 bits, ideally 256 bits
  • authenticated modes first: GCM or CCM
  • only if those are unavailable, CTR or CBC with separate authentication (Encrypt-then-MAC)
  • ECB should not be used outside very specific circumstances, because identical plaintext blocks produce identical ciphertext blocks

libsodium's AEAD documentation adds a practical choice: on CPUs with hardware AES support, AEGIS-256 is its safest pick; otherwise XChaCha20-Poly1305, which is portable to every architecture. Its AES256-GCM implementation needs hardware support (AES-NI or the ARM crypto extensions).

ConstructionKeyNonceWhere it fits
AES-256-GCM256 bits96 bitswide support, Web Crypto, cloud KMS
ChaCha20-Poly1305 (IETF)256 bits96 bitsTLS 1.3, devices without AES hardware
XChaCha20-Poly1305256 bits192 bitsrandom nonces with no practical message limit

Always decrypt with the library's single call and treat a failed tag check as "this data is not yours". Never return partial plaintext from a failed decryption.

Do

  • Use AES-256-GCM, ChaCha20-Poly1305 or XChaCha20-Poly1305
  • Treat any authentication failure as a hard error
  • Store algorithm and key ID beside each ciphertext

Avoid

  • AES-ECB for anything
  • CBC or CTR without a MAC
  • Decrypting before checking the tag in a streaming loop