Back to Blog
SecurityCryptographyAESRSABackendWeb Development

Modern Web Cryptography: Hashing, Symmetric AES Encryption, and Asymmetric Key Management

Written by Dev Toolkit Editorial
•
July 15, 2026
•10 MIN READ

Master fundamental cryptographic primitives in modern web applications. Learn when to use cryptographic hashing, symmetric AES-256 encryption, asymmetric RSA key pairs, and secure secret management.

Transport Layer Security (TLS/HTTPS) protects data in transit across the public internet. However, modern full-stack applications frequently require additional application-layer security measures to safeguard data at rest, verify message integrity, authenticate API payloads, and manage zero-trust user sessions.

Whether you are encrypting sensitive user fields in a database, generating API authentication codes, or configuring asymmetric key pairs for microservice authentication, understanding cryptographic primitives is essential for building resilient web systems.

In this guide, we will explore the core pillars of web cryptography—Cryptographic Hashing, Message Authentication Codes (MACs), Symmetric Encryption (AES), and Asymmetric Cryptography (RSA/ECC)—and demonstrate how to apply them safely in modern web development workflows.


1. Cryptographic Hash Functions: SHA-256 and Integrity Checksums

A cryptographic hash function takes an arbitrary input string or binary payload and converts it into a fixed-length sequence of bytes known as a digest. In practice, this binary digest is represented as a hexadecimal or Base64-encoded string for transport and storage. Cryptographic hashes are strictly one-way operations: it is mathematically infeasible to reverse a cryptographic hash digest to recover the original input data.

Key Properties of Cryptographic Hashes

  • Deterministic: The same input payload will always produce the exact same output hash digest.
  • Pre-image Resistance: Given a digest \(H\), it is computationally infeasible to find an input \(M\) such that \(\text{Hash}(M) = H\).
  • Collision Resistance: It is computationally infeasible to find two distinct inputs \(M_1\) and \(M_2\) such that \(\text{Hash}(M_1) = \text{Hash}(M_2)\).
  • Avalanche Effect: Changing even a single bit in the input radically and unpredictably alters the resulting hash digest.

Common Use Cases

  1. File & Payload Integrity Checksums: Verifying that downloaded binaries, software artifacts, or uploaded files have not been corrupted during transfer.
  2. API Key Identifiers: Storing SHA-256 digests of API keys in your database. When a client presents an API key, the server computes its SHA-256 hash and compares it against the stored digest, allowing instant key verification without ever persisting the raw plain-text secret.
  3. Content Identifiers: Creating deterministic content-based hashes (such as Git commit SHAs or CID content identifiers).

Browser Web Crypto API: SHA-256 Example

The standard Web Crypto API (window.crypto.subtle in browsers and globalThis.crypto.subtle in modern Node.js environments) is built natively into JavaScript runtimes:

// Browser-compatible SHA-256 hash calculation using Web Crypto API
async function computeSHA256(message: string): Promise<string> {
  const encoder = new TextEncoder();
  const data = encoder.encode(message);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  
  // Convert binary ArrayBuffer to a human-readable hexadecimal string
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

Critical Note on Password Storage: Never use standard cryptographic hash functions like SHA-256 or SHA-512 directly for user passwords. Fast general-purpose hash functions are designed for high throughput, making them vulnerable to offline GPU-accelerated brute-force attacks. For password storage, always use slow password-hashing algorithms with unique per-user salts:

  • Argon2id and scrypt: Memory-hard algorithms designed to resist GPU/ASIC hardware acceleration.
  • bcrypt: Incorporates an adaptive computational work factor based on Blowfish key expansion.

2. Message Authentication Codes (MACs) vs. Digital Signatures

A common point of confusion in web security is the difference between a Message Authentication Code (MAC) and a Digital Signature. Both guarantee message integrity and authenticity, but they rely on fundamentally different key paradigms:

Symmetric Message Authentication (e.g., HMAC)

A Hash-based Message Authentication Code (HMAC) combines a cryptographic hash function with a shared secret key. Both the sender and receiver possess the exact same secret key.

  • Symmetric Key: Sender computes \(\text{HMAC}(K, M)\) and attaches it to the webhook or payload. The recipient recomputes the HMAC using the shared secret \(K\) and compares the values in constant time.
  • Authentication & Integrity: Confirms the payload was produced by a holder of the shared secret and has not been altered.
  • No Non-Repudiation: HMAC does not provide non-repudiation because both parties hold the same secret key; either party could technically generate a valid MAC tag.

Asymmetric Digital Signatures

A Digital Signature uses an asymmetric key pair. The sender signs the payload using their private key, and anyone can verify the signature using the sender’s public key.

  • Asymmetric Keys: The private key generates the signature; the public key verifies it.
  • Non-Repudiation: Only the private key holder could have generated a valid signature, providing mathematical proof of authorship.

HMAC vs. Digital Signatures Comparison


3. Symmetric Encryption: AES-256-GCM and AEAD

Unlike one-way hashing, encryption is a reversible two-way operation: plaintext data is converted into ciphertext using an encryption key, and can later be decrypted back into its original plaintext form using the key.

In symmetric encryption, the exact same key is used for both encryption and decryption.

Symmetric AEAD (AES-GCM) Encryption Flow

Authenticated Encryption with Associated Data (AEAD)

Modern cryptography mandates the use of Authenticated Encryption with Associated Data (AEAD) algorithms, such as AES-256-GCM (Galois/Counter Mode) or ChaCha20-Poly1305.

  • Confidentiality & Authenticated Integrity: AES-GCM provides data confidentiality (preventing unauthorized reading) and generates a 128-bit authentication tag that detects bit-flipping attacks or tampering.
  • Initialization Vector (IV) / Nonce: AES-GCM requires a unique 96-bit (12-byte) nonce (“number used once”) for every single encryption operation under a given key. While software APIs (including Web Crypto) frequently name this parameter “IV”, “nonce” highlights its critical constraint: never reuse a nonce with the same key. Nonce reuse in counter-mode ciphers degrades confidentiality and can expose plaintext.
  • Binary Ciphertext & Transport Representation: Encryption algorithms operate on and produce raw binary byte arrays. To transmit ciphertext in JSON payloads, HTTP headers, or database columns, encode the resulting binary ciphertext and nonce into Base64 or Hexadecimal format.

Browser Web Crypto API: AES-256-GCM Example

// Helper: Convert Uint8Array to Hex String representation
function bufToHex(buffer: ArrayBuffer): string {
  return Array.from(new Uint8Array(buffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}

// Encrypt plaintext using AES-256-GCM in the browser
async function encryptAESGCM(plaintext: string, rawKeyBytes: Uint8Array) {
  // Validate that key material is exactly 256 bits (32 bytes)
  if (rawKeyBytes.length !== 32) {
    throw new Error('AES-256 requires exactly 32 bytes (256 bits) of key material.');
  }

  const encoder = new TextEncoder();
  
  // Import raw key bytes as CryptoKey
  const key = await crypto.subtle.importKey(
    'raw',
    rawKeyBytes,
    { name: 'AES-GCM', length: 256 },
    false,
    ['encrypt', 'decrypt']
  );

  // Generate a cryptographically secure 96-bit (12-byte) nonce/IV
  const iv = crypto.getRandomValues(new Uint8Array(12));

  // Encrypt: Web Crypto appends the 16-byte (128-bit) Auth Tag to the ciphertext
  const encryptedBuffer = await crypto.subtle.encrypt(
    { name: 'AES-GCM', iv },
    key,
    encoder.encode(plaintext)
  );

  return {
    ciphertextHex: bufToHex(encryptedBuffer),
    ivHex: bufToHex(iv)
  };
}

4. Asymmetric Cryptography: RSA Key Pairs & JWT Verification

In distributed architectures, sharing a single symmetric key across dozens of microservices creates significant key distribution risks. If any single service is compromised, the shared secret is exposed across the entire network.

Asymmetric Cryptography solves this problem by using a mathematically linked pair of keys:

  1. Public Key: Distributed freely to clients, gateways, and third-party verifiers. Used to encrypt data (RSA-OAEP) or verify digital signatures (RSA-PSS / RS256).
  2. Private Key: Kept strictly secret on the issuing authentication server. Used to decrypt data or create digital signatures.

Standard RSA Key Sizes & Schemes

  • Key Sizes: Modern RSA keys should be at least 2048-bit, though 3072-bit or 4096-bit keys are strongly recommended for long-term security.
  • Encryption Padding: Use RSA-OAEP (Optimal Asymmetric Encryption Padding) with SHA-256. Avoid legacy PKCS#1 v1.5 encryption padding due to padding oracle vulnerabilities.
  • Signature Schemes: RSA-PSS (PS256) is the recommended standard for new RSA signature designs due to its formal security proofs. RS256 (RSA PKCS#1 v1.5 signature) remains widely deployed across open standards like JSON Web Tokens (JWT). Modern systems also leverage distinct Elliptic Curve signature algorithms, such as Ed25519 (EdDSA) or ECDSA (P-256), offering smaller key sizes and higher performance.

Asymmetric Auth Server (IDP) Token Verification Flow

Comprehensive JWT Validation Checklist

When validating incoming JSON Web Tokens (JWTs) in API gateways, do not rely on signature verification alone. Always validate:

  1. Signature Verification: Verify signature using the public key or shared secret.
  2. Explicit Algorithm Whitelist: Configure the expected signing algorithm explicitly on the application server rather than trusting the alg header parameter in the incoming token. Strictly reject tokens with alg: "none" or mismatched key types (preventing algorithm confusion and key substitution attacks).
  3. Expiration (exp): Reject expired tokens.
  4. Not Before (nbf): Ensure current time is after the nbf timestamp.
  5. Issued At (iat): Verify reasonable issuance timestamp bounds.
  6. Issuer (iss): Confirm the token was issued by your trusted Identity Provider.
  7. Audience (aud): Ensure the token was intended specifically for your API scope.

5. Encoding vs. Encryption: Common Pitfalls

A frequent security mistake in web engineering is confusing data encoding with encryption.

  • Base64 / Base64URL Encoding: Transforms binary data or text strings into ASCII characters to prevent character corruption during HTTP transport. Base64 is not encryption or security. Anyone can decode Base64 instantly without a key.
  • Encryption: Obfuscates plaintext using a secret key and randomized nonce, producing binary ciphertext that is computationally impossible to read without the key.

Encoding vs Encryption Primitive Comparison


6. Best Practices for Modern Application Security

  1. Never Roll Your Own Crypto: Always rely on standard, peer-reviewed libraries and browser primitives (Web Crypto API, node:crypto, or libsodium).
  2. Secure Key Management: Never commit secret keys, private keys, or credentials to version control. Store secrets in environment variables managed by a Key Management Service (AWS KMS, GCP KMS, or HashiCorp Vault).
  3. Browser Cookie & Storage Security: When storing session tokens in cookies, set the Secure and HttpOnly flags. Choose SameSite=Strict or SameSite=Lax based on your application’s cross-site navigation requirements. Avoid storing long-lived authentication tokens or high-privilege secrets in browser localStorage or sessionStorage, as these storage mechanisms are accessible to client-side JavaScript and vulnerable to Cross-Site Scripting (XSS) attacks.
  4. Key Rotation: Design key management infrastructure to support routine key rotation and versioning (such as kid headers in JWKS endpoints).

7. Cryptographic Task Quick Reference

Task Recommended Primitive / Algorithm Anti-Pattern / Insecure Choice
Data at Rest (Field-Level) AES-256-GCM or ChaCha20-Poly1305 AES-ECB, unauthenticated AES-CBC, IV reuse
Password Storage Argon2id, bcrypt, or scrypt Plain SHA-256, SHA-512, MD5, or un-salted hashes
Webhook Authentication HMAC-SHA256 (Symmetric MAC) Unsigned HTTP POST payloads
Asymmetric Signatures / JWT RS256 (RSA-2048/4096), PS256, or Ed25519 Weak HS256 keys, alg: "none", missing claim checks
Asymmetric Data Encryption RSA-OAEP with SHA-256 RSA PKCS#1 v1.5 or raw RSA encryption
Random Value Generation crypto.getRandomValues() Math.random() (Pseudo-random, predictable)

Further Reading & Resources

Interactive Tools

  • /hash-generator/ – Compute SHA-256, SHA-512, and MD5 digests offline.
  • /aes-cipher/ – Encrypt and decrypt text strings locally using AES-GCM or AES-CBC.
  • /rsa-generator/ – Generate 2048-bit and 4096-bit RSA public and private key pairs.
  • /jwt-debugger/ – Decode JWT payloads and verify signatures offline.