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
JavaScript
'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