Get a Pentest and security assessment of your IT network.

Cyber Security

Secure HTML LocalStorage with Asymmetric Crypto

TL;DR

This guide shows you how to securely store sensitive data (like passwords or API keys) in a user’s browser using HTML LocalStorage, protected by asymmetric encryption. We’ll use JavaScript’s Web Crypto API to generate key pairs and encrypt/decrypt the data.

Steps

  1. Generate Key Pair:
    • First, check if a key pair already exists in LocalStorage. This avoids regenerating keys on every page load.
    • If no key pair exists, generate one using the crypto.subtle.generateKey function. We’ll use RSA with a key size of 2048 bits for good security.
    async function getKeyPair() {
      const existingKeyPair = JSON.parse(localStorage.getItem('keyPair'));
    
      if (existingKeyPair) {
        return existingKeyPair;
      }
    
      const keyPair = await crypto.subtle.generateKey(
        {
          name: 'RSA-OAEP',
          modulusLength: 2048,
          publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
          hash: { name: 'SHA-256' },
        },
        true, // extractable
        ['encrypt', 'decrypt']
      );
    
      localStorage.setItem('keyPair', JSON.stringify(keyPair));
      return keyPair;
    }
    
  2. Encrypt Data:
    • Convert the data you want to store into an ArrayBuffer using TextEncoder.
    • Use the public key from the key pair to encrypt the data with crypto.subtle.encrypt. We’ll use ‘RSA-OAEP’ as the encryption algorithm.
    async function encryptData(data) {
      const keyPair = await getKeyPair();
      const encoder = new TextEncoder();
      const dataBuffer = encoder.encode(data);
    
      const encrypted = await crypto.subtle.encrypt(
        {
          name: 'RSA-OAEP',
        },
        keyPair.publicKey,
        dataBuffer
      );
    
      return new Uint8Array(encrypted);
    }
    
  3. Store Encrypted Data in LocalStorage:
    • Convert the encrypted data (which is an ArrayBuffer) into a base64 string using btoa. This makes it safe to store as text in LocalStorage.
    • Save the base64 encoded string in LocalStorage with a descriptive key name.
    async function saveData(data, storageKey) {
      const encryptedData = await encryptData(data);
      const base64String = btoa(String.fromCharCode(...encryptedData));
      localStorage.setItem(storageKey, base64String);
    }
    
  4. Decrypt Data:
    • Retrieve the base64 encoded data from LocalStorage using localStorage.getItem.
    • Decode the base64 string back into an ArrayBuffer using atob.
    • Use the private key from the key pair to decrypt the data with crypto.subtle.decrypt.
    async function decryptData(storageKey) {
      const base64String = localStorage.getItem(storageKey);
      if (!base64String) return null;
    
      const encryptedData = Uint8Array.from(atob(base64String), c => c.charCodeAt(0));
      const keyPair = await getKeyPair();
    
      const decrypted = await crypto.subtle.decrypt(
        {
          name: 'RSA-OAEP',
        },
        keyPair.privateKey,
        encryptedData
      );
    
      const decoder = new TextDecoder();
      return decoder.decode(decrypted);
    }
    
  5. Example Usage:
    • To store a password: await saveData('mySecretPassword', 'superSecurePassword');
    • To retrieve the password: const password = await decryptData('mySecretPassword');
  6. Important Considerations:
    • Key Security: The private key is stored in the browser. While encrypted, it’s still vulnerable if the user’s machine is compromised. This method is suitable for protecting against casual access but not against determined attackers.
    • Browser Support: Web Crypto API has good support across modern browsers. Check MDN for compatibility details.
    • Error Handling: The code snippets above lack comprehensive error handling (e.g., what happens if decryption fails?). Add try...catch blocks to handle potential errors gracefully.
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