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.
337 lines (335 loc) • 12.8 kB
JavaScript
/**
* Advanced Entropy Analyzer Module
* Provides sophisticated entropy analysis for SecureString
*/
/**
* Advanced entropy analyzer for strings
*/
class EntropyAnalyzer {
/**
* Performs comprehensive entropy analysis
*/
static analyzeEntropy(content) {
const shannonEntropy = this.calculateShannonEntropy(content);
const minEntropy = this.calculateMinEntropy(content);
const maxEntropy = Math.log2(this.getUniqueCharacters(content).length);
const compressionRatio = this.calculateCompressionRatio(content);
const characterDistribution = this.getCharacterDistribution(content);
const bigramEntropy = this.calculateNGramEntropy(content, 2);
const trigramEntropy = this.calculateNGramEntropy(content, 3);
const patternComplexity = this.calculatePatternComplexity(content);
const predictability = this.calculatePredictability(content);
const randomnessScore = this.calculateRandomnessScore(content);
const recommendations = this.generateRecommendations(content, shannonEntropy, patternComplexity);
return {
shannonEntropy,
minEntropy,
maxEntropy,
compressionRatio,
patternComplexity,
characterDistribution,
bigramEntropy,
trigramEntropy,
predictability,
randomnessScore,
recommendations,
};
}
/**
* Analyzes patterns in the string
*/
static analyzePatterns(content) {
const repeatingPatterns = this.findRepeatingPatterns(content);
const sequentialPatterns = this.findSequentialPatterns(content);
const keyboardPatterns = this.findKeyboardPatterns(content);
const dictionaryWords = this.findDictionaryWords(content);
const commonSubstitutions = this.findCommonSubstitutions(content);
const overallComplexity = this.calculateOverallComplexity(content);
return {
repeatingPatterns,
sequentialPatterns,
keyboardPatterns,
dictionaryWords,
commonSubstitutions,
overallComplexity,
};
}
/**
* Calculates Shannon entropy
*/
static calculateShannonEntropy(content) {
const frequencies = this.getCharacterFrequencies(content);
const length = content.length;
let entropy = 0;
for (const count of Object.values(frequencies)) {
const probability = count / length;
entropy -= probability * Math.log2(probability);
}
return entropy;
}
/**
* Calculates min-entropy (worst-case entropy)
*/
static calculateMinEntropy(content) {
const frequencies = this.getCharacterFrequencies(content);
const maxFrequency = Math.max(...Object.values(frequencies));
const probability = maxFrequency / content.length;
return -Math.log2(probability);
}
/**
* Calculates n-gram entropy
*/
static calculateNGramEntropy(content, n) {
if (content.length < n)
return 0;
const ngrams = {};
const totalNgrams = content.length - n + 1;
for (let i = 0; i <= content.length - n; i++) {
const ngram = content.substring(i, i + n);
ngrams[ngram] = (ngrams[ngram] || 0) + 1;
}
let entropy = 0;
for (const count of Object.values(ngrams)) {
const probability = count / totalNgrams;
entropy -= probability * Math.log2(probability);
}
return entropy;
}
/**
* Calculates compression ratio as entropy indicator
*/
static calculateCompressionRatio(content) {
// Simulate compression by counting unique substrings
const substrings = new Set();
for (let len = 1; len <= Math.min(content.length, 10); len++) {
for (let i = 0; i <= content.length - len; i++) {
substrings.add(content.substring(i, i + len));
}
}
return substrings.size / content.length;
}
/**
* Calculates pattern complexity
*/
static calculatePatternComplexity(content) {
let complexity = 0;
// Character variety
const uniqueChars = this.getUniqueCharacters(content);
complexity += uniqueChars.length / content.length;
// Case variation
const hasUpper = /[A-Z]/.test(content);
const hasLower = /[a-z]/.test(content);
const hasDigits = /\d/.test(content);
const hasSpecial = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(content);
complexity += (Number(hasUpper) + Number(hasLower) + Number(hasDigits) + Number(hasSpecial)) / 4;
// Pattern disruption
const patterns = this.findRepeatingPatterns(content);
complexity -= patterns.length / content.length;
return Math.max(0, Math.min(1, complexity));
}
/**
* Calculates predictability score
*/
static calculatePredictability(content) {
let predictability = 0;
// Sequential characters
let sequential = 0;
for (let i = 1; i < content.length; i++) {
const diff = content.charCodeAt(i) - content.charCodeAt(i - 1);
if (Math.abs(diff) === 1)
sequential++;
}
predictability += sequential / (content.length - 1);
// Repeated characters
let repeated = 0;
for (let i = 1; i < content.length; i++) {
if (content[i] === content[i - 1])
repeated++;
}
predictability += repeated / (content.length - 1);
return Math.min(1, predictability);
}
/**
* Calculates overall randomness score
*/
static calculateRandomnessScore(content) {
const entropy = this.calculateShannonEntropy(content);
const maxPossibleEntropy = Math.log2(256); // Assuming byte-level entropy
const normalizedEntropy = entropy / maxPossibleEntropy;
const complexity = this.calculatePatternComplexity(content);
const predictability = this.calculatePredictability(content);
return (normalizedEntropy + complexity + (1 - predictability)) / 3;
}
/**
* Finds repeating patterns
*/
static findRepeatingPatterns(content) {
const patterns = {};
for (let len = 2; len <= Math.min(content.length / 2, 10); len++) {
for (let i = 0; i <= content.length - len; i++) {
const pattern = content.substring(i, i + len);
if (!patterns[pattern]) {
patterns[pattern] = { count: 0, positions: [] };
}
patterns[pattern].count++;
patterns[pattern].positions.push(i);
}
}
return Object.entries(patterns)
.filter(([, data]) => data.count > 1)
.map(([pattern, data]) => ({ pattern, ...data }))
.sort((a, b) => b.count - a.count)
.slice(0, 10);
}
/**
* Finds sequential patterns
*/
static findSequentialPatterns(content) {
const patterns = [];
for (let len = 3; len <= Math.min(content.length, 8); len++) {
for (let i = 0; i <= content.length - len; i++) {
const substring = content.substring(i, i + len);
if (this.isSequential(substring)) {
const type = this.getSequentialType(substring);
patterns.push({ pattern: substring, type });
}
}
}
return patterns;
}
/**
* Finds keyboard patterns
*/
static findKeyboardPatterns(content) {
const patterns = [];
for (const [layout, layoutPatterns] of Object.entries(this.KEYBOARD_PATTERNS)) {
for (const keyPattern of layoutPatterns) {
for (let len = 3; len <= keyPattern.length; len++) {
for (let i = 0; i <= keyPattern.length - len; i++) {
const pattern = keyPattern.substring(i, i + len);
if (content.toLowerCase().includes(pattern)) {
patterns.push({ pattern, layout });
}
}
}
}
}
return patterns;
}
/**
* Finds dictionary words
*/
static findDictionaryWords(content) {
const words = [];
const lowerContent = content.toLowerCase();
for (const word of this.COMMON_WORDS) {
let position = lowerContent.indexOf(word);
while (position !== -1) {
const confidence = word.length / content.length;
words.push({ word, position, confidence });
position = lowerContent.indexOf(word, position + 1);
}
}
return words.sort((a, b) => b.confidence - a.confidence);
}
/**
* Finds common substitutions (like @ for a, 3 for e)
*/
static findCommonSubstitutions(content) {
const substitutions = [
{ original: 'a', substituted: '@' },
{ original: 'e', substituted: '3' },
{ original: 'i', substituted: '1' },
{ original: 'o', substituted: '0' },
{ original: 's', substituted: '$' },
{ original: 't', substituted: '7' },
];
const found = [];
for (const sub of substitutions) {
if (content.includes(sub.substituted)) {
found.push(sub);
}
}
return found;
}
/**
* Helper methods
*/
static getCharacterFrequencies(content) {
const frequencies = {};
for (const char of content) {
frequencies[char] = (frequencies[char] || 0) + 1;
}
return frequencies;
}
static getCharacterDistribution(content) {
const frequencies = this.getCharacterFrequencies(content);
const distribution = {};
for (const [char, count] of Object.entries(frequencies)) {
distribution[char] = count / content.length;
}
return distribution;
}
static getUniqueCharacters(content) {
return Array.from(new Set(content));
}
static isSequential(str) {
if (str.length < 3)
return false;
const ascending = str.split('').every((char, i) => i === 0 || char.charCodeAt(0) === str.charCodeAt(i - 1) + 1);
const descending = str.split('').every((char, i) => i === 0 || char.charCodeAt(0) === str.charCodeAt(i - 1) - 1);
return ascending || descending;
}
static getSequentialType(str) {
return str.charCodeAt(1) > str.charCodeAt(0) ? 'ascending' : 'descending';
}
static calculateOverallComplexity(content) {
const entropy = this.calculateShannonEntropy(content);
const patterns = this.findRepeatingPatterns(content);
const sequential = this.findSequentialPatterns(content);
let complexity = entropy / Math.log2(256); // Normalize to 0-1
complexity -= patterns.length / content.length; // Reduce for patterns
complexity -= sequential.length / content.length; // Reduce for sequences
return Math.max(0, Math.min(1, complexity));
}
static generateRecommendations(content, entropy, complexity) {
const recommendations = [];
if (entropy < 3) {
recommendations.push("Increase character variety to improve entropy");
}
if (complexity < 0.5) {
recommendations.push("Reduce predictable patterns");
}
if (content.length < 12) {
recommendations.push("Consider increasing length for better security");
}
if (!/[A-Z]/.test(content)) {
recommendations.push("Add uppercase letters");
}
if (!/[a-z]/.test(content)) {
recommendations.push("Add lowercase letters");
}
if (!/\d/.test(content)) {
recommendations.push("Add numbers");
}
if (!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(content)) {
recommendations.push("Add special characters");
}
return recommendations;
}
}
EntropyAnalyzer.KEYBOARD_PATTERNS = {
qwerty: [
'qwertyuiop', 'asdfghjkl', 'zxcvbnm',
'qwerty', 'asdf', 'zxcv', '123456789', '1234567890'
],
dvorak: [
'pyfgcrl', 'aoeuidhtns', 'qjkxbmwvz'
]
};
EntropyAnalyzer.COMMON_WORDS = [
'password', 'admin', 'user', 'login', 'secret', 'test', 'demo',
'welcome', 'hello', 'world', 'company', 'system', 'access'
];
export { EntropyAnalyzer };
//# sourceMappingURL=entropy-analyzer.js.map