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.
340 lines (336 loc) • 11.5 kB
JavaScript
;
var crypto = require('crypto');
var randomGenerators = require('./random-generators.js');
var Uint8Array = require('../../helpers/Uint8Array.js');
/**
* Random crypto - Cryptographic utilities (IV, keys, nonces)
*/
class RandomCrypto {
/**
* Generate secure nonce/IV for encryption
* @param algorithm - Algorithm requiring the nonce
* @param options - Generation options
* @returns Nonce as Uint8Array
*/
static generateNonce(algorithm, options = {}) {
let length;
switch (algorithm) {
case "aes-gcm":
length = 12; // 96 bits recommended for AES-GCM
break;
case "chacha20-poly1305":
length = 12; // 96 bits for ChaCha20-Poly1305
break;
case "aes-cbc":
length = 16; // 128 bits for AES-CBC
break;
case "custom":
length = options.customLength || 16;
break;
default:
throw new Error(`Unsupported algorithm: ${algorithm}`);
}
return randomGenerators.RandomGenerators.getRandomBytes(length, options);
}
/**
* Generate a secure Initialization Vector (IV) for encryption algorithms
* @param length - Length of the IV in bytes
* @param options - Generation options including algorithm
* @returns Secure IV as EnhancedUint8Array
*/
static generateSecureIV(length, options = {}) {
const { algorithm, quantumSafe = false, useEntropyPool = true, validateSize = true, } = options;
if (length <= 0) {
throw new Error("IV length must be positive");
}
// If algorithm is specified, validate the length matches expected size
if (algorithm && validateSize) {
const expectedSizes = {
"aes-128-cbc": 16,
"aes-192-cbc": 16,
"aes-256-cbc": 16,
"aes-128-ctr": 16,
"aes-192-ctr": 16,
"aes-256-ctr": 16,
"aes-128-gcm": 12,
"aes-192-gcm": 12,
"aes-256-gcm": 12,
chacha20: 12,
"chacha20-poly1305": 12,
"des-ede3-cbc": 8,
"blowfish-cbc": 8,
};
const expectedSize = expectedSizes[algorithm];
if (expectedSize && length !== expectedSize) {
console.warn(`Warning: IV length ${length} bytes does not match recommended ${expectedSize} bytes for ${algorithm}`);
}
}
// Generate secure random bytes for IV
const iv = randomGenerators.RandomGenerators.getRandomBytes(length, {
quantumSafe,
useEntropyPool,
});
return new Uint8Array.EnhancedUint8Array(iv);
}
/**
* Generate multiple IVs efficiently
* @param count - Number of IVs to generate
* @param length - Length of each IV
* @param options - Generation options
* @returns Array of IVs
*/
static generateSecureIVBatch(count, length, options = {}) {
if (count <= 0 || count > 1000) {
throw new Error("Count must be between 1 and 1000");
}
const ivs = [];
// Generate all random bytes at once for efficiency
const allBytes = randomGenerators.RandomGenerators.getRandomBytes(length * count, options);
for (let i = 0; i < count; i++) {
const offset = i * length;
const ivBytes = allBytes.slice(offset, offset + length);
ivs.push(new Uint8Array.EnhancedUint8Array(ivBytes));
}
return ivs;
}
/**
* Generate IV for specific algorithm
* @param algorithm - Encryption algorithm
* @param options - Generation options
* @returns Algorithm-specific IV
*/
static generateSecureIVForAlgorithm(algorithm, options = {}) {
const algorithmSizes = {
"aes-128-cbc": 16,
"aes-192-cbc": 16,
"aes-256-cbc": 16,
"aes-128-ctr": 16,
"aes-192-ctr": 16,
"aes-256-ctr": 16,
"aes-128-gcm": 12,
"aes-192-gcm": 12,
"aes-256-gcm": 12,
chacha20: 12,
"chacha20-poly1305": 12,
"des-ede3-cbc": 8,
"blowfish-cbc": 8,
};
const length = algorithmSizes[algorithm.toLowerCase()];
if (!length) {
throw new Error(`Unsupported algorithm: ${algorithm}`);
}
return RandomCrypto.generateSecureIV(length, {
...options,
algorithm: algorithm,
});
}
/**
* Generate multiple IVs for specific algorithm
* @param count - Number of IVs to generate
* @param algorithm - Encryption algorithm
* @param options - Generation options
* @returns Array of algorithm-specific IVs
*/
static generateSecureIVBatchForAlgorithm(count, algorithm, options = {}) {
const algorithmSizes = {
"aes-128-cbc": 16,
"aes-192-cbc": 16,
"aes-256-cbc": 16,
"aes-128-ctr": 16,
"aes-192-ctr": 16,
"aes-256-ctr": 16,
"aes-128-gcm": 12,
"aes-192-gcm": 12,
"aes-256-gcm": 12,
chacha20: 12,
"chacha20-poly1305": 12,
"des-ede3-cbc": 8,
"blowfish-cbc": 8,
};
const length = algorithmSizes[algorithm.toLowerCase()];
if (!length) {
throw new Error(`Unsupported algorithm: ${algorithm}`);
}
return RandomCrypto.generateSecureIVBatch(count, length, {
...options,
algorithm: algorithm,
});
}
/**
* Validate IV for algorithm
* @param iv - IV to validate
* @param algorithm - Target algorithm
* @returns Validation result
*/
static validateIV(iv, algorithm) {
const algorithmSizes = {
"aes-128-cbc": 16,
"aes-192-cbc": 16,
"aes-256-cbc": 16,
"aes-128-ctr": 16,
"aes-192-ctr": 16,
"aes-256-ctr": 16,
"aes-128-gcm": 12,
"aes-192-gcm": 12,
"aes-256-gcm": 12,
chacha20: 12,
"chacha20-poly1305": 12,
"des-ede3-cbc": 8,
"blowfish-cbc": 8,
};
const expectedLength = algorithmSizes[algorithm.toLowerCase()];
const actualLength = iv.length;
if (!expectedLength) {
return {
valid: false,
actualLength,
message: `Unknown algorithm: ${algorithm}`,
};
}
if (actualLength !== expectedLength) {
return {
valid: false,
expectedLength,
actualLength,
message: `IV length mismatch: expected ${expectedLength} bytes, got ${actualLength} bytes`,
};
}
// Check for all zeros (weak IV)
const isAllZeros = Array.from(iv).every((byte) => byte === 0);
if (isAllZeros) {
return {
valid: false,
expectedLength,
actualLength,
message: "IV is all zeros (weak)",
};
}
return {
valid: true,
expectedLength,
actualLength,
message: "IV is valid",
};
}
/**
* Create secure cipher with auto-generated IV
* @param algorithm - Cipher algorithm
* @param key - Encryption key
* @param options - Cipher options
* @returns Cipher and IV
*/
static createSecureCipheriv(algorithm, key, options = {}) {
const ivOptions = {
quantumSafe: options.quantumSafe,
useEntropyPool: options.useHardwareEntropy,
validateSize: options.validateStrength,
};
const iv = RandomCrypto.generateSecureIVForAlgorithm(algorithm, ivOptions);
const cipher = crypto.createCipheriv(algorithm, key, Buffer.from(iv));
return { cipher, iv: Buffer.from(iv) };
}
/**
* Create secure decipher
* @param algorithm - Cipher algorithm
* @param key - Decryption key
* @param iv - Initialization vector
* @returns Decipher
*/
static createSecureDecipheriv(algorithm, key, iv) {
return crypto.createDecipheriv(algorithm, key, iv);
}
/**
* Generate cryptographic key
* @param length - Key length in bytes
* @param options - Generation options
* @returns Cryptographic key
*/
static generateCryptoKey(length, options = {}) {
const { quantumSafe = false, useHardwareEntropy = true, validateStrength = true, } = options;
const keyBytes = randomGenerators.RandomGenerators.getRandomBytes(length, {
quantumSafe,
useEntropyPool: useHardwareEntropy,
});
const key = Buffer.from(keyBytes);
if (validateStrength) {
RandomCrypto.validateKeyStrength(key);
}
return key;
}
/**
* Validate key strength
* @param key - Key to validate
* @returns Validation result
*/
static validateKeyStrength(key) {
const issues = [];
let strength = "strong";
// Check for all zeros
if (key.every((byte) => byte === 0)) {
issues.push("Key is all zeros");
strength = "weak";
}
// Check for all same value
const firstByte = key[0];
if (key.every((byte) => byte === firstByte)) {
issues.push("Key has no entropy");
strength = "weak";
}
// Check entropy
const uniqueBytes = new Set(key);
const entropyRatio = uniqueBytes.size / key.length;
if (entropyRatio < 0.1) {
issues.push("Very low entropy");
strength = "weak";
}
else if (entropyRatio < 0.3) {
issues.push("Low entropy");
strength = "fair";
}
else if (entropyRatio < 0.6) {
strength = "good";
}
// Check length
if (key.length < 16) {
issues.push("Key too short");
strength = "weak";
}
else if (key.length < 32) {
if (strength === "strong")
strength = "good";
}
return {
valid: issues.length === 0,
strength,
issues,
};
}
/**
* Generate key derivation salt
* @param length - Salt length
* @param options - Generation options
* @returns KDF salt
*/
static generateKDFSalt(length = 32, options = {}) {
return randomGenerators.RandomGenerators.generateSalt(length, options);
}
/**
* Generate HMAC key
* @param algorithm - HMAC algorithm
* @param options - Generation options
* @returns HMAC key
*/
static generateHMACKey(algorithm = "sha256", options = {}) {
// Recommended key sizes for HMAC
const keySizes = {
sha1: 20,
sha256: 32,
sha384: 48,
sha512: 64,
};
const keySize = keySizes[algorithm.toLowerCase()] || 32;
return RandomCrypto.generateCryptoKey(keySize, options);
}
}
exports.RandomCrypto = RandomCrypto;
//# sourceMappingURL=random-crypto.js.map