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.

396 lines (392 loc) 15.8 kB
'use strict'; var hashCore = require('../hash/hash-core.js'); var hashTypes = require('../hash/hash-types.js'); require('crypto'); var randomCore = require('../random/random-core.js'); require('../random/random-types.js'); require('../random/random-sources.js'); require('nehonix-uri-processor'); require('../../utils/memory/index.js'); var types = require('../../types.js'); require('argon2'); require('../../algorithms/hash-algorithms.js'); var sideChannel = require('../../security/side-channel.js'); require('child_process'); require('../../types/secure-memory.js'); require('https'); require('../../security/runtime-verification.js'); require('../../security/tamper-evident-logging.js'); var passwordTypes = require('./password-types.js'); /** * 🔐 Password Algorithms Module * * Implements various password hashing algorithms with security optimizations */ /** * Password hashing algorithms implementation */ class PasswordAlgorithms { constructor(config) { this.config = config; } /** * Update configuration */ updateConfig(config) { this.config = config; } /** * Hash password using specified algorithm */ async hash(password, salt, options) { switch (options.algorithm) { case passwordTypes.PasswordAlgorithm.ARGON2ID: return this.hashWithArgon2(password, salt, options, "id"); case passwordTypes.PasswordAlgorithm.ARGON2I: return this.hashWithArgon2(password, salt, options, "i"); case passwordTypes.PasswordAlgorithm.ARGON2D: return this.hashWithArgon2(password, salt, options, "d"); case passwordTypes.PasswordAlgorithm.SCRYPT: return this.hashWithScrypt(password, salt, options); case passwordTypes.PasswordAlgorithm.PBKDF2_SHA512: return this.hashWithPBKDF2(password, salt, options); case passwordTypes.PasswordAlgorithm.BCRYPT_PLUS: return this.hashWithBcryptPlus(password, salt, options); case passwordTypes.PasswordAlgorithm.MILITARY: return this.hashWithMilitary(password, salt, options); default: throw new Error(`Unsupported algorithm: ${options.algorithm}`); } } /** * Verify password using specified algorithm */ async verify(password, hash, salt, metadata) { const options = { algorithm: metadata.algorithm, securityLevel: metadata.securityLevel, iterations: metadata.iterations, memorySize: metadata.memorySize, parallelism: metadata.parallelism, saltLength: metadata.saltLength, }; const computedHash = await this.hash(password, salt, options); // Use constant-time comparison to prevent timing attacks return sideChannel.constantTimeEqual(hash, computedHash); } /** * Hash with Argon2 (recommended) */ async hashWithArgon2(password, salt, options, variant) { // Try to use native Argon2 implementation try { const argon2 = await import('argon2').catch(() => null); if (argon2) { const argon2Options = { type: variant === "i" ? argon2.argon2i : variant === "d" ? argon2.argon2d : argon2.argon2id, memoryCost: options.memorySize || 65536, timeCost: Math.floor((options.iterations || 100000) / 1000), parallelism: options.parallelism || 4, salt: Buffer.from(salt), hashLength: 32, }; const fullHash = await argon2.hash(password, argon2Options); // Extract just the hash part from the full Argon2 format return this.extractHashValue(fullHash); } } catch (error) { // Fall back to custom implementation } // Fallback: Use PBKDF2 with enhanced security return this.hashWithEnhancedPBKDF2(password, salt, options, `argon2${variant}-fallback`); } /** * Hash with scrypt */ async hashWithScrypt(password, salt, options) { try { // Use Node.js built-in crypto.scrypt const crypto = await import('crypto'); const scryptOptions = { N: Math.pow(2, 14), // CPU/memory cost (16384 - more reasonable) r: 8, // Block size p: options.parallelism || 1, }; // Use promisified scrypt const result = await new Promise((resolve, reject) => { crypto.scrypt(password, Buffer.from(salt), 32, scryptOptions, (err, derivedKey) => { if (err) reject(err); else resolve(derivedKey); }); }); return result.toString("hex"); } catch (error) { // Fall back to enhanced PBKDF2 } return this.hashWithEnhancedPBKDF2(password, salt, options, "scrypt-fallback"); } /** * Hash with PBKDF2-SHA512 */ async hashWithPBKDF2(password, salt, options) { const iterations = options.iterations || 100000; // Use FortifyJS Hash module for PBKDF2 const hash = hashCore.Hash.createSecureHash(password, salt, { algorithm: types.HashAlgorithm.PBKDF2, iterations, outputFormat: "hex", strength: hashTypes.HashStrength.MILITARY, memoryHard: false, // Explicitly disable memory-hard hashing quantumResistant: false, // Explicitly disable quantum-resistant hashing timingSafe: false, // Explicitly disable timing-safe hashing }); // Extract just the hash part using our helper method return this.extractHashValue(hash); } /** * Enhanced PBKDF2 with multiple rounds and algorithms */ async hashWithEnhancedPBKDF2(password, salt, options, prefix = "enhanced") { const iterations = options.iterations || 100000; // First round: PBKDF2-SHA512 let round1 = hashCore.Hash.createSecureHash(password, salt, { algorithm: types.HashAlgorithm.PBKDF2, iterations: Math.floor(iterations / 3), outputFormat: "hex", memoryHard: false, quantumResistant: false, timingSafe: false, }); // Extract just the hash using our helper method round1 = this.extractHashValue(round1); // Second round: SHA3-512 let round2 = hashCore.Hash.createSecureHash(round1, salt, { algorithm: types.HashAlgorithm.SHA3_512, iterations: Math.floor(iterations / 3), outputFormat: "hex", memoryHard: false, quantumResistant: false, timingSafe: false, }); // Extract just the hash using our helper method round2 = this.extractHashValue(round2); // Third round: BLAKE3 let finalHash = hashCore.Hash.createSecureHash(round2, salt, { algorithm: types.HashAlgorithm.BLAKE3, iterations: Math.floor(iterations / 3), outputFormat: "hex", memoryHard: false, quantumResistant: false, timingSafe: false, }); // Extract just the hash using our helper method finalHash = this.extractHashValue(finalHash); return `${prefix}:${finalHash}`; } /** * Enhanced bcrypt with additional security layers */ async hashWithBcryptPlus(password, salt, options) { try { const bcrypt = await import('bcrypt').catch(() => null); if (bcrypt) { // First layer: Standard bcrypt const rounds = Math.min(15, Math.max(10, Math.floor((options.iterations || 100000) / 10000))); const bcryptHash = await bcrypt.hash(password, rounds); // Second layer: PBKDF2 on bcrypt result let enhancedHash = hashCore.Hash.createSecureHash(bcryptHash, salt, { algorithm: types.HashAlgorithm.PBKDF2, iterations: 50000, outputFormat: "hex", memoryHard: false, quantumResistant: false, timingSafe: false, }); // Extract just the hash using our helper method enhancedHash = this.extractHashValue(enhancedHash); return `bcrypt-plus:${enhancedHash}`; } } catch (error) { // Fall back to enhanced PBKDF2 } return this.hashWithEnhancedPBKDF2(password, salt, options, "bcrypt-plus-fallback"); } /** * Military-grade multi-layer hashing */ async hashWithMilitary(password, salt, options) { const iterations = options.iterations || 200000; // Layer 1: Key stretching with PBKDF2-SHA512 let layer1 = hashCore.Hash.createSecureHash(password, salt, { algorithm: types.HashAlgorithm.PBKDF2, iterations: Math.floor(iterations / 4), outputFormat: "hex", memoryHard: false, quantumResistant: false, timingSafe: false, }); // Extract just the hash using our helper method layer1 = this.extractHashValue(layer1); // Layer 2: Memory-hard function simulation let layer2 = layer1; for (let i = 0; i < 1000; i++) { const tempSalt = randomCore.SecureRandom.generateSalt(32); let tempHash = hashCore.Hash.createSecureHash(layer2, tempSalt, { algorithm: types.HashAlgorithm.SHA3_512, outputFormat: "hex", memoryHard: false, quantumResistant: false, timingSafe: false, }); // Extract just the hash using our helper method layer2 = this.extractHashValue(tempHash); } // Layer 3: BLAKE3 with high iterations let layer3 = hashCore.Hash.createSecureHash(layer2, salt, { algorithm: types.HashAlgorithm.BLAKE3, iterations: Math.floor(iterations / 4), outputFormat: "hex", memoryHard: false, quantumResistant: false, timingSafe: false, }); // Extract just the hash using our helper method layer3 = this.extractHashValue(layer3); // Layer 4: Final hardening with SHA3-512 let finalHash = hashCore.Hash.createSecureHash(layer3, salt, { algorithm: types.HashAlgorithm.SHA3_512, iterations: Math.floor(iterations / 4), outputFormat: "hex", strength: hashTypes.HashStrength.MILITARY, memoryHard: false, quantumResistant: false, timingSafe: false, }); // Extract just the hash using our helper method finalHash = this.extractHashValue(finalHash); return `military:${finalHash}`; } // ===== PRIVATE HELPER METHODS ===== /** * Extract just the hash value from complex hash formats */ extractHashValue(hashResult) { // Handle Argon2 format: $argon2id$v=19$m=65536,t=3,p=4$salt$hash if (hashResult.startsWith("$argon2")) { const parts = hashResult.split("$"); if (parts.length >= 6) { return parts[5]; // The actual hash is the last part } } // Handle PBKDF2 format: $pbkdf2$rounds$salt$hash if (hashResult.startsWith("$pbkdf2")) { const parts = hashResult.split("$"); if (parts.length >= 5) { return parts[4]; // The actual hash } } // Handle bcrypt format: $2b$rounds$salthash (extract hash part) if (hashResult.startsWith("$2")) { const parts = hashResult.split("$"); if (parts.length >= 4) { const saltAndHash = parts[3]; if (saltAndHash.length > 22) { return saltAndHash.substring(22); // bcrypt hash after 22-char salt } } } // Handle scrypt format: $scrypt$N$r$p$salt$hash if (hashResult.startsWith("$scrypt")) { const parts = hashResult.split("$"); if (parts.length >= 7) { return parts[6]; // The actual hash } } // Handle any other $ delimited format - take the last part if (hashResult.includes("$")) { const parts = hashResult.split("$"); return parts[parts.length - 1]; } // If no special format, return as-is return hashResult; } /** * Get algorithm-specific default options */ getAlgorithmDefaults(algorithm) { switch (algorithm) { case passwordTypes.PasswordAlgorithm.ARGON2ID: case passwordTypes.PasswordAlgorithm.ARGON2I: case passwordTypes.PasswordAlgorithm.ARGON2D: return { iterations: 3, memorySize: 65536, // 64MB parallelism: 4, saltLength: 32, }; case passwordTypes.PasswordAlgorithm.SCRYPT: return { iterations: 32768, // N parameter memorySize: 8, // r parameter parallelism: 1, // p parameter saltLength: 32, }; case passwordTypes.PasswordAlgorithm.PBKDF2_SHA512: return { iterations: 100000, saltLength: 32, }; case passwordTypes.PasswordAlgorithm.BCRYPT_PLUS: return { iterations: 120000, // Equivalent to bcrypt rounds + PBKDF2 saltLength: 32, }; case passwordTypes.PasswordAlgorithm.MILITARY: return { iterations: 200000, memorySize: 131072, // 128MB equivalent parallelism: 8, saltLength: 64, }; default: return { iterations: 100000, saltLength: 32, }; } } /** * Estimate hashing time for algorithm */ estimateHashingTime(algorithm, options) { // Rough estimates in milliseconds switch (algorithm) { case passwordTypes.PasswordAlgorithm.ARGON2ID: case passwordTypes.PasswordAlgorithm.ARGON2I: case passwordTypes.PasswordAlgorithm.ARGON2D: return ((options.memorySize || 65536) / 1000 + (options.iterations || 3) * 100); case passwordTypes.PasswordAlgorithm.SCRYPT: return (options.iterations || 32768) / 100; case passwordTypes.PasswordAlgorithm.PBKDF2_SHA512: return (options.iterations || 100000) / 1000; case passwordTypes.PasswordAlgorithm.BCRYPT_PLUS: return (options.iterations || 120000) / 500; case passwordTypes.PasswordAlgorithm.MILITARY: return (options.iterations || 200000) / 200; default: return 100; // Default estimate } } } exports.PasswordAlgorithms = PasswordAlgorithms; //# sourceMappingURL=password-algorithms.js.map