Loading content...
When WhatsApp announced end-to-end encryption for all messages in 2016, it extended unbreakable privacy protection to over a billion users overnight. This wasn't mere marketing—it was a fundamental technical guarantee: messages are encrypted on the sender's device in such a way that only the intended recipient can decrypt them. Not WhatsApp, not governments, not hackers who breach WhatsApp's servers.
End-to-end encryption (E2EE) represents one of the most significant privacy technologies of our time. But implementing it at scale introduces profound complexity. How do you establish shared secrets with someone you've never met? How do you maintain security when users switch phones? What happens when someone joins a group chat—can they read old messages?
This page takes you deep into the cryptography and system design that makes E2EE possible, focusing on the Signal Protocol—the gold standard that powers WhatsApp, Signal, Facebook Messenger's secret conversations, and Google Messages.
You will understand the Signal Protocol's key exchange (X3DH), the Double Ratchet Algorithm for forward secrecy, how group encryption works, the challenges of multi-device support, and the architectural implications of building systems where the server cannot see message content. This knowledge is essential for any security-conscious system design.
Before diving into cryptographic protocols, let's understand what E2EE protects against and why it's fundamentally different from transport encryption.
| Aspect | Transport Encryption (TLS) | End-to-End Encryption |
|---|---|---|
| Encryption scope | Client ↔ Server, Server ↔ Client | Client ↔ Client (server has only ciphertext) |
| Key knowledge | Server has keys; can decrypt | Only endpoints have keys; server cannot decrypt |
| Server breach impact | All messages exposed | Only metadata exposed; content remains encrypted |
| Legal compulsion | Server can be compelled to provide content | Server genuinely cannot provide content |
| Implementation complexity | Standard TLS libraries | Custom protocol + key management |
| Feature limitations | None—server can process content | No server-side search, spam filtering, content moderation |
E2EE protects against:
1. Server compromise: If attackers breach WhatsApp's servers, they get only encrypted blobs. Without users' private keys (which never leave devices), the content is unrecoverable.
2. Insider threats: Malicious employees cannot read messages—they simply don't have the keys.
3. Legal demands: When governments demand message content, the company can truthfully say they cannot decrypt it.
4. Network interception: Even if traffic is intercepted (e.g., via compromised ISP), content remains encrypted.
What E2EE does NOT protect against:
E2EE protects message content but not metadata: who messaged whom, when, how often, and from where. This metadata can be extremely revealing. The NSA famously said 'We kill people based on metadata.' Protecting metadata requires additional techniques like sealed sender (Signal) or onion routing (Tor).
The Signal Protocol combines several cryptographic primitives. Understanding these building blocks is essential before we examine how they're assembled.
The foundation of key exchange. Two parties, each with a private/public key pair, can compute a shared secret without ever transmitting that secret:
Alice has: (a, A) where A = a·G (a is private, A is public)
Bob has: (b, B) where B = b·G (b is private, B is public)
Alice computes: shared = a·B = a·(b·G) = (a·b)·G
Bob computes: shared = b·A = b·(a·G) = (b·a)·G
Result: Both arrive at the same point (a·b)·G
Even knowing A, B, and G, an eavesdropper cannot compute (a·b)·G
without solving the Elliptic Curve Discrete Logarithm Problem (hard).
Used for: Establishing shared secrets between users who may never have communicated before.
| Primitive | Purpose | Typical Algorithm |
|---|---|---|
| Key Exchange | Establish shared secret | X25519 (Curve25519 ECDH) |
| Digital Signature | Authenticate key ownership | Ed25519 (EdDSA) |
| Symmetric Encryption | Encrypt message content | AES-256-GCM |
| Key Derivation | Derive multiple keys from shared secret | HKDF (HMAC-based KDF) |
| MAC | Message authentication | HMAC-SHA256 |
| Hash Function | One-way transformation | SHA-256 |
Two critical security properties that distinguish E2EE from simple encryption:
Forward Secrecy (FS): Compromise of current keys does not allow decryption of past messages. Even if your key is stolen today, everything you sent before remains secure.
Post-Compromise Security (PCS): Also called 'self-healing' or 'future secrecy.' After a key compromise, the system automatically recovers security for future messages without user intervention.
The Signal Protocol achieves both through the Double Ratchet Algorithm, which continuously evolves encryption keys.
Most encryption systems lack forward secrecy: if someone steals your key, they can decrypt all past messages. Signal's approach means that even if your phone is seized and keys extracted, investigators can only read the handful of most recent messages—not your entire history.
The first challenge in E2EE messaging: how do Alice and Bob establish a shared secret if Bob is offline when Alice wants to send her first message? The X3DH (Extended Triple Diffie-Hellman) protocol solves this elegantly.
In traditional Diffie-Hellman, both parties must be online simultaneously to exchange ephemeral keys. Messaging requires asynchonous initiation:
Traditional DH:
Alice: "Here's my ephemeral public key EKA"
Bob: "Here's mine EKB. Let's compute shared = ECDH(EKA, EKB)"
Problem: Bob must be online to respond.
Messaging reality:
Alice: "Hi Bob!" (Bob's phone is off)
[24 hours pass]
Bob comes online, should receive Alice's message.
Solution: Bob pre-generates and uploads prekeys to the server. Alice can fetch Bob's prekeys and initiate communication without Bob being online.
1234567891011121314151617181920212223
Bob's Key Bundle (stored on server):━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1. Identity Key (IKB) └── Long-term public key, represents Bob's identity └── Signed by Bob's device, verified by others └── Changed rarely (device reinstall) 2. Signed Prekey (SPKB) └── Medium-term key, rotated periodically (weekly/monthly) └── Signed by Identity Key (proves Bob generated it) └── Signature included for verification 3. One-Time Prekeys (OPKB1, OPKB2, ... OPKBn) └── Ephemeral keys, used once then deleted └── Client generates many (100+), uploads to server └── Server hands out one per new conversation └── Provides extra forward secrecy for initial message Why multiple key types?• Identity Key: Permanent identity, allows verification• Signed Prekey: Limits damage if one-time prekeys exhausted• One-Time Prekeys: Optimal forward secrecy for session initiationWhen Alice initiates a conversation with Bob:
12345678910111213141516171819202122232425262728293031
ALICE SERVER BOB │ │ │ │ 1. Request Bob's key bundle │ │ │ ─────────────────────────────►│ │ │ │ │ │ 2. Return: IKB, SPKB, OPKB │ │ │ ◄─────────────────────────────│ │ │ │ (Delete OPKB from server) │ │ │ │ │ 3. Generate ephemeral key EKA │ │ │ │ │ │ 4. Compute DH values: │ │ │ DH1 = DH(IKA, SPKB) │ Alice's identity, Bob's signed prekey │ DH2 = DH(EKA, IKB) │ Alice's ephemeral, Bob's identity │ DH3 = DH(EKA, SPKB) │ Alice's ephemeral, Bob's signed prekey │ DH4 = DH(EKA, OPKB) │ Alice's ephemeral, Bob's one-time prekey │ │ │ 5. SK = KDF(DH1 || DH2 || DH3 || DH4) │ Master secret derived from all DH values │ │ │ 6. Send initial message: │ │ │ {IKA, EKA, OPKB_id, │ │ │ encrypted_message} │ │ │ ─────────────────────────────►│ ────────────────────────────►│ │ │ │ │ │ 7. Bob receives, computes │ │ │ same DH values using his │ │ │ private keys, derives SK │ │ │ │ │ │ 8. Bob decrypts message │ │ │ using derived key │Mutual Authentication: Both parties' identity keys are in the DH calculation. Neither can be impersonated without the identity private key.
Forward Secrecy: The ephemeral key EKA and one-time prekey OPKB are used once and deleted. Compromising identity keys later doesn't reveal this session's secrets.
Deniability: The protocol provides cryptographic deniability—there's no signature on messages that could prove Alice sent them. Anyone with Bob's keys could have constructed the conversation.
If Bob doesn't come online to replenish prekeys, they can be exhausted. The protocol falls back to just three DH computations (without DH4). Security is slightly reduced but still strong. Clients monitor prekey counts and upload new ones periodically.
X3DH establishes a shared secret for the conversation's first message. But using the same key for all messages is dangerous—compromise of that key exposes everything. The Double Ratchet Algorithm continuously evolves keys, providing forward secrecy for every individual message.
The 'double' in Double Ratchet refers to two interlocking mechanisms:
1. Symmetric-Key Ratchet (KDF Chain): A one-way chain of keys derived from the previous key:
ChainKey_0 → KDF → ChainKey_1 → KDF → ChainKey_2 → ...
↓ ↓
MessageKey_1 MessageKey_2
Each message uses a unique MessageKey derived from the current ChainKey. ChainKeys are then ratcheted forward. Old ChainKeys are deleted.
2. Diffie-Hellman Ratchet: Periodically, parties exchange new ephemeral DH keys, computing a fresh shared secret that's mixed into the chain:
Party A: New ephemeral key pair (a, A)
Party B: Receives A, computes DH(B_priv, A) = new_shared_secret
This resets/strengthens the chain.
The DH ratchet provides post-compromise security: even if an attacker learns current ChainKeys, the next DH ratchet step generates new keys they cannot compute.
123456789101112131415161718192021222324252627282930313233343536373839
ALICE BOB │ │ │ ═══════ Initial X3DH Handshake ═══════│ │ Root Key (RK₀) established │ │ │ │ ──────────── DH Ratchet #1 ────────── │ │ Alice generates (a₁, A₁) │ │ Sends A₁ with first message │ │ │ │ ┌─────────────────────────┐ │ │ │ RK₁, CK_sending = KDF( │ │ │ │ RK₀, DH(a₁, B_pub) │ │ │ │ ) │ │ │ └─────────────────────────┘ │ │ Message 1 ──────────────────────────► │ │ encrypted with MK₁ from CK │ │ │ │ Message 2 ──────────────────────────► │ │ CK ratcheted, encrypted with MK₂ │ │ │ │ ──────────── DH Ratchet #2 ────────── │ │ │ Bob generates (b₁, B₁) │ ◄────────────────────────── Message 3 │ │ Gets B₁ │ encrypted with his sending CK │ │ │ Alice computes DH(a₁, B₁) │ │ Derives new RK, CK for receiving │ │ │ │ ──────────── DH Ratchet #3 ────────── │ │ Alice generates new (a₂, A₂) │ │ Message 4 ──────────────────────────► │ │ │ │ ... continues alternating ... │ KEY INSIGHT:• Each DH ratchet step introduces fresh randomness• Compromise of keys at time T doesn't reveal keys at T+1• Old keys are deleted → forward secrecy• New DH values heal from compromise → post-compromise securityNetwork delays mean messages may arrive out of order. The Double Ratchet must handle this:
Message keys are stored temporarily: If message #5 arrives before #4, we skip ahead in the chain, deriving and storing MK₄. When message #4 arrives, we use the stored key.
Ratchet state includes counters: Each message carries (DH_ratchet_number, chain_position). This allows the receiver to locate the correct key.
Security consideration: Storing message keys for skipped messages slightly weakens forward secrecy for those specific messages during the storage window. Keys are deleted after a timeout or limit.
The symmetric ratchet alone provides forward secrecy but not post-compromise security (if someone learns the chain key, they can derive all future keys). The DH ratchet alone is expensive (DH computation per message). Combining both: symmetric ratchet for efficiency (multiple messages per DH round), DH ratchet for post-compromise security (periodic fresh secrets).
Encrypting for groups introduces new challenges. The naive approach—running N separate Double Ratchet sessions for an N-member group—doesn't scale. WhatsApp's Sender Keys protocol provides efficient group encryption.
Naive approach (pairwise encryption):
Broadcast encryption:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
SENDER KEYS PROTOCOL━━━━━━━━━━━━━━━━━━━━ Concept: Each group member generates a "Sender Key" for that group.Messages from that member are encrypted with their Sender Key.All other members receive the Sender Key via pairwise channels. STEP 1: SENDER KEY DISTRIBUTION───────────────────────────────Alice joins group with [Bob, Carol, Dave] Alice generates: • SenderKey_Alice = random_key() • SenderChain_Alice = initial_chain_key() • SenderSigningKey_Alice = keypair() Alice sends SenderKey to each member via existing pairwise E2EE channel: Alice ──[via 1:1 E2EE]──► Bob: {SenderKey_Alice, SigningKey_Alice_pub} Alice ──[via 1:1 E2EE]──► Carol: {SenderKey_Alice, SigningKey_Alice_pub} Alice ──[via 1:1 E2EE]──► Dave: {SenderKey_Alice, SigningKey_Alice_pub} Cost: O(n) pairwise messages to distribute keys STEP 2: SENDING MESSAGES────────────────────────Alice sends message to group: 1. Derive message key from chain: MK = ratchet(SenderChain_Alice)2. Encrypt: ciphertext = AES(MK, plaintext)3. Sign: signature = Sign(SenderSigningKey_Alice, ciphertext)4. Broadcast: {ciphertext, signature, chain_counter} Bob, Carol, Dave receive:1. Look up Alice's sender key for this group2. Derive same message key using chain_counter3. Verify signature4. Decrypt: plaintext = AES(MK, ciphertext) Cost: O(1) for sender, O(1) for each receiver STEP 3: MEMBER CHANGES (THE HARD PART)──────────────────────────────────────New member joins: • All existing members send their Sender Keys to new member • O(n) key distribution • New member CANNOT decrypt old messages (forward secrecy for group) Member removed: • Removed member knows everyone's Sender Keys! • Everyone must generate NEW Sender Keys and redistribute • O(n²) key distribution in worst case • Critical for security: removed members can't read future messagesSender Keys advantages:
Sender Keys limitations:
MLS (Message Layer Security): The IETF is standardizing a new protocol that provides better scaling for large groups using tree-based key agreement. Future messaging systems may adopt MLS for improved efficiency.
Removing a member from an E2EE group is inherently expensive. The removed member has everyone's sender keys. You MUST regenerate all keys to prevent them reading future messages. For a 1000-member group, this means 999,000 key distribution messages over pairwise channels. This is why 'remove member' is slow in large E2EE groups.
Users expect to access messages from their phone, tablet, desktop, and web browser simultaneously. But E2EE complicates multi-device: each device has its own keys, and the server cannot decrypt messages to relay them between devices.
In a non-E2EE system:
Alice sends to Bob → Server stores message →
Bob's Phone fetches message
Bob's Desktop fetches message
Bob's Tablet fetches message
With E2EE, each of Bob's devices has a different identity key. A message encrypted for Bob's Phone cannot be decrypted by Bob's Desktop.
Approaches to multi-device E2EE:
| Approach | How It Works | Trade-offs |
|---|---|---|
| Per-device encryption | Sender encrypts separately for each device | O(devices) encryption; full E2EE guarantees |
| Primary device relay | Secondary devices fetch from primary phone | Requires primary online; single point of failure |
| Shared key across devices | All devices share same private key | Key sync is risky; compromise of one compromises all |
| Device group protocol | Treat user's devices as a 'group' | Complex; Signal's current approach |
Signal introduced a sophisticated multi-device solution in 2021:
Each device is a separate identity: Bob's phone has (IK_phone), desktop has (IK_desktop). He's effectively multiple 'users' with linked accounts.
Senders encrypt for each device: When Alice messages Bob, she actually encrypts for IK_phone AND IK_desktop. The server delivers both ciphertexts.
Device group for sent messages: When Bob sends a message, he also encrypts it for his other devices so they have his sent messages too.
Key linking: Devices are cryptographically linked during a pairing process. The primary device vouches for secondary devices.
1234567891011121314151617181920212223242526272829303132
ALICE sends "Hello" to BOB (who has 3 devices)━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1. Alice's app queries: "What devices does Bob have?" Server returns: [device_1_pubkey, device_2_pubkey, device_3_pubkey] 2. Alice encrypts separately for each device: ciphertext_1 = E2EE(device_1_pubkey, "Hello") ciphertext_2 = E2EE(device_2_pubkey, "Hello") ciphertext_3 = E2EE(device_3_pubkey, "Hello") 3. Alice sends all ciphertexts to server: { recipient: "bob", device_ciphertexts: [ {device_id: 1, ciphertext: ciphertext_1}, {device_id: 2, ciphertext: ciphertext_2}, {device_id: 3, ciphertext: ciphertext_3} ] } 4. Server delivers to each of Bob's online devices: Phone: receives ciphertext_1, decrypts with device_1_privkey Desktop: receives ciphertext_2, decrypts with device_2_privkey Tablet: receives ciphertext_3, decrypts with device_3_privkey 5. All devices show "Hello" from Alice IMPLICATIONS:• Sender's work scales with recipient's device count• Message size on wire scales with device count• Adding a device requires notifying all contactsMulti-device has practical limits. If Bob has 10 devices, every message to him requires 10 encryptions. Signal limits linked devices to 5. WhatsApp recently expanded beyond phone-only but still has limits. The protocol can handle more, but UX and battery impact become concerns.
E2EE is only as strong as the key distribution mechanism. How do you know that the public key you're using is actually Bob's, and not an attacker performing a man-in-the-middle attack?
Without verification:
Alice thinks she has Bob's key: BobKey_fake (actually attacker's)
Bob thinks he has Alice's key: AliceKey_fake (actually attacker's)
Alice → [Encrypt(BobKey_fake, msg)] → Attacker
Attacker decrypts, reads, re-encrypts
Attacker → [Encrypt(BobKey_real, msg)] → Bob
Both Alice and Bob see valid encrypted communication.
Neither knows the attacker is in the middle.
Trust on First Use (TOFU): Most users accept keys without verification. They trust that the first key they receive is legitimate. MITM on first contact can go undetected.
Verification mechanisms help users confirm key authenticity:
| Method | How It Works | User Experience |
|---|---|---|
| Safety Numbers | Both users compare a 60-digit number derived from both identity keys | View in app, compare digits verbally/visually |
| QR Code Scanning | One user displays QR containing their key, other scans and verifies match | In-person scanning, instant visual confirmation |
| Key Fingerprint | Cryptographic hash of public key displayed as hex or words | Share via trusted channel, compare |
| Web of Trust | Users sign each other's keys; trust propagates | Complex for average users |
| Certificate Transparency | Public log of all key assignments; auditable | Background technical guarantee |
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
/** * Safety numbers (security codes) in Signal/WhatsApp * * Derived from both parties' identity keys, so: * - Alice and Bob compute the same number * - Change if either key changes * - Hard for attacker to create matching number */ function computeSafetyNumber( myIdentityKey: PublicKey, theirIdentityKey: PublicKey, myUserId: string, theirUserId: string): string { // Concatenate identity keys with user IDs // Order is deterministic (lowest user ID first) const [first, second] = [myUserId, theirUserId].sort(); const [key1, key2] = first === myUserId ? [myIdentityKey, theirIdentityKey] : [theirIdentityKey, myIdentityKey]; // Hash the combination const fingerprintData = concat(first, key1, second, key2); const hash = SHA256(fingerprintData); // Convert to displayable format // Signal uses 6 groups of 5 digits (30 digits per person, 60 total) return formatAsDigits(hash.slice(0, 30));} function formatAsDigits(bytes: Uint8Array): string { // Convert bytes to large number, then to decimal digits let num = BigInt('0x' + bytesToHex(bytes)); let digits = num.toString().padStart(60, '0'); // Format as: 12345 67890 12345 67890 12345 67890 // 12345 67890 12345 67890 12345 67890 return digits.match(/.{5}/g)!.join(' ');} // Example output:// "12345 67890 12345 67890 12345 67890\n12345 67890 12345 67890 12345 67890"//// Alice and Bob both see this SAME number.// If an attacker substituted keys, numbers would differ.When a contact's identity key changes (new phone, reinstall), WhatsApp shows 'Security code changed.' This could be legitimate—or MITM. Users should verify again after key changes. Unfortunately, most users ignore these warnings, making MITM attacks on unsuspecting users feasible.
E2EE fundamentally constrains system architecture. Many features that are trivial with server-side access to content become impossible or require creative solutions.
| Feature | Without E2EE | With E2EE |
|---|---|---|
| Server-side search | Index all message content, full-text search | Impossible; client must search local storage only |
| Spam filtering | ML models analyze content server-side | Must rely on metadata, user reports, or client-side detection |
| Content moderation | Scan for illegal content (CSAM, etc.) | Cannot scan; controversial client-side scanning proposed |
| Message backup/restore | Server stores and restores messages | User must manage encryption keys; easy to lose access |
| Cross-device sync | Server delivers same content to all devices | Requires per-device encryption or complex key sharing |
| Link previews | Server fetches URL metadata | Client must fetch; leaks browsing to preview servers |
| Analytics | Analyze content for insights | Limited to metadata; no content analysis |
If users lose their phone, they lose access to their messages—including the keys needed to decrypt them. Secure backup is one of the hardest problems in E2EE:
Options:
No backup: Messages exist only on device. Lost phone = lost messages.
Unencrypted cloud backup: Messages backed up to iCloud/Google Drive in plaintext. Breaks E2EE entirely.
User-managed backup key: User creates a strong password; backup is encrypted with it. If they forget the password, backup is unrecoverable.
Hardware Security Module (HSM) backup: User's backup key is stored in tamper-resistant HSMs. WhatsApp allows this with a PIN; attempts are rate-limited and HSMs are designed to delete key after too many failures.
Social recovery: Backup key sharded across trusted contacts. Reconstruct from M-of-N contacts. Adds key management complexity.
12345678910111213141516171819202122232425262728293031323334353637
WHATSAPP E2EE BACKUP (Released 2021)━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ USER FLOW:1. User enables E2EE backup2. Creates 64-digit backup encryption key OR 6-digit PIN PIN-BASED FLOW:┌────────────┐ ┌──────────────────────────────┐│ User's │ │ Hardware Security Module ││ Device │ │ (Meta's secure datacenter) ││ │ │ ││ PIN: 1234 │──────►│ Store: encrypted_backup_key ││ │ │ Rate limit: 10 attempts ││ │ │ Auto-delete after failure │└────────────┘ └──────────────────────────────┘ Backup encryption key = KDF(random_key, PIN, salt) Restore flow:1. New phone enters PIN2. Request to HSM with PIN3. HSM verifies (rate-limited)4. If correct: returns encrypted_backup_key5. Device decrypts backup Security:• HSM is physically tamper-resistant• PIN attempts are strictly rate-limited• After N failures, HSM permanently deletes key• Meta cannot access keys without PIN• Government compulsion gets only encrypted blob Trade-off:• Requires trusting Meta's HSM implementation• 6-digit PIN is brute-forceable if HSM were compromised• 64-digit key avoids HSM but is hard to rememberE2EE creates tension with lawful intercept requirements in some jurisdictions. Some governments have proposed mandating 'backdoors' or client-side scanning. Security experts argue such mechanisms fundamentally weaken security for everyone. This remains an ongoing policy debate globally.
Implementing E2EE correctly is notoriously difficult. Subtle bugs can completely undermine security. Here are critical implementation considerations:
Cryptographic operations have costs. At scale, they must be optimized:
| Operation | Typical Time | Notes |
|---|---|---|
| X25519 ECDH | ~25μs | Per key exchange; acceptable |
| Ed25519 Sign | ~20μs | Per message in some protocols |
| Ed25519 Verify | ~50μs | Per message received |
| AES-256-GCM encrypt | ~1μs per KB | Main message encryption; fast |
| HKDF derivation | ~5μs | Per key derivation; fast |
| SHA-256 hash | ~0.5μs per KB | Various uses; negligible |
At 100 billion messages/day, even microseconds matter. But the primary latency concern is usually network, not crypto. Modern devices handle messaging crypto efficiently.
Battery impact: Cryptographic operations use CPU, which drains battery. But compared to radio usage (sending/receiving data), crypto overhead is negligible. The concern is more about key storage I/O and background processing.
The single most important implementation advice: don't invent your own cryptographic protocols. Use Signal's libsignal library directly. Even small deviations from the protocol can introduce vulnerabilities. Many high-profile E2EE failures came from companies 'rolling their own' crypto instead of using established solutions.
End-to-end encryption transforms messaging from a trust-the-server model to a trust-only-endpoints model. This fundamental change provides unprecedented privacy but introduces significant complexity.
What's next:
With encryption covered, we'll explore media handling—how WhatsApp efficiently stores, transmits, and streams images, videos, and documents while maintaining end-to-end encryption. We'll examine thumbnail generation, resumable uploads, and CDN integration strategies.
You now understand the cryptographic foundations and system design challenges of end-to-end encrypted messaging. These concepts—key exchange, ratcheting, group protocols, and trust verification—are the building blocks of secure communication in countless applications beyond messaging.