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.

309 lines (306 loc) 10.8 kB
'use strict'; /** * Advanced Entropy Analyzer Module * Provides optimized entropy analysis for SecureString */ /** * Advanced entropy analyzer for strings */ class EntropyAnalyzer { /** * Performs comprehensive entropy analysis */ static analyzeEntropy(content) { const charFreq = this.getCharacterFrequencies(content); const shannonEntropy = this.calculateShannonEntropy(content, charFreq); const minEntropy = this.calculateMinEntropy(content, charFreq); const maxEntropy = Math.log2(Object.keys(charFreq).length); const diversityScore = this.calculateDiversityScore(content, charFreq); const characterDistribution = this.getCharacterDistribution(content, charFreq); 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(shannonEntropy, patternComplexity, predictability); const recommendations = this.generateRecommendations(content, shannonEntropy, patternComplexity); return { shannonEntropy, minEntropy, maxEntropy, diversityScore, 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, freq) { let entropy = 0; const length = content.length; for (const count of Object.values(freq)) { const prob = count / length; entropy -= prob * Math.log2(prob); } return entropy; } /** * Calculates min-entropy */ static calculateMinEntropy(content, freq) { const maxFreq = Math.max(...Object.values(freq)); return -Math.log2(maxFreq / content.length); } /** * Calculates n-gram entropy */ static calculateNGramEntropy(content, n) { if (content.length < n) return 0; const ngrams = {}; const total = content.length - n + 1; for (let i = 0; i < total; i++) { const ngram = content.slice(i, i + n); ngrams[ngram] = (ngrams[ngram] || 0) + 1; } let entropy = 0; for (const count of Object.values(ngrams)) { const prob = count / total; entropy -= prob * Math.log2(prob); } return entropy; } /** * Calculates diversity score based on character variety */ static calculateDiversityScore(content, freq) { const uniqueChars = Object.keys(freq).length; const charsetSize = Math.min(95, uniqueChars); // ASCII printable chars return charsetSize / 95; } /** * Calculates pattern complexity */ static calculatePatternComplexity(content) { let complexity = 0; const uniqueChars = new Set(content).size; complexity += uniqueChars / content.length; const charTypes = [ /[A-Z]/.test(content), /[a-z]/.test(content), /\d/.test(content), /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(content), ]; complexity += charTypes.filter(Boolean).length / 4; const patterns = this.findRepeatingPatterns(content); complexity -= patterns.length / Math.max(1, content.length / 4); return Math.max(0, Math.min(1, complexity)); } /** * Calculates predictability score */ static calculatePredictability(content) { let predictability = 0; let sequential = 0, repeated = 0; for (let i = 1; i < content.length; i++) { if (Math.abs(content.charCodeAt(i) - content.charCodeAt(i - 1)) === 1) sequential++; if (content[i] === content[i - 1]) repeated++; } predictability += (sequential + repeated) / (content.length - 1); return Math.min(1, predictability); } /** * Calculates overall randomness score */ static calculateRandomnessScore(entropy, complexity, predictability) { const normalizedEntropy = entropy / Math.log2(256); return (normalizedEntropy + complexity + (1 - predictability)) / 3; } /** * Finds repeating patterns */ static findRepeatingPatterns(content) { const patterns = {}; const maxLen = Math.min(content.length >> 1, 8); for (let len = 2; len <= maxLen; len++) { for (let i = 0; i <= content.length - len; i++) { const pattern = content.slice(i, i + len); patterns[pattern] = patterns[pattern] || { count: 0, positions: [], }; patterns[pattern].count++; patterns[pattern].positions.push(i); } } return Object.entries(patterns) .filter(([, { count }]) => count > 1) .map(([pattern, data]) => ({ pattern, ...data })) .sort((a, b) => b.count - a.count) .slice(0, 5); } /** * Finds sequential patterns */ static findSequentialPatterns(content) { const patterns = []; const maxLen = Math.min(content.length, 6); for (let len = 3; len <= maxLen; len++) { for (let i = 0; i <= content.length - len; i++) { const substr = content.slice(i, i + len); const codes = substr.split("").map((c) => c.charCodeAt(0)); const isAsc = codes.every((c, j) => j === 0 || c === codes[j - 1] + 1); const isDesc = codes.every((c, j) => j === 0 || c === codes[j - 1] - 1); if (isAsc) patterns.push({ pattern: substr, type: "ascending" }); else if (isDesc) patterns.push({ pattern: substr, type: "descending" }); } } return patterns.slice(0, 5); } /** * Finds keyboard patterns */ static findKeyboardPatterns(content) { const patterns = []; const lower = content.toLowerCase(); for (const [layout, layoutPatterns] of Object.entries(this.KEYBOARD_PATTERNS)) { for (const pattern of layoutPatterns) { if (lower.includes(pattern)) { patterns.push({ pattern, layout }); } } } return patterns.slice(0, 5); } /** * Finds dictionary words */ static findDictionaryWords(content) { const words = []; const lower = content.toLowerCase(); for (const word of this.COMMON_WORDS) { let pos = lower.indexOf(word); while (pos !== -1) { words.push({ word, position: pos, confidence: word.length / content.length, }); pos = lower.indexOf(word, pos + 1); } } return words.sort((a, b) => b.confidence - a.confidence).slice(0, 5); } /** * Finds common substitutions */ static findCommonSubstitutions(content) { return Object.entries(this.SUBSTITUTIONS) .filter(([, substituted]) => content.includes(substituted)) .map(([substituted, original]) => ({ original, substituted })); } /** * Helper methods */ static getCharacterFrequencies(content) { const freq = {}; for (const char of content) { freq[char] = (freq[char] || 0) + 1; } return freq; } static getCharacterDistribution(content, freq) { const dist = {}; const len = content.length; for (const [char, count] of Object.entries(freq)) { dist[char] = count / len; } return dist; } static generateRecommendations(content, entropy, complexity) { const rec = []; if (entropy < 3) rec.push("Increase character variety to improve entropy"); if (complexity < 0.5) rec.push("Reduce predictable patterns"); if (content.length < 12) rec.push("Consider increasing length for better security"); if (!/[A-Z]/.test(content)) rec.push("Add uppercase letters"); if (!/[a-z]/.test(content)) rec.push("Add lowercase letters"); if (!/\d/.test(content)) rec.push("Add numbers"); if (!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(content)) rec.push("Add special characters"); return rec; } static calculateOverallComplexity(content) { const entropy = this.calculateShannonEntropy(content, this.getCharacterFrequencies(content)); const patterns = this.findRepeatingPatterns(content); const sequences = this.findSequentialPatterns(content); let complexity = entropy / Math.log2(256); complexity -= (patterns.length + sequences.length) / Math.max(1, content.length / 4); return Math.max(0, Math.min(1, complexity)); } } EntropyAnalyzer.KEYBOARD_PATTERNS = { qwerty: ["qwerty", "asdf", "zxcv", "1234", "qwer", "asdfg", "zxcvb"], dvorak: ["pyfg", "aoeu", "qjkx"], }; EntropyAnalyzer.COMMON_WORDS = [ "password", "admin", "user", "login", "secret", "test", "demo", "welcome", "hello", "world", "company", "system", "access", ]; EntropyAnalyzer.SUBSTITUTIONS = { "@": "a", "3": "e", "1": "i", "0": "o", $: "s", "7": "t", }; exports.EntropyAnalyzer = EntropyAnalyzer; //# sourceMappingURL=entropy-analyzer.js.map