UNPKG

client-trace

Version:

A comprehensive client-side security and telemetry library. Features device fingerprinting, bot detection, network tampering analysis, and secure transport.

106 lines (92 loc) 3.01 kB
/** * Encrypted Telemetry Transport * Encrypts data using AES-GCM before sending. */ /** * Derives an AES-GCM key from a shared secret using PBKDF2. * @param {string} secret - The shared secret. * @param {Uint8Array} salt - The salt. * @returns {Promise<CryptoKey>} */ async function deriveKey(secret, salt) { const encoder = new TextEncoder(); const keyMaterial = await crypto.subtle.importKey( 'raw', encoder.encode(secret), { name: 'PBKDF2' }, false, ['deriveKey'] ); return crypto.subtle.deriveKey( { name: 'PBKDF2', salt: salt, iterations: 100000, hash: 'SHA-256' }, keyMaterial, { name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt'] ); } /** * Encrypts a payload. * @param {object} payload - The data to encrypt. * @param {string} secret - The shared secret. * @returns {Promise<{ iv: string, ciphertext: string, authTag: string, salt: string }>} */ export async function encryptTelemetry(payload, secret) { const salt = crypto.getRandomValues(new Uint8Array(16)); const iv = crypto.getRandomValues(new Uint8Array(12)); const key = await deriveKey(secret, salt); const encoder = new TextEncoder(); const data = encoder.encode(JSON.stringify(payload)); const encryptedBuffer = await crypto.subtle.encrypt( { name: 'AES-GCM', iv: iv }, key, data ); // Split ciphertext and authentication tag (last 16 bytes) const encryptedArray = new Uint8Array(encryptedBuffer); const tag = encryptedArray.slice(-16); const ciphertext = encryptedArray.slice(0, -16); // Convert to Base64 for transport const toBase64 = (buffer) => btoa(String.fromCharCode(...buffer)); return { iv: toBase64(iv), ciphertext: toBase64(ciphertext), authTag: toBase64(tag), salt: toBase64(salt) }; } /** * Decrypts a payload (Client-side helper, mostly for verification/testing). */ export async function decryptTelemetry(encryptedData, secret) { const fromBase64 = (str) => { const binaryString = atob(str); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes; }; const salt = fromBase64(encryptedData.salt); const iv = fromBase64(encryptedData.iv); const ciphertext = fromBase64(encryptedData.ciphertext); const key = await deriveKey(secret, salt); const decryptedBuffer = await crypto.subtle.decrypt( { name: 'AES-GCM', iv: iv }, key, ciphertext ); const decoder = new TextDecoder(); return JSON.parse(decoder.decode(decryptedBuffer)); }