EncryptCodecencryptcodec
Blog/Cryptography
CryptographyMarch 12, 2026 · 10 min read

AES vs RSA — Which Encryption Should You Use in Your App?

Should you encrypt that payload with AES or RSA? The answer depends on what you're protecting, who has the keys, and how fast it needs to be.

The One-Line Distinction

AES is for encrypting data. RSA is for encrypting keys.

That's 80% of what you need to know. If you're encrypting a file, a database field, or an API payload — use AES. If you're securely exchanging a secret between two parties who've never met — use RSA (or better, ECDH).

One key encrypts and decrypts

Why You Almost Always Want AES

AES (Advanced Encryption Standard) is a symmetric cipher — the same key encrypts and decrypts. It is:

  • 1000x faster than RSA for bulk data
  • Battle-tested — no known practical attacks against AES-256
  • Simple to use correctly with AES-GCM mode (authentication built in)
  • Available natively in every major language and platform

Here is AES-256-GCM encryption across the most common stacks:

// Works in browser and Node.js 16+
async function encrypt(plaintext, key32Bytes) {
const key = await crypto.subtle.importKey(
  "raw", key32Bytes, { name: "AES-GCM" }, false, ["encrypt"]
);
const iv = crypto.getRandomValues(new Uint8Array(12)); // fresh IV every time
const ciphertext = await crypto.subtle.encrypt(
  { name: "AES-GCM", iv }, key,
  new TextEncoder().encode(plaintext)
);
return { ciphertext, iv };
}

Use AES-256-GCM for: encrypting files, database fields, messages, API payloads, secrets at rest.

When RSA Makes Sense

RSA is asymmetric — a public key encrypts, a private key decrypts. This solves the key distribution problem: you can publish your public key and anyone can send you data only you can decrypt.

In practice, RSA is almost never used to encrypt data directly — it is too slow and has a hard size limit (~190 bytes for RSA-2048). Instead it is used to:

  • Encrypt an AES key (hybrid encryption)
  • Sign data digitally to verify authorship
// RSA encrypts the AES key, not the data itself
async function wrapAESKey(aesKey, rsaPublicKey) {
const raw = await crypto.subtle.exportKey("raw", aesKey);
return crypto.subtle.encrypt({ name: "RSA-OAEP" }, rsaPublicKey, raw);
}

Use RSA for: TLS handshakes, code signing, encrypted email (S/MIME), securely transmitting an AES key.

The Modern Alternative: ECDH + AES

If you need asymmetric key exchange, ECDH (Elliptic Curve Diffie-Hellman) beats RSA on every metric:

  • Smaller keys — 256-bit ECDH ≈ 3072-bit RSA security
  • Faster performance
  • Forward secrecy when used correctly

This is exactly how TLS 1.3 and Signal work. Two parties derive a shared AES key using ECDH, then encrypt data with AES-GCM.

async function deriveSharedKey(myPrivateKey, theirPublicKey) {
const shared = await crypto.subtle.deriveBits(
  { name: "ECDH", public: theirPublicKey }, myPrivateKey, 256
);
return crypto.subtle.importKey(
  "raw", shared, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]
);
}
// Now use the returned AES key to encrypt data with AES-GCM

Decision Table

What you are doingUse this
Encrypting data at restAES-256-GCM
Encrypting data in transitTLS (handles it for you)
Sharing an AES key with a recipientRSA-OAEP or ECDH
Verifying data integrity / authorshipHMAC-SHA256 or RSA/ECDSA signatures
Storing passwordsbcrypt, Argon2 — not AES
Real-time messaging, E2E encryptionECDH + AES-GCM

Common Mistakes

Using RSA to encrypt large data

RSA-2048 can only encrypt ~190 bytes. The fix: use RSA to encrypt an AES key, use AES for the data itself.

Using AES-CBC instead of AES-GCM

AES-CBC has no built-in authentication — an attacker can tamper with the ciphertext without detection. Always use AES-GCM, which authenticates and encrypts in one step.

Reusing IVs

Reusing the same IV with the same AES key completely breaks AES-GCM security. Always generate a fresh random IV per encryption operation:

// ✅ correct — fresh random IV every time
const iv = crypto.getRandomValues(new Uint8Array(12));

// ❌ wrong — reusing a static IV destroys AES-GCM security
const iv = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);

Hashing passwords with AES or SHA-256

SHA-256 is too fast — attackers compute billions of hashes per second. Use bcrypt or Argon2 which are intentionally slow and memory-hard.

Share this post

Try AES-256-GCM encryption in your browser

No signup, no server — just paste and encrypt.

Frequently Asked Questions

Related posts