Blog | G5 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:
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;
}
  • Encrypt Data:
  • 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);
    }
    
  • Store Encrypted Data in LocalStorage:
  • async function saveData(data, storageKey) {
      const encryptedData = await encryptData(data);
      const base64String = btoa(String.fromCharCode(...encryptedData));
      localStorage.setItem(storageKey, base64String);
    }
    
  • Decrypt Data:
  • 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);
    }
    
  • Example Usage:
  • Important Considerations:
  • Exit mobile version