public static void GenerateStatistics() { // INITIALIZE var statistics = new Statistics() { GlobalFrequencies = new Dictionary <char, double>(), PositionFrequencies = new Dictionary <char, double> [CellPatternSize] }; for (var i = 0; i < CellPatternSize; i++) { statistics.PositionFrequencies[i] = new Dictionary <char, double>(); } // Load var maps = LoadMaps(); // Frequencies var totalDecodedLength = 0; var totalCoincidence = 0.0; foreach (var map in maps) { totalCoincidence += ComputeCoincidenceRate(map.DecodedData); totalDecodedLength += map.DecodedData.Length; for (var i = 0; i < map.DecodedData.Length; i++) { var currentLetter = map.DecodedData[i]; if (!statistics.GlobalFrequencies.ContainsKey(currentLetter)) { statistics.GlobalFrequencies[currentLetter] = 1; } else { statistics.GlobalFrequencies[currentLetter]++; } var patternIndex = i % CellPatternSize; var positionFrequencies = statistics.PositionFrequencies[patternIndex]; if (!positionFrequencies.ContainsKey(currentLetter)) { positionFrequencies[currentLetter] = 1; } else { positionFrequencies[currentLetter]++; } } } statistics.IndexOfCoincidence = totalCoincidence / maps.Count(); // Normalize foreach (var k in statistics.GlobalFrequencies.Keys.ToList()) { statistics.GlobalFrequencies[k] /= totalDecodedLength; } for (var i = 0; i < CellPatternSize; i++) { var positionFrequencies = statistics.PositionFrequencies[i]; foreach (var k in positionFrequencies.Keys.ToList()) { positionFrequencies[k] /= totalDecodedLength / CellPatternSize; } } SaveStatistics(statistics); // Check //var globalTotalFreq = statistics.GlobalFrequencies.Values.Aggregate(0.0, (acc, freq) => acc + freq); //var positionTotalFreq = statistics.PositionFrequencies.Sum(p => p.Values.Aggregate(0.0, (acc, freq) => acc + freq)); }
public static void SaveStatistics(Statistics statistics) { File.WriteAllText(StatisticsPath, JsonConvert.SerializeObject(statistics, Formatting.Indented)); }
private static double ComputeError(string decrypted, int blockOffset, int blockSize, Statistics statistics) { var frequencies = GetFrequencies(decrypted); return(GetPositionError(decrypted, blockOffset, blockSize, statistics)); }
public static double GetPositionError(string decrypted, int blockOffset, int blockSize, Statistics statistics) { var distance = 0.0; for (var i = 0; i < decrypted.Length; i++) { var absolutePosition = blockSize * i + blockOffset; var positionStatistics = statistics.PositionFrequencies[absolutePosition % CellPatternSize]; var currentData = decrypted[i]; if (positionStatistics.ContainsKey(currentData)) { distance += (1 - positionStatistics[currentData]); } else { distance += 10; } } return(distance); }
private static ComputedKey GuessKey(string message, int keyLength, Statistics statistics) { var alternatives = new Dictionary <int, List <(int, double)> >(); var blockSize = keyLength; var numberOfBlock = (int)Math.Ceiling(message.Length / (double)blockSize); var offsetOverflow = message.Length % blockSize; var key = new StringBuilder(); for (var blockOffset = 0; blockOffset < blockSize; blockOffset++) { alternatives.Add(blockOffset, new List <(int, double)>()); var bestError = double.MaxValue; var bestXor = -1; // Only between thoses for (var xorKey = MinKeyXor; xorKey <= MaxKeyXor; xorKey++) { var numberOfBlockAffected = offsetOverflow > 0 ? blockOffset > offsetOverflow ? numberOfBlock - 1 : numberOfBlock : numberOfBlock; var decryptedBlock = new char[numberOfBlockAffected]; for (var blockNumber = 0; blockNumber < numberOfBlock; blockNumber++) { var absoluteOffset = blockNumber * blockSize + blockOffset; if (absoluteOffset < message.Length) { var currentData = message[absoluteOffset]; decryptedBlock[blockNumber] = (char)(currentData ^ xorKey); } } var decrypted = HttpUtility.UrlDecode(new string(decryptedBlock)); var error = ComputeError(decrypted, blockOffset, blockSize, statistics); if (error <= bestError) { if (error == bestError) { if (bestXor != -1) { alternatives[blockOffset].Add((xorKey, error)); } } else { var clampedValue = error * ErrorClamp; alternatives[blockOffset].RemoveAll(x => x.Item2 > clampedValue); alternatives[blockOffset].Add((xorKey, error)); } bestError = error; bestXor = xorKey; } } key.Append((char)bestXor); } // Shift back the key with its checksum var computedKey = key.ToString(); int shift = int.Parse(Checksum(computedKey), NumberStyles.HexNumber) * 2; var finalKey = RightRotateShift(computedKey, shift); return(new ComputedKey { Value = finalKey, Alternatives = alternatives.Where(x => x.Value.Count > 1).ToDictionary(x => x.Key, x => x.Value) }); }