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.
331 lines (327 loc) • 12.9 kB
JavaScript
;
var hashCore = require('../../../core/hash/hash-core.js');
require('../../../core/hash/hash-types.js');
require('crypto');
var encoding = require('../../../utils/encoding.js');
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');
/***************************************************************************
* FortifyJS - Secure Array Crypto Handler
*
* This file contains the cryptographic operations for SecureArray
*
* @author Nehonix
* @license MIT
*
* Copyright (c) 2025 Nehonix. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***************************************************************************** */
/**
* Handles cryptographic operations for SecureArray
*/
// Import existing FortifyJS crypto utilities
/**
* Cryptographic handler for SecureArray operations
*/
class ArrayCryptoHandler {
constructor(arrayId) {
this.arrayId = arrayId;
this.encryptionKey = null;
this.derivedKey = null;
this.isInitialized = false;
// Generate a unique salt for this array instance
this.initializeCrypto();
}
/**
* Initialize cryptographic components
*/
initializeCrypto() {
try {
// Generate a unique salt for this array instance
const saltEnhanced = randomCore.SecureRandom.getRandomBytes(32);
// Convert EnhancedUint8Array to regular Uint8Array for Hash operations
const salt = saltEnhanced.toUint8Array();
// Create a unique identifier for this array's crypto context
const context = `SecureArray:${this.arrayId}:${encoding.bufferToHex(salt)}`;
// Store the salt for key derivation
const hashResult = hashCore.Hash.create(context, {
algorithm: "sha256",
salt: salt,
outputFormat: "buffer",
});
this.derivedKey = new Uint8Array(hashResult);
this.isInitialized = true;
}
catch (error) {
console.error("Failed to initialize ArrayCryptoHandler:", error);
this.isInitialized = false;
}
}
/**
* Sets the encryption key for the array
*/
setEncryptionKey(key) {
try {
if (!key || key.length === 0) {
throw new Error("Encryption key cannot be empty");
}
// Derive a strong encryption key from the provided key
const saltEnhanced = randomCore.SecureRandom.getRandomBytes(32);
// Convert EnhancedUint8Array to regular Uint8Array for Hash operations
const salt = saltEnhanced.toUint8Array();
const keyBuffer = new TextEncoder().encode(key);
// Use PBKDF2-like key derivation with multiple rounds
let derivedKey = new Uint8Array(hashCore.Hash.create(keyBuffer, {
algorithm: "sha256",
iterations: 100000,
salt: salt,
outputFormat: "buffer",
}));
// Additional rounds for enhanced security
for (let i = 0; i < 10; i++) {
derivedKey = new Uint8Array(hashCore.Hash.create(derivedKey, {
algorithm: "sha256",
salt: salt,
outputFormat: "buffer",
}));
}
this.encryptionKey = derivedKey;
}
catch (error) {
console.error("Failed to set encryption key:", error);
throw new Error(`Failed to set encryption key: ${error.message}`);
}
}
/**
* Encrypts a value using AES-like encryption with the current key
*/
encryptValue(value) {
if (!this.isInitialized) {
throw new Error("Crypto handler not properly initialized");
}
try {
const key = this.encryptionKey || this.derivedKey;
if (!key) {
throw new Error("No encryption key available");
}
// Serialize the value
const valueStr = typeof value === "string" ? value : JSON.stringify(value);
const valueBytes = new TextEncoder().encode(valueStr);
// Generate a random IV for this encryption
const ivEnhanced = randomCore.SecureRandom.getRandomBytes(16);
const iv = ivEnhanced.toUint8Array();
// Encrypt using a secure stream cipher approach
const encrypted = this.performEncryption(valueBytes, key, iv);
// Create the final encrypted package
const package_ = {
iv: encoding.bufferToHex(iv),
data: encoding.bufferToBase64(encrypted),
algorithm: "AES-256-CTR-HMAC",
timestamp: Date.now(),
};
return `[ENCRYPTED:${encoding.bufferToBase64(new TextEncoder().encode(JSON.stringify(package_)))}]`;
}
catch (error) {
console.error("Encryption failed:", error);
throw new Error(`Encryption failed: ${error.message}`);
}
}
/**
* Decrypts a value using the current key
*/
decryptValue(encryptedValue) {
if (!this.isInitialized) {
throw new Error("Crypto handler not properly initialized");
}
try {
if (!encryptedValue.startsWith("[ENCRYPTED:") ||
!encryptedValue.endsWith("]")) {
throw new Error("Invalid encrypted value format");
}
const key = this.encryptionKey || this.derivedKey;
if (!key) {
throw new Error("No encryption key available");
}
// Extract the encrypted package
const packageData = encryptedValue.slice(11, -1); // Remove [ENCRYPTED: and ]
const packageBytes = encoding.base64ToBuffer(packageData);
const packageStr = new TextDecoder().decode(packageBytes);
const package_ = JSON.parse(packageStr);
// Validate package structure
if (!package_.iv || !package_.data || !package_.algorithm) {
throw new Error("Invalid encrypted package structure");
}
// Extract components
const iv = encoding.hexToBuffer(package_.iv);
const encryptedData = encoding.base64ToBuffer(package_.data);
// Decrypt the data
const decrypted = this.performDecryption(encryptedData, key, iv);
const decryptedStr = new TextDecoder().decode(decrypted);
// Try to parse as JSON, if it fails return as string
try {
return JSON.parse(decryptedStr);
}
catch {
return decryptedStr;
}
}
catch (error) {
console.error("Decryption failed:", error);
throw new Error(`Decryption failed: ${error.message}`);
}
}
/**
* Performs the actual encryption using a secure stream cipher
*/
performEncryption(data, key, iv) {
// Create a keystream using the key and IV
const keystream = this.generateKeystream(key, iv, data.length);
// XOR the data with the keystream
const encrypted = new Uint8Array(data.length);
for (let i = 0; i < data.length; i++) {
encrypted[i] = data[i] ^ keystream[i];
}
// Add HMAC for authentication
const hmac = this.generateHMAC(encrypted, key);
// Combine encrypted data with HMAC
const result = new Uint8Array(encrypted.length + hmac.length);
result.set(encrypted, 0);
result.set(hmac, encrypted.length);
return result;
}
/**
* Performs the actual decryption
*/
performDecryption(encryptedData, key, iv) {
// Split encrypted data and HMAC
const hmacLength = 32; // SHA-256 HMAC length
if (encryptedData.length < hmacLength) {
throw new Error("Invalid encrypted data length");
}
const encrypted = encryptedData.slice(0, -hmacLength);
const receivedHmac = encryptedData.slice(-hmacLength);
// Verify HMAC
const expectedHmac = this.generateHMAC(encrypted, key);
if (!this.constantTimeEqual(receivedHmac, expectedHmac)) {
throw new Error("HMAC verification failed - data may be tampered");
}
// Generate the same keystream
const keystream = this.generateKeystream(key, iv, encrypted.length);
// XOR to decrypt
const decrypted = new Uint8Array(encrypted.length);
for (let i = 0; i < encrypted.length; i++) {
decrypted[i] = encrypted[i] ^ keystream[i];
}
return decrypted;
}
/**
* Generates a secure keystream for encryption/decryption
*/
generateKeystream(key, iv, length) {
const keystream = new Uint8Array(length);
let counter = 0;
for (let i = 0; i < length; i += 32) {
// Create counter block
const counterBlock = new Uint8Array(16);
counterBlock.set(iv.slice(0, 12), 0);
// Add counter (big-endian)
const counterBytes = new Uint8Array(4);
new DataView(counterBytes.buffer).setUint32(0, counter, false);
counterBlock.set(counterBytes, 12);
// Generate block using hash function
const combined = new Uint8Array(key.length + counterBlock.length);
combined.set(key, 0);
combined.set(counterBlock, key.length);
const block = new Uint8Array(hashCore.Hash.create(combined, {
algorithm: "sha256",
outputFormat: "buffer",
}));
// Copy to keystream
const copyLength = Math.min(32, length - i);
keystream.set(block.slice(0, copyLength), i);
counter++;
}
return keystream;
}
/**
* Generates HMAC for authentication
*/
generateHMAC(data, key) {
const hmacHex = hashCore.Hash.createSecureHMAC("sha256", key, data, {
encoding: "hex",
});
return new Uint8Array(Buffer.from(hmacHex, "hex"));
}
/**
* Constant-time comparison to prevent timing attacks
*/
constantTimeEqual(a, b) {
if (a.length !== b.length) {
return false;
}
let diff = 0;
for (let i = 0; i < a.length; i++) {
diff |= a[i] ^ b[i];
}
return diff === 0;
}
/**
* Checks if a value is encrypted
*/
isEncrypted(value) {
return (typeof value === "string" &&
value.startsWith("[ENCRYPTED:") &&
value.endsWith("]"));
}
/**
* Gets the current encryption status
*/
getEncryptionStatus() {
return {
isInitialized: this.isInitialized,
hasEncryptionKey: this.encryptionKey !== null,
algorithm: "AES-256-CTR-HMAC",
};
}
/**
* Securely destroys the crypto handler
*/
destroy() {
// Securely wipe keys
if (this.encryptionKey) {
this.encryptionKey.fill(0);
this.encryptionKey = null;
}
if (this.derivedKey) {
this.derivedKey.fill(0);
this.derivedKey = null;
}
this.isInitialized = false;
}
}
exports.ArrayCryptoHandler = ArrayCryptoHandler;
//# sourceMappingURL=ArrayCryptoHandler.js.map