Get a Pentest and security assessment of your IT network.

Cyber Security

Web Messaging: End-to-End Encryption

TL;DR

This guide shows you how to add end-to-end encryption to your web messaging app using asymmetric cryptography (public/private key pairs). This means only the sender and receiver can read messages. We’ll cover key generation, message encryption/decryption, and basic implementation considerations.

1. Understanding Asymmetric Encryption

Asymmetric encryption uses a pair of keys: a public key and a private key.

  • Public Key: Can be shared freely. Anyone can use it to encrypt messages for you.
  • Private Key: Must be kept secret! Only you have access to it. Used to decrypt messages encrypted with your public key.

Think of it like a lock and key. The public key is the open lock – anyone can use it to secure something (encrypt). The private key is the only key that opens that specific lock (decrypt).

2. Choosing an Encryption Library

Don’t try to implement asymmetric encryption yourself! Use a well-vetted library.

  • Web Crypto API: Built into most modern browsers. Good for simple use cases.
  • jsrsasign: A popular JavaScript library with more features and wider browser support.
  • node-forge: For server-side Node.js applications.

For this guide, we’ll assume you are using the Web Crypto API as it requires no external dependencies.

3. Key Generation

Each user needs a key pair. This is usually done when they create an account or first start using the app.

async function generateKeyPair() {
  const keyPair = await window.crypto.subtle.generateKey(
    {
      name: "RSA-OAEP",
      modulusLength: 2048,
      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
      hash: "SHA-256",
    },
    true, // extractable
    ["encrypt", "decrypt"]
  );
  return keyPair;
}

This code generates an RSA key pair with a modulus length of 2048 bits. The `extractable` flag being set to `true` allows you to export the keys (see step 6). The `hash` algorithm is used for padding.

4. Encryption

To encrypt a message, use the recipient’s public key.

async function encryptMessage(message, publicKey) {
  const enc = new TextEncoder();
  const data = enc.encode(message);
  const encrypted = await window.crypto.subtle.encrypt(
    {
      name: "RSA-OAEP",
    },
    publicKey,
    data
  );
  return Array.from(new Uint8Array(encrypted)); // Convert to array for storage/transmission
}

This code encrypts the message using the provided public key. The result is an `Uint8Array` which needs to be converted into a format suitable for storage or transmission (e.g., base64 encoding).

5. Decryption

To decrypt a message, use your private key.

async function decryptMessage(encryptedMessage, privateKey) {
  const decrypted = await window.crypto.subtle.decrypt(
    {
      name: "RSA-OAEP",
    },
    privateKey,
    encryptedMessage
  );
  return new TextDecoder().decode(decrypted); // Convert back to string
}

This code decrypts the message using your private key. The result is a `Uint8Array` which needs to be converted into a string.

6. Key Storage and Exchange

This is the hardest part! Securely storing and exchanging keys is crucial.

  • Key Export/Import: You can export public and private keys as JSON Web Keys (JWK) format using crypto.subtle.exportKey.
  • Server-Side Storage: Store public keys on your server, linked to user accounts. Never store private keys on the server!
  • Secure Exchange: Use HTTPS for all communication. Consider key verification mechanisms (e.g., fingerprints) to prevent man-in-the-middle attacks.

Example of exporting a public key:

async function exportPublicKey(publicKey) {
  const exported = await crypto.subtle.exportKey(
    "jwk", // format
    publicKey
  );
  return JSON.stringify(exported);
}

7. Implementation Considerations

  • Performance: Asymmetric encryption is slower than symmetric encryption. Consider using a hybrid approach (e.g., encrypting the message with a randomly generated symmetric key, then encrypting the symmetric key with the recipient’s public key).
  • Key Rotation: Regularly rotate keys to limit the impact of potential compromises.
  • Error Handling: Implement robust error handling for all cryptographic operations.
  • Browser Compatibility: Check browser compatibility for the Web Crypto API features you are using.
Related posts
Cyber Security

Zip Codes & PII: Are They Personal Data?

Cyber Security

Zero-Day Vulnerabilities: User Defence Guide

Cyber Security

Zero Knowledge Voting with Trusted Server

Cyber Security

ZeroNet: 51% Attack Risks & Mitigation