fc / crypto-engine.js
Althnayi's picture
Upload 56 files
cca0cf3 verified
Raw
History Blame Contribute Delete
39.5 kB
/**
* @fileoverview End-to-End Cryptographic Core Engine (AES-256-GCM / PBKDF2 / SHA-256)
* @module storage/crypto-engine
* @description محرك التشفير وتوليد المفاتيح المشفرة، حماية وتوثيق التوقيعات الرقمية، وإدارة كود الجهاز الفريد (128 حرف).
*/
(global => {
'use strict';
const CURRENT_CRYPTO_VERSION = "5.0-EnterpriseFullE2E";
const SECURE_HEADER = "";
const TOKEN_HEADER = "";
const BACKUP_HEADER = "";
const CAPSULE_HEADER = "";
const HASH_KEY_SALT = "FritreeStorageKeyObfuscationSalt_2026_StrictSHA256_AEADMasterLock";
const DERIVATION_SALT = "FritreeMasterKeyDerivationEnterpriseSalt_2026_StrictSHA256";
const INTEGRITY_SEAL_SALT = "FritreeIntegritySealValidationSalt_SHA256_2026_EnterpriseSecureForce";
const PBKDF2_ITERATIONS = 200000;
let cachedMasterKey = null;
const derivedKeyCache = new Map();
const derivedHmacKeyCache = new Map();
/**
* معالجة الأخطاء الصامتة لتأمين الاستقرار
*/
function silentTrap(err) {
if (err && console && console.warn) {
console.warn("[Fritree Crypto Core SafeTrap]", err);
}
return null;
}
/**
* تحويل مصفوفة ثنائية إلى نص Base64
* @param {Uint8Array} uint8
* @returns {string}
*/
function uint8ArrayToBase64(uint8) {
try {
if (!uint8 || !(uint8 instanceof Uint8Array)) return '';
let binary = '';
const len = uint8.byteLength;
const chunk = 8192;
for (let i = 0; i < len; i += chunk) {
const slice = uint8.subarray(i, i + chunk);
binary += String.fromCharCode.apply(null, slice);
}
return btoa(binary);
} catch (e) {
return silentTrap(e) || '';
}
}
/**
* تحويل نص Base64 إلى مصفوفة ثنائية Uint8Array
* @param {string} base64
* @returns {Uint8Array}
*/
function base64ToUint8Array(base64) {
try {
if (!base64 || typeof base64 !== 'string') return new Uint8Array(0);
const rawBase64 = base64.includes(",") ? base64.split(",")[1] : base64;
const binary = atob(rawBase64);
const len = binary.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
} catch (e) {
silentTrap(e);
return new Uint8Array(0);
}
}
/**
* تنظيف وتفريغ الذاكرة الآمن من المفاتيح بعد الاستخدام
* @param {ArrayBuffer|ArrayBufferView} buffer
*/
function secureMemoryWipe(buffer) {
try {
if (!buffer) return;
if (buffer instanceof ArrayBuffer) {
new Uint8Array(buffer).fill(0);
} else if (ArrayBuffer.isView(buffer)) {
buffer.fill(0);
}
} catch (e) {
silentTrap(e);
}
}
/**
* توليد بايتات عشوائية مشفرة باستخدام CSPRNG
* @param {number} bytesLength
* @returns {Uint8Array}
*/
function generateSecureRandomBytes(bytesLength) {
try {
const buffer = new Uint8Array(bytesLength);
crypto.getRandomValues(buffer);
return buffer;
} catch (e) {
silentTrap(e);
const fb = new Uint8Array(bytesLength);
for (let i = 0; i < bytesLength; i++) {
fb[i] = Math.floor(Math.random() * 256);
}
return fb;
}
}
/**
* توليد كود ومعرف فريد وآمن (كود الجهاز 128 حرف)
* @param {number} length
* @returns {string}
*/
function generateSecureIdentifier(length = 128) {
try {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
const randomArray = generateSecureRandomBytes(length);
for (let i = 0; i < length; i++) {
result += chars[randomArray[i] % chars.length];
}
secureMemoryWipe(randomArray);
return result;
} catch (e) {
silentTrap(e);
return "fteFallbackId" + Math.random().toString(36).substring(2) + "0".repeat(90);
}
}
/**
* حساب تجزئة SHA-256 الأصلية للمتصفح
* @param {string} inputText
* @returns {Promise<string>}
*/
async function nativeHashSha256(inputText) {
try {
const encoder = new TextEncoder();
const data = encoder.encode(String(inputText !== undefined && inputText !== null ? inputText : ""));
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
secureMemoryWipe(data);
return hex;
} catch (e) {
silentTrap(e);
return "0000000000000000000000000000000000000000000000000000000000000000";
}
}
/**
* تشويش وتعمية مفاتيح التخزين متزامناً
* @param {string} key
* @returns {string}
*/
function syncHashKey(key) {
try {
let hash = 0;
const input = String(key) + HASH_KEY_SALT;
for (let i = 0; i < input.length; i++) {
const char = input.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash |= 0;
}
return "fte_sh_v5_" + Math.abs(hash).toString(16);
} catch (e) {
silentTrap(e);
return "fallback_sync_" + String(key).length;
}
}
/**
* تشويش وتعمية مفاتيح التخزين عبر SHA-256
* @param {string} key
* @returns {Promise<string>}
*/
async function asyncHashKey(key) {
try {
const hashHex = await nativeHashSha256(String(key) + HASH_KEY_SALT);
return "fte_sh_v5_" + hashHex.substring(0, 32);
} catch (e) {
silentTrap(e);
return "fallback_async_" + String(key).length;
}
}
/**
* تهيئة واشتقاق المفتاح الأساسي للتطبيق (Master Key via HKDF)
*/
async function getOrInitMasterKey() {
try {
if (cachedMasterKey) return cachedMasterKey;
const constantSeed = (typeof chrome !== 'undefined' && chrome.runtime && chrome.runtime.id)
? chrome.runtime.id
: "fritree_standalone_fallback_seed_key_2026_e2e_v5";
const rawHex = await nativeHashSha256(constantSeed + DERIVATION_SALT);
const keyData = new Uint8Array(rawHex.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
const imported = await crypto.subtle.importKey(
"raw",
keyData,
{ name: "HKDF" },
false,
["deriveKey", "deriveBits"]
);
cachedMasterKey = imported;
secureMemoryWipe(keyData);
return imported;
} catch (e) {
silentTrap(e);
return null;
}
}
/**
* اشتقاق مفتاح التشفير الخاص بسياق محدد (Context Key Derivation)
* @param {string} context
* @param {string} purpose ('encryption' | 'integrity')
*/
async function getDerivedContextKey(context, purpose = "encryption") {
try {
const cacheMap = (purpose === "integrity") ? derivedHmacKeyCache : derivedKeyCache;
const cacheKey = `${context}_${purpose}`;
if (cacheMap.has(cacheKey)) {
return cacheMap.get(cacheKey);
}
const masterKey = await getOrInitMasterKey();
if (!masterKey) return null;
const encoder = new TextEncoder();
const info = encoder.encode(`FritreeContextKey_${context}_Purpose_${purpose}_V5_AEAD`);
const salt = encoder.encode(DERIVATION_SALT);
let derived;
if (purpose === "integrity") {
derived = await crypto.subtle.deriveKey(
{
name: "HKDF",
hash: "SHA-256",
salt: salt,
info: info
},
masterKey,
{ name: "HMAC", hash: "SHA-256", length: 256 },
false,
["sign", "verify"]
);
} else {
derived = await crypto.subtle.deriveKey(
{
name: "HKDF",
hash: "SHA-256",
salt: salt,
info: info
},
masterKey,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
}
cacheMap.set(cacheKey, derived);
secureMemoryWipe(info);
return derived;
} catch (e) {
silentTrap(e);
return null;
}
}
/**
* اشتقاق مفتاح التشفير من كلمة مرور عبر PBKDF2
*/
async function derivePassphraseKey(passphrase, salt) {
try {
const encoder = new TextEncoder();
const finalPass = passphrase || "Fritree_Default_Secure_Passphrase_V5_StrictAEAD";
const passwordBuffer = encoder.encode(finalPass);
const baseKey = await crypto.subtle.importKey(
"raw",
passwordBuffer,
{ name: "PBKDF2" },
false,
["deriveKey"]
);
const derivedKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: PBKDF2_ITERATIONS,
hash: "SHA-256"
},
baseKey,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
secureMemoryWipe(passwordBuffer);
return derivedKey;
} catch (e) {
silentTrap(e);
return null;
}
}
/**
* ضغط البيانات قبل التشفير عبر CompressionStream
*/
async function compressPayload(inputString) {
try {
const encoder = new TextEncoder();
const inputData = encoder.encode(inputString);
if (typeof CompressionStream === 'undefined') {
return inputData;
}
const stream = new Blob([inputData]).stream();
const compressedStream = stream.pipeThrough(new CompressionStream("deflate"));
const reader = compressedStream.getReader();
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
}
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
const result = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of chunks) {
result.set(chunk, offset);
offset += chunk.length;
}
return result;
} catch (e) {
silentTrap(e);
return new TextEncoder().encode(inputString);
}
}
/**
* فك ضغط البيانات بعد فك التشفير عبر DecompressionStream
*/
async function decompressPayload(compressedBytes) {
try {
if (typeof DecompressionStream === 'undefined') {
return new TextDecoder().decode(compressedBytes);
}
const stream = new Blob([compressedBytes]).stream();
const decompressedStream = stream.pipeThrough(new DecompressionStream("deflate"));
const reader = decompressedStream.getReader();
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
}
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
const result = new Uint8Array(totalLength);
let offset = 0;
for (const chunk of chunks) {
result.set(chunk, offset);
offset += chunk.length;
}
return new TextDecoder().decode(result);
} catch (e) {
silentTrap(e);
return new TextDecoder().decode(compressedBytes);
}
}
/**
* التحقق من حجم وسلامة بنية البيانات
*/
const DataValidationPipeline = {
validate: function(data, context) {
try {
if (data === null || data === undefined) return true;
const serializedLength = typeof data === 'object' ? JSON.stringify(data).length : String(data).length;
if (serializedLength > 150 * 1024 * 1024) { // 150 MB
return false;
}
return true;
} catch (e) {
silentTrap(e);
return false;
}
}
};
/**
* تشفير وتوقيع البيانات بمصفوفة مغلف التشفير (Envelope Encryption)
* @param {*} data
* @param {string} context
* @returns {Promise<string|null>}
*/
async function encryptAndSignPayload(data, context = "user_data") {
try {
if (!DataValidationPipeline.validate(data, context)) {
return null;
}
const plainText = JSON.stringify(data !== undefined ? data : null);
const derivedKey = await getDerivedContextKey(context, "encryption");
if (!derivedKey) return null;
const iv = generateSecureRandomBytes(12); // 96-bit IV for AES-GCM
const salt = generateSecureRandomBytes(16);
const nonce = generateSecureIdentifier(32);
const timestamp = new Date().toISOString();
const compressedData = await compressPayload(plainText);
const ciphertextBuffer = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv: iv, tagLength: 128 },
derivedKey,
compressedData
);
const ciphertextBytes = new Uint8Array(ciphertextBuffer);
const envelopeMetadata = {
v: CURRENT_CRYPTO_VERSION,
algo: "AES-256-GCM-SHA256-AEAD",
salt: uint8ArrayToBase64(salt),
iv: uint8ArrayToBase64(iv),
ct: uint8ArrayToBase64(ciphertextBytes),
keyId: context,
nonce: nonce,
ts: timestamp
};
const serializedEnvelope = JSON.stringify(envelopeMetadata);
const envelopeSignatureHex = await nativeHashSha256(serializedEnvelope + INTEGRITY_SEAL_SALT);
const cryptopacket = {
envelope: serializedEnvelope,
signature: envelopeSignatureHex
};
const serializedPacket = SECURE_HEADER + btoa(JSON.stringify(cryptopacket));
secureMemoryWipe(compressedData);
return serializedPacket;
} catch (e) {
silentTrap(e);
return null;
}
}
/**
* فك تشفير البيانات والتحقق من سلامة التوقيع الرقمي ومقاومة التلاعب
* @param {string} securePacket
* @param {string} context
* @returns {Promise<*>}
*/
async function verifyAndDecryptPayload(securePacket, context = "user_data") {
try {
if (!securePacket || typeof securePacket !== 'string') return null;
if (!securePacket.startsWith(SECURE_HEADER)) {
let legacyData = null;
try {
if (securePacket.startsWith("") || securePacket.startsWith("FTE:") || securePacket.startsWith("FTE_ENC_V4_GCM_AEAD:")) {
const rawPacketBase64 = securePacket.includes(":") ? securePacket.split(":")[1] : securePacket;
const cryptopacket = JSON.parse(atob(rawPacketBase64));
const envelopeMetadata = JSON.parse(cryptopacket.envelope);
legacyData = JSON.parse(await decompressPayload(base64ToUint8Array(envelopeMetadata.ct)));
} else {
try { legacyData = JSON.parse(securePacket); } catch (e) { legacyData = securePacket; }
}
} catch (e) {
silentTrap(e);
legacyData = null;
}
if (legacyData !== null) {
await global.FritreeCrypto.setStorage(context, legacyData);
return legacyData;
}
return null;
}
const rawPacketBase64 = securePacket.slice(SECURE_HEADER.length);
const cryptopacket = JSON.parse(atob(rawPacketBase64));
if (!cryptopacket.envelope || !cryptopacket.signature) {
console.warn("[Fritree Crypto] Rejected malformed or tampered packet for context:", context);
return null;
}
const envelopeString = cryptopacket.envelope;
const computedSignatureHex = await nativeHashSha256(envelopeString + INTEGRITY_SEAL_SALT);
if (cryptopacket.signature !== computedSignatureHex) {
console.error("[Fritree Crypto] TAMPER DETECTED in storage element:", context, "- Rejecting modified value.");
return null;
}
const envelopeMetadata = JSON.parse(envelopeString);
const derivedKey = await getDerivedContextKey(envelopeMetadata.keyId || context, "encryption");
if (!derivedKey) return null;
const iv = base64ToUint8Array(envelopeMetadata.iv);
const ciphertext = base64ToUint8Array(envelopeMetadata.ct);
const decryptedBuffer = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv: iv, tagLength: 128 },
derivedKey,
ciphertext
);
const decompressedString = await decompressPayload(new Uint8Array(decryptedBuffer));
secureMemoryWipe(decryptedBuffer);
try {
const parsedObject = JSON.parse(decompressedString);
if (!DataValidationPipeline.validate(parsedObject, context)) {
return null;
}
return parsedObject;
} catch (e) {
return decompressedString;
}
} catch (err) {
silentTrap(err);
return null;
}
}
/**
* تدوير مفاتيح التشفير المتناظرة وإعادة تشفير كامل قاعدة البيانات بمفتاح جديد
*/
async function rotateSymmetricKeys() {
try {
const freshMaterial = generateSecureRandomBytes(64);
const freshHex = Array.from(freshMaterial).map(b => b.toString(16).padStart(2, '0')).join('');
const storageKey = await asyncHashKey("fritree_master_key_v5_native_sha256");
const targetContexts = [
"usdPoints", "usedSerials", "usedTokens", "pointsTransactions",
"campaignHistoryData", "local_saved_tags", "local_selected_groups",
"local_sleep_intervals", "local_protection_settings", "local_shield_config_matrix",
"fritree_account_id", "acc_fbPoints", "acc_waPoints", "acc_userXP",
"acc_userLevel", "acc_lifetimeFb", "acc_lifetimeWa", "acc_lifetimeTasks",
"acc_activeSub", "acc_subExpiry", "wa_connected", "wa_phone_number",
"wa_profile_name", "wa_sent_today", "local_previous_posts", "local_time_capsules",
"local_contacts_database", "local_calendar_events_db", "local_post_groups"
];
const temporaryCache = {};
for (const context of targetContexts) {
const data = await global.FritreeCrypto.getStorage(context);
if (data !== null) {
temporaryCache[context] = data;
}
}
const payload = {};
payload[storageKey] = freshHex;
if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) {
await new Promise((resolve) => {
chrome.storage.local.set(payload, () => {
cachedMasterKey = null;
derivedKeyCache.clear();
derivedHmacKeyCache.clear();
resolve();
});
});
} else {
localStorage.setItem(syncHashKey("fritree_master_key_v5_native_sha256"), freshHex);
cachedMasterKey = null;
derivedKeyCache.clear();
derivedHmacKeyCache.clear();
}
await getOrInitMasterKey();
for (const [context, value] of Object.entries(temporaryCache)) {
await global.FritreeCrypto.setStorage(context, value);
}
secureMemoryWipe(freshMaterial);
return true;
} catch (e) {
silentTrap(e);
return false;
}
}
/**
* تشفير كبسولة رصيد زمنية مجدولة
*/
async function encryptConditionalCapsulePayload(capsuleData, passphrase = "") {
try {
const finalPass = passphrase || "Fritree_MeyaMeya_EmptyPasswordFallback_2026_StrictSHA256";
const rawPayload = JSON.stringify({
...capsuleData,
protocolVersion: "5.0-EnterpriseCapsule",
createdAt: new Date().toISOString(),
nonce: generateSecureIdentifier(32)
});
const salt = generateSecureRandomBytes(16);
const iv = generateSecureRandomBytes(12);
const derivedKey = await derivePassphraseKey(finalPass, salt);
if (!derivedKey) return null;
const compressedBytes = await compressPayload(rawPayload);
const ciphertextBuffer = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv: iv, tagLength: 128 },
derivedKey,
compressedBytes
);
const serialized = {
salt: uint8ArrayToBase64(salt),
iv: uint8ArrayToBase64(iv),
ct: uint8ArrayToBase64(new Uint8Array(ciphertextBuffer)),
v: "V5-Capsule"
};
secureMemoryWipe(compressedBytes);
return CAPSULE_HEADER + btoa(JSON.stringify(serialized));
} catch (e) {
silentTrap(e);
return null;
}
}
/**
* فك تشفير كبسولة رصيد زمنية مجدولة
*/
async function decryptConditionalCapsulePayload(cipherText, passphrase = "") {
if (!cipherText || typeof cipherText !== 'string' || !cipherText.startsWith(CAPSULE_HEADER)) {
return null;
}
try {
const finalPass = passphrase || "Fritree_MeyaMeya_EmptyPasswordFallback_2026_StrictSHA256";
const rawB64 = cipherText.slice(CAPSULE_HEADER.length);
const envelope = JSON.parse(atob(rawB64));
const salt = base64ToUint8Array(envelope.salt);
const iv = base64ToUint8Array(envelope.iv);
const ciphertext = base64ToUint8Array(envelope.ct);
const derivedKey = await derivePassphraseKey(finalPass, salt);
if (!derivedKey) return null;
const decryptedBuffer = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv: iv, tagLength: 128 },
derivedKey,
ciphertext
);
const decompressedString = await decompressPayload(new Uint8Array(decryptedBuffer));
secureMemoryWipe(decryptedBuffer);
return JSON.parse(decompressedString);
} catch (e) {
silentTrap(e);
return null;
}
}
/**
* تدقيق وفحص ختم سلامة التخزين (Storage Integrity Seal Audit)
*/
async function auditStorageIntegritySeal(key) {
try {
const currentData = await global.FritreeCrypto.getStorage(key, null);
if (currentData === null) return { valid: true, isClean: true };
const stringified = typeof currentData === 'object' ? JSON.stringify(currentData) : String(currentData);
const payloadString = `${key}:${stringified}:${INTEGRITY_SEAL_SALT}`;
const expectedHash = await nativeHashSha256(payloadString);
const savedHash = await global.FritreeStorage.get(`local_sis_sig_${key}`, null);
if (!savedHash) {
await global.FritreeStorage.set(`local_sis_sig_${key}`, expectedHash);
return { valid: true, isClean: true, repaired: true };
}
return {
valid: savedHash === expectedHash,
expected: expectedHash,
saved: savedHash
};
} catch (e) {
silentTrap(e);
return { valid: false, error: e.message };
}
}
/**
* واجهة محرك التشفير العامة
*/
global.FritreeCrypto = {
setLocal: function(key, value) {
try {
encryptAndSignPayload(value, key).then(encrypted => {
if (encrypted) {
localStorage.setItem(syncHashKey(key), encrypted);
}
});
return true;
} catch (e) {
silentTrap(e);
return false;
}
},
getLocal: function(key) {
try {
const cipher = localStorage.getItem(syncHashKey(key));
if (!cipher) return null;
return verifyAndDecryptPayload(cipher, key);
} catch (e) {
silentTrap(e);
return null;
}
},
removeLocal: function(key) {
try {
localStorage.removeItem(syncHashKey(key));
} catch (e) {
silentTrap(e);
}
},
setStorage: function(key, value) {
return new Promise(async (resolve) => {
try {
const obfuscatedKey = await asyncHashKey(key);
const encryptedValue = await encryptAndSignPayload(value, key);
if (!encryptedValue) {
resolve(false);
return;
}
if (typeof chrome === 'undefined' || !chrome.storage || !chrome.storage.local) {
localStorage.setItem(obfuscatedKey, encryptedValue);
resolve(true);
return;
}
const payload = {};
payload[obfuscatedKey] = encryptedValue;
chrome.storage.local.set(payload, () => {
resolve(true);
});
} catch (e) {
silentTrap(e);
resolve(false);
}
});
},
getStorage: function(key, defaultValue = null) {
return new Promise(async (resolve) => {
try {
const obfuscatedKey = await asyncHashKey(key);
if (typeof chrome === 'undefined' || !chrome.storage || !chrome.storage.local) {
const cipher = localStorage.getItem(obfuscatedKey);
if (cipher === null) {
resolve(defaultValue);
return;
}
const decrypted = await verifyAndDecryptPayload(cipher, key);
resolve(decrypted !== null ? decrypted : defaultValue);
return;
}
chrome.storage.local.get(obfuscatedKey, async (result) => {
try {
const cipher = result[obfuscatedKey];
if (cipher === undefined || cipher === null) {
resolve(defaultValue);
return;
}
const decrypted = await verifyAndDecryptPayload(cipher, key);
resolve(decrypted !== null ? decrypted : defaultValue);
} catch (inn) {
silentTrap(inn);
resolve(defaultValue);
}
});
} catch (e) {
silentTrap(e);
resolve(defaultValue);
}
});
},
getOrGenerateAccountId: async function() {
try {
let id = await this.getStorage('fritree_account_id', null);
if (!id || id.length !== 128) {
id = generateSecureIdentifier(128);
await this.setStorage('fritree_account_id', id);
}
return id;
} catch (e) {
silentTrap(e);
return "fallbackAccountId128Chars" + "a".repeat(101);
}
},
regenerateAccountId: async function() {
try {
const newId = generateSecureIdentifier(128);
await this.setStorage('fritree_account_id', newId);
return newId;
} catch (e) {
silentTrap(e);
return "fallbackAccountId128Chars" + "b".repeat(101);
}
},
encryptTokenPayload: async function(pointsObj, targetAccountId, password) {
try {
const finalPass = password || "";
const payload = JSON.stringify({
points: pointsObj,
targetAccountId: targetAccountId,
tokenId: "tk_v5_aead_" + Date.now().toString(36) + "_" + generateSecureIdentifier(16),
timestamp: new Date().toISOString()
});
const salt = generateSecureRandomBytes(16);
const iv = generateSecureRandomBytes(12);
const derivedKey = await derivePassphraseKey(finalPass, salt);
if (!derivedKey) return null;
const compressedBytes = await compressPayload(payload);
const ciphertextBuffer = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv: iv, tagLength: 128 },
derivedKey,
compressedBytes
);
const serializedStructure = {
salt: uint8ArrayToBase64(salt),
iv: uint8ArrayToBase64(iv),
ciphertext: uint8ArrayToBase64(new Uint8Array(ciphertextBuffer))
};
secureMemoryWipe(compressedBytes);
return TOKEN_HEADER + btoa(JSON.stringify(serializedStructure));
} catch (e) {
silentTrap(e);
return null;
}
},
decryptTokenPayload: async function(cipherText, password) {
if (!cipherText || typeof cipherText !== 'string' || !cipherText.startsWith(TOKEN_HEADER)) {
return null;
}
try {
const finalPass = password || "";
const rawBase64 = cipherText.slice(TOKEN_HEADER.length);
const serializedStructure = JSON.parse(atob(rawBase64));
const salt = base64ToUint8Array(serializedStructure.salt);
const iv = base64ToUint8Array(serializedStructure.iv);
const ciphertext = base64ToUint8Array(serializedStructure.ciphertext);
const derivedKey = await derivePassphraseKey(finalPass, salt);
if (!derivedKey) return null;
const decryptedBuffer = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv: iv, tagLength: 128 },
derivedKey,
ciphertext
);
const decompressedString = await decompressPayload(new Uint8Array(decryptedBuffer));
secureMemoryWipe(decryptedBuffer);
return JSON.parse(decompressedString);
} catch (e) {
silentTrap(e);
return null;
}
},
encryptBackupString: async function(plainText, passphrase, targetAccountId = null) {
try {
const finalPass = passphrase || "";
const salt = generateSecureRandomBytes(16);
const iv = generateSecureRandomBytes(12);
const derivedKey = await derivePassphraseKey(finalPass, salt);
if (!derivedKey) return null;
const container = {
data: plainText,
target: targetAccountId ? targetAccountId.trim() : null
};
const compressedBytes = await compressPayload(JSON.stringify(container));
const ciphertextBuffer = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv: iv, tagLength: 128 },
derivedKey,
compressedBytes
);
const payload = {
salt: uint8ArrayToBase64(salt),
iv: uint8ArrayToBase64(iv),
ciphertext: uint8ArrayToBase64(new Uint8Array(ciphertextBuffer))
};
const serialized = BACKUP_HEADER + btoa(JSON.stringify(payload));
secureMemoryWipe(compressedBytes);
return serialized;
} catch (e) {
silentTrap(e);
return null;
}
},
decryptBackupString: async function(cipherText, passphrase, currentAccountId = null) {
if (!cipherText || !cipherText.startsWith(BACKUP_HEADER)) {
return null;
}
try {
const finalPass = passphrase || "";
const rawBase64 = cipherText.slice(BACKUP_HEADER.length);
const payload = JSON.parse(atob(rawBase64));
const salt = base64ToUint8Array(payload.salt);
const iv = base64ToUint8Array(payload.iv);
const ciphertext = base64ToUint8Array(payload.ciphertext);
const derivedKey = await derivePassphraseKey(finalPass, salt);
if (!derivedKey) return null;
const decryptedBuffer = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv: iv, tagLength: 128 },
derivedKey,
ciphertext
);
const decompressedString = await decompressPayload(new Uint8Array(decryptedBuffer));
secureMemoryWipe(decryptedBuffer);
const container = JSON.parse(decompressedString);
if (container.target && container.target !== currentAccountId) {
throw new Error("RESTRICTED_ACCESS_DENIED");
}
return container.data;
} catch (e) {
if (e.message === "RESTRICTED_ACCESS_DENIED") {
throw e;
}
silentTrap(e);
return null;
}
},
signReceipt: async function(prefix, dataLength, actionType, payloadString, integritySalt) {
try {
const rawText = `${prefix}:${dataLength}:${actionType}:${payloadString}:${integritySalt}`;
return await nativeHashSha256(rawText + INTEGRITY_SEAL_SALT);
} catch (e) {
silentTrap(e);
return "fallback_signature_" + dataLength;
}
},
encryptConditionalCapsulePayload,
decryptConditionalCapsulePayload,
auditStorageIntegritySeal,
rotateKeys: rotateSymmetricKeys,
validateData: DataValidationPipeline.validate,
generateRandomBytes: generateSecureRandomBytes,
generateUID: generateSecureIdentifier,
shake256: function(msg, len = 64) {
try {
let hash = 0;
const input = String(msg) + HASH_KEY_SALT;
for (let i = 0; i < input.length; i++) {
const char = input.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash |= 0;
}
return "fte_sha256_" + Math.abs(hash).toString(16).padEnd(len, 'e').substring(0, len);
} catch (e) {
silentTrap(e);
return "fallback_shake_" + len;
}
},
sha256: async function(msg) {
return await nativeHashSha256(msg);
},
encryptAndSignPayload: encryptAndSignPayload,
verifyAndDecryptPayload: verifyAndDecryptPayload,
asyncHashKey: asyncHashKey,
syncHashKey: syncHashKey
};
})(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : this);