UNPKG

fortify2-js

Version:

MOST POWERFUL JavaScript Security Library! Military-grade cryptography + 19 enhanced object methods + quantum-resistant algorithms + perfect TypeScript support. More powerful than Lodash with built-in security.

400 lines (394 loc) 15 kB
'use strict'; var hashCore = require('../../../core/hash/hash-core.js'); require('../../../core/hash/hash-types.js'); var crypto = require('crypto'); require('../../../core/hash/hash-security.js'); require('../../../core/hash/hash-advanced.js'); require('../../../algorithms/hash-algorithms.js'); var randomCore = require('../../../core/random/random-core.js'); require('../../../core/random/random-types.js'); require('../../../core/random/random-sources.js'); require('nehonix-uri-processor'); require('../../../utils/memory/index.js'); require('../../../types.js'); var randomCrypto = require('../../../core/random/random-crypto.js'); var validators = require('../../../core/validators.js'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var crypto__namespace = /*#__PURE__*/_interopNamespaceDefault(crypto); /** * FortifyJS Express Encryption Service * encryption/decryption service using FortifyJS cryptographic utilities * * Features: * - AES-256-GCM encryption with authentication * - ChaCha20-Poly1305 fallback for quantum-safe encryption * - Proper key derivation using PBKDF2 * - Secure IV/nonce generation * - Constant-time operations * - Memory-safe operations with secure wiping */ /** * encryption service using FortifyJS utilities */ class EncryptionService { /** * Encrypt data using production-grade encryption */ static async encrypt(data, key, options = {}) { try { // Validate inputs this.validateInputs(data, key); const { algorithm = "aes-256-gcm", keyDerivationIterations = this.DEFAULT_ITERATIONS, additionalData, quantumSafe = false, } = options; // Serialize data const jsonData = JSON.stringify(data); const dataBuffer = new TextEncoder().encode(jsonData); // Generate cryptographically secure salt const salt = randomCore.SecureRandom.getRandomBytes(this.SALT_LENGTH); // Derive encryption key using PBKDF2 const derivedKey = await this.deriveKey(key, salt, keyDerivationIterations); // Generate secure IV/nonce const iv = this.generateIV(algorithm); // Encrypt based on algorithm let encrypted; let authTag; if (algorithm === "chacha20-poly1305" || quantumSafe) { ({ encrypted, authTag } = this.encryptChaCha20Poly1305(dataBuffer, derivedKey, iv, additionalData)); } else { ({ encrypted, authTag } = this.encryptAES256GCM(dataBuffer, derivedKey, iv, additionalData)); } // Create encrypted package const package_ = { algorithm: quantumSafe ? "chacha20-poly1305" : algorithm, iv: this.bufferToHex(iv), data: this.bufferToHex(encrypted), authTag: this.bufferToHex(authTag), salt: this.bufferToHex(salt.toUint8Array()), timestamp: Date.now(), version: this.VERSION, }; // Secure memory cleanup this.secureWipe(derivedKey); this.secureWipe(dataBuffer); return JSON.stringify(package_); } catch (error) { throw new Error(`Encryption failed: ${error instanceof Error ? error.message : "Unknown error"}`); } } /** * Decrypt data using production-grade decryption */ static async decrypt(encryptedData, key) { try { // Parse encrypted package const package_ = JSON.parse(encryptedData); this.validatePackage(package_); // Convert hex strings back to buffers const iv = this.hexToBuffer(package_.iv); const encrypted = this.hexToBuffer(package_.data); const authTag = this.hexToBuffer(package_.authTag); const salt = this.hexToBuffer(package_.salt); // Derive the same key const derivedKey = await this.deriveKey(key, salt, this.DEFAULT_ITERATIONS); // Decrypt based on algorithm let decrypted; if (package_.algorithm === "chacha20-poly1305") { decrypted = this.decryptChaCha20Poly1305(encrypted, derivedKey, iv, authTag); } else { decrypted = this.decryptAES256GCM(encrypted, derivedKey, iv, authTag); } // Convert back to string and parse JSON const jsonString = new TextDecoder().decode(decrypted); const result = JSON.parse(jsonString); // Secure memory cleanup this.secureWipe(derivedKey); this.secureWipe(decrypted); return result; } catch (error) { throw new Error(`Decryption failed: ${error instanceof Error ? error.message : "Invalid encrypted data"}`); } } /** * Derive encryption key using PBKDF2 */ static async deriveKey(password, salt, iterations) { const passwordBuffer = new TextEncoder().encode(password); const saltBuffer = salt instanceof Uint8Array ? salt : salt.toUint8Array(); // Use FortifyJS Hash for key derivation const hashResult = hashCore.Hash.createSecureHash(passwordBuffer, saltBuffer, { algorithm: "sha256", iterations, outputFormat: "buffer", }); // Handle both sync and async results const derivedKey = hashResult instanceof Promise ? Buffer.from((await hashResult)) : Buffer.from(hashResult); return new Uint8Array(derivedKey); } /** * Generate secure IV/nonce for encryption */ static generateIV(algorithm) { return randomCrypto.RandomCrypto.generateNonce(algorithm === "chacha20-poly1305" ? "chacha20-poly1305" : "aes-gcm", { quantumSafe: true }); } /** * Encrypt using AES-256-GCM */ static encryptAES256GCM(data, key, iv, additionalData) { try { // Use Node.js crypto for AES-GCM const cipher = crypto__namespace.createCipheriv("aes-256-gcm", key.slice(0, 32), iv); if (additionalData) { cipher.setAAD(new TextEncoder().encode(additionalData)); } const encrypted = Buffer.concat([ cipher.update(Buffer.from(data)), cipher.final(), ]); const authTag = cipher.getAuthTag(); return { encrypted: new Uint8Array(encrypted), authTag: new Uint8Array(authTag), }; } catch (error) { throw new Error(`AES-GCM encryption failed: ${error instanceof Error ? error.message : "Unknown error"}`); } } /** * Decrypt using AES-256-GCM */ static decryptAES256GCM(encrypted, key, iv, authTag) { try { const decipher = crypto__namespace.createDecipheriv("aes-256-gcm", key.slice(0, 32), iv); decipher.setAuthTag(Buffer.from(authTag)); const decrypted = Buffer.concat([ decipher.update(Buffer.from(encrypted)), decipher.final(), ]); return new Uint8Array(decrypted); } catch (error) { throw new Error(`AES-GCM decryption failed: ${error instanceof Error ? error.message : "Authentication failed"}`); } } /** * Encrypt using ChaCha20-Poly1305 (quantum-safe fallback) */ static encryptChaCha20Poly1305(data, key, iv, additionalData) { // Try to use libsodium if available try { const sodium = require("libsodium-wrappers"); if (sodium && typeof sodium.crypto_aead_chacha20poly1305_ietf_encrypt === "function") { const aad = additionalData ? new TextEncoder().encode(additionalData) : null; const result = sodium.crypto_aead_chacha20poly1305_ietf_encrypt(data, aad, null, iv, key.slice(0, 32)); // Split result into encrypted data and auth tag const encrypted = result.slice(0, -16); const authTag = result.slice(-16); return { encrypted: new Uint8Array(encrypted), authTag: new Uint8Array(authTag), }; } } catch (error) { // Fall back to AES-GCM if ChaCha20-Poly1305 is not available console.warn("ChaCha20-Poly1305 not available, falling back to AES-GCM"); } // Fallback to AES-GCM return this.encryptAES256GCM(data, key, iv, additionalData); } /** * Decrypt using ChaCha20-Poly1305 */ static decryptChaCha20Poly1305(encrypted, key, iv, authTag) { // Try to use libsodium if available try { const sodium = require("libsodium-wrappers"); if (sodium && typeof sodium.crypto_aead_chacha20poly1305_ietf_decrypt === "function") { const ciphertext = new Uint8Array(encrypted.length + authTag.length); ciphertext.set(encrypted); ciphertext.set(authTag, encrypted.length); const result = sodium.crypto_aead_chacha20poly1305_ietf_decrypt(null, ciphertext, null, iv, key.slice(0, 32)); return new Uint8Array(result); } } catch (error) { // Fall back to AES-GCM if ChaCha20-Poly1305 is not available console.warn("ChaCha20-Poly1305 not available, falling back to AES-GCM"); } // Fallback to AES-GCM return this.decryptAES256GCM(encrypted, key, iv, authTag); } /** * Validate inputs for encryption */ static validateInputs(data, key) { if (data === undefined || data === null) { throw new Error("Data cannot be null or undefined"); } if (!key || typeof key !== "string") { throw new Error("Key must be a non-empty string"); } if (key.length < 8) { throw new Error("Key must be at least 8 characters long"); } // Use FortifyJS validators for additional validation try { validators.Validators.validateLength(key.length, 8, 1024); } catch (error) { throw new Error(`Invalid key: ${error instanceof Error ? error.message : "Unknown error"}`); } } /** * Validate encrypted package structure */ static validatePackage(package_) { const requiredFields = [ "algorithm", "iv", "data", "authTag", "salt", "timestamp", "version", ]; for (const field of requiredFields) { if (!package_[field]) { throw new Error(`Invalid encrypted package: missing ${field}`); } } if (!["aes-256-gcm", "chacha20-poly1305"].includes(package_.algorithm)) { throw new Error(`Unsupported encryption algorithm: ${package_.algorithm}`); } // Validate timestamp (not too old, not in future) const now = Date.now(); const maxAge = 24 * 60 * 60 * 1000; // 24 hours if (package_.timestamp > now + 60000) { // 1 minute future tolerance throw new Error("Invalid encrypted package: timestamp in future"); } if (now - package_.timestamp > maxAge) { throw new Error("Invalid encrypted package: timestamp too old"); } } /** * Convert buffer to hex string */ static bufferToHex(buffer) { return Array.from(buffer) .map((b) => b.toString(16).padStart(2, "0")) .join(""); } /** * Convert hex string to buffer */ static hexToBuffer(hex) { if (hex.length % 2 !== 0) { throw new Error("Invalid hex string length"); } const buffer = new Uint8Array(hex.length / 2); for (let i = 0; i < hex.length; i += 2) { buffer[i / 2] = parseInt(hex.substring(i, i + 2), 16); } return buffer; } /** * Secure memory wipe using FortifyJS utilities */ static secureWipe(buffer) { try { // Use FortifyJS secure memory wiping if (buffer && buffer.length > 0) { // Overwrite with random data first const randomData = randomCore.SecureRandom.getRandomBytes(buffer.length); buffer.set(randomData.toUint8Array()); // Then overwrite with zeros buffer.fill(0); // Finally overwrite with 0xFF buffer.fill(0xff); buffer.fill(0); } } catch (error) { // Fallback to simple zero fill if (buffer && buffer.length > 0) { buffer.fill(0); } } } /** * Generate a secure session key for temporary use */ static generateSessionKey() { const keyBytes = randomCore.SecureRandom.getRandomBytes(32); return this.bufferToHex(keyBytes.toUint8Array()); } /** * Verify the integrity of encrypted data without decrypting */ static verifyIntegrity(encryptedData) { try { const package_ = JSON.parse(encryptedData); this.validatePackage(package_); return true; } catch (error) { return false; } } /** * Get encryption metadata without decrypting */ static getMetadata(encryptedData) { try { const package_ = JSON.parse(encryptedData); return { algorithm: package_.algorithm, timestamp: package_.timestamp, version: package_.version, }; } catch (error) { throw new Error("Invalid encrypted data format"); } } } EncryptionService.VERSION = "1.0.0"; EncryptionService.DEFAULT_ITERATIONS = 100000; EncryptionService.KEY_LENGTH = 32; // 256 bits EncryptionService.IV_LENGTH = 12; // 96 bits for GCM EncryptionService.SALT_LENGTH = 32; // 256 bits EncryptionService.AUTH_TAG_LENGTH = 16; // 128 bits exports.EncryptionService = EncryptionService; //# sourceMappingURL=EncryptionService.js.map