private static void HackCipher(SubstitutionPermutationNetwork spn, byte[] expectedKey, int iterationsCount) { var linearCryptoanalysis = new LinearCryptoanalysis(spn); var bestLayerApproximations = linearCryptoanalysis.ChooseBestPathsStartingFromSingleSBoxInRound0(Exploit.maxSBoxesInLastRound, Exploit.maxSBoxesInRound, Exploit.thresholdBias).ToList(); Console.WriteLine($"Total approximations: {bestLayerApproximations.Count}"); var plains = Enumerable.Range(0, iterationsCount).Select(i => GenerateRandomPlainText()).ToArray(); var encs = plains.Select(plain => spn.EncryptBlock(plain)).ToArray(); var solutions = new List <Solution>(); foreach (var approximationsGroup in bestLayerApproximations .Where(layer => layer.round0sboxNum % 8 == 6 || (layer.round0sboxNum % 8 == 7 && ((layer.round0x & 0x01) == 0))) .GroupBy(layer => layer.ActivatedSboxesNums.Aggregate("", (s, num) => s + num)) .OrderBy(group => group.Key)) { foreach (var approximation in approximationsGroup.Distinct().OrderByDescending(layer => layer.inputProbability.Bias()).Take(3)) { solutions.AddRange(Exploit.HackApproximation(plains, encs, approximation, expectedKey)); } } Exploit.OrderSolutions(solutions, expectedKey); }
static void Main(string[] args) { // ProofOfConecpt.Do(); // return; if (args.Length < 1) { Console.WriteLine("Usage: sploit.exe <fileToDecrypt> [expectedKey]"); Environment.Exit(1); } var expectedKey = args.Length >= 2 ? File.ReadAllBytes(args[1]) : new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; byte[] imageBytes; try { imageBytes = File.ReadAllBytes(args[0]); } catch (Exception e) { Console.WriteLine($"Can't read data from file {args[0]}", e); Environment.Exit(1); return; } var spn = new SubstitutionPermutationNetwork(SubstitutionPermutationNetwork.GenerateRandomKey()); var pairs = GeneratePlainEncryptedPairs(imageBytes); var plains = pairs.Select(tuple => tuple.Item1).ToArray(); var encs = pairs.Select(tuple => tuple.Item2).ToArray(); var linearCryptoanalysis = new LinearCryptoanalysis(spn); var bestLayerApproximations = linearCryptoanalysis.ChooseBestPathsStartingFromSingleSBoxInRound0(Exploit.maxSBoxesInLastRound, Exploit.maxSBoxesInRound, Exploit.thresholdBias).ToList(); Console.WriteLine($"Total approximations: {bestLayerApproximations.Count}"); var solutions = new List <Solution>(); foreach (var approximationsGroup in bestLayerApproximations .Where(layer => layer.round0sboxNum % 8 == 3 || (layer.round0sboxNum % 8 == 4 && ((layer.round0x & 0x01) == 0))) .GroupBy(layer => layer.ActivatedSboxesNums.Aggregate("", (s, num) => s + num)) .OrderBy(group => group.Key)) { foreach (var approximation in approximationsGroup.Distinct().OrderByDescending(layer => layer.inputProbability.Bias()).Take(6)) { solutions.AddRange(Exploit.HackApproximation(plains, encs, approximation, expectedKey)); } } var solutionsDict = Exploit.OrderSolutions(solutions, expectedKey); var imageLength = imageBytes.Length - SubstitutionPermutationNetwork.GenerateRandomIV().Length; if (imageLength >= 65536) { throw new Exception("Unexpected image ciphertext length"); } Console.WriteLine("\nBruting left bits.."); var plaintextPrefixFrom4 = new byte[] { 0, 0, 0, 0, 0, 0, 0x36, 0, 0, 0 }; var hackedKey = GetFinalSolution(solutionsDict, imageBytes.Take(24).ToArray(), plaintextPrefixFrom4); if (hackedKey != null) { Console.WriteLine($"\nHACKED KEY: {hackedKey.ToHexUpperCase()}"); } else { Console.WriteLine("BAD LUCK. Key not hacked"); } }