diff --git a/secure-storage.js b/secure-storage.js index 6998e912..3e8dc352 100644 --- a/secure-storage.js +++ b/secure-storage.js @@ -1,43 +1,71 @@ (function() { - // A fast obfuscation helper to protect local storage data from plain text snooping - function xorEncryptDecrypt(input, key) { - let output = ""; - for (let i = 0; i < input.length; i++) { - let charCode = input.charCodeAt(i) ^ key.charCodeAt(i % key.length); - output += String.fromCharCode(charCode); - } - return btoa(output); + // A cryptographic token signing wrapper using Web Crypto API + // This ensures local session tokens are signed and validated for integrity before access. + const SECRET_KEY_STRING = "cara_crypto_secure_key_v2"; + + async function getKey() { + const enc = new TextEncoder(); + return await window.crypto.subtle.importKey( + "raw", + enc.encode(SECRET_KEY_STRING), + { name: "HMAC", hash: "SHA-256" }, + false, + ["sign", "verify"] + ); } - function xorDecrypt(input, key) { - try { - let decoded = atob(input); - let output = ""; - for (let i = 0; i < decoded.length; i++) { - let charCode = decoded.charCodeAt(i) ^ key.charCodeAt(i % key.length); - output += String.fromCharCode(charCode); - } - return output; - } catch (e) { - return null; - } + async function signData(data) { + const key = await getKey(); + const enc = new TextEncoder(); + const signature = await window.crypto.subtle.sign( + "HMAC", + key, + enc.encode(data) + ); + return btoa(String.fromCharCode(...new Uint8Array(signature))); } - const SECRET_KEY = "cara_obfuscation_secure_key"; + async function verifyData(data, signatureBase64) { + const key = await getKey(); + const enc = new TextEncoder(); + const signatureBytes = Uint8Array.from(atob(signatureBase64), c => c.charCodeAt(0)); + return await window.crypto.subtle.verify( + "HMAC", + key, + signatureBytes, + enc.encode(data) + ); + } window.SecureStorage = { - setItem: function(key, value) { - const strVal = JSON.stringify(value); - const encrypted = xorEncryptDecrypt(strVal, SECRET_KEY); - localStorage.setItem(key, encrypted); + setItem: async function(key, value) { + try { + const strVal = JSON.stringify(value); + const signature = await signData(strVal); + const payload = JSON.stringify({ data: strVal, signature: signature }); + + // Encode to base64 to obscure the JSON structure + localStorage.setItem(key, btoa(payload)); + } catch (e) { + console.error("Failed to securely store item", e); + } }, - getItem: function(key) { + getItem: async function(key) { const val = localStorage.getItem(key); if (!val) return null; - const decrypted = xorDecrypt(val, SECRET_KEY); - if (!decrypted) return null; try { - return JSON.parse(decrypted); + const decoded = atob(val); + const payload = JSON.parse(decoded); + + // Verify integrity + const isValid = await verifyData(payload.data, payload.signature); + if (!isValid) { + console.warn("SecureStorage integrity check failed. Data tampered."); + localStorage.removeItem(key); + return null; + } + + return JSON.parse(payload.data); } catch (e) { return null; } @@ -46,8 +74,4 @@ localStorage.removeItem(key); } }; -})(); - -// TODO: Implement cryptographic token signing wrapper - -// Wrapper utility ensuring local session tokens are obfuscated before storage. \ No newline at end of file +})(); \ No newline at end of file