public static List <Solution> HackApproximation(byte[][] plains, byte[][] encs, Layer bestLayerApproximation, byte[] expectedKey) { int iterationsCount = plains.Length; Console.WriteLine($"\nBEST OPTION: round0sboxNum {bestLayerApproximation.round0sboxNum}\tround0x {bestLayerApproximation.round0x}\tround0y {bestLayerApproximation.round0y}\tbias {bestLayerApproximation.inputProbability.Bias()}\toutSBoxes {string.Join(",", bestLayerApproximation.ActivatedSboxesNums)}\tLastRoundInputBits {SubstitutionPermutationNetwork.GetBitString(bestLayerApproximation.inputBits)}"); var targetPartialSubkeys = GenerateTargetPartialSubkeys(bestLayerApproximation.ActivatedSboxesNums) .Select(targetPartialSubkey => (targetPartialSubkey, SubstitutionPermutationNetwork.GetBytesBigEndian(targetPartialSubkey))) .ToList(); var keyProbabilities = targetPartialSubkeys .ToDictionary(u => u.Item1, u => 0); var hackingSubstitutionPermutationNetwork = new SubstitutionPermutationNetwork(SubstitutionPermutationNetwork.GenerateRandomKey()); for (int i = 0; i < plains.Length; i++) { if (i > 0 && i % (plains.Length / 4) == 0) { Console.WriteLine($" done {i} iterations of {iterationsCount}"); } var plain = plains[i]; var enc = encs[i]; HackIteration(plain, enc, bestLayerApproximation.round0sboxNum, bestLayerApproximation.round0x, bestLayerApproximation.inputBits, targetPartialSubkeys, hackingSubstitutionPermutationNetwork, keyProbabilities); } return(GetSolutions(bestLayerApproximation, keyProbabilities, expectedKey, iterationsCount)); }
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); }
public static int ProcessGet(string host, string id, string flag) { var state = JsonHelper.ParseJson <State>(id.ToStringFromBase64()); var imageId = state.FileId; var spn = new SubstitutionPermutationNetwork(Convert.FromBase64String(state.MasterKeyHex)); try { var tcpClient = ConnectToService(host, GET_PORT); using (var stream = tcpClient.GetStream()) { stream.WriteBigEndian(imageId); byte[] encryptedData = null; byte[] imageData; try { encryptedData = stream.ReadLengthFieldAware(); imageData = spn.DecryptWithPadding(encryptedData); } catch (Exception e) { throw new ServiceException(ExitCode.CORRUPT, $"Can't receive or decrypt image of '{encryptedData?.Length}' bytes", innerException: e); } string receivedImageMd5Hex; try { receivedImageMd5Hex = CalcImageBytesHash(imageData); } catch (Exception e) { throw new ServiceException(ExitCode.MUMBLE, "Failed to parse image from service response", innerException: e); } if (receivedImageMd5Hex != state.SourceImageHash) { throw new ServiceException(ExitCode.CORRUPT, $"Source image md5 {state.SourceImageHash} != received {receivedImageMd5Hex}"); } return((int)ExitCode.OK); } } catch (ServiceException) { throw; } catch (Exception e) { throw new ServiceException(ExitCode.DOWN, string.Format("General failure"), innerException: e); } }
private static List <(byte[], byte[])> GeneratePlainEncryptedPairs(byte[] imageBytes) { var result = new List <(byte[], byte[])>(); var prefixWithEncryptedPixels = imageBytes.Skip(SubstitutionPermutationNetwork.GenerateRandomIV().Length + 0x38 - SubstitutionPermutationNetwork.BlockSizeBytes).ToList(); for (int i = SubstitutionPermutationNetwork.BlockSizeBytes; i < prefixWithEncryptedPixels.Count - SubstitutionPermutationNetwork.BlockSizeBytes; i += SubstitutionPermutationNetwork.BlockSizeBytes) { var prevC = prefixWithEncryptedPixels.Skip(i - SubstitutionPermutationNetwork.BlockSizeBytes).Take(SubstitutionPermutationNetwork.BlockSizeBytes).ToArray(); var c = prefixWithEncryptedPixels.Skip(i).Take(SubstitutionPermutationNetwork.BlockSizeBytes).ToArray(); var expectedP = new byte[] { 0, 0xFF, 0, 0, 0, 0xFF, 0, 0 }; var input = SubstitutionPermutationNetwork.XorBlock(prevC, expectedP); result.Add((input, c)); } return(result); }
public static void Do() { Console.WriteLine($"SPN: rounds {SubstitutionPermutationNetwork.RoundsCount}, blocksize {SubstitutionPermutationNetwork.BlockSizeBytes * 8 } bits"); var expectedKey = SubstitutionPermutationNetwork.GenerateRandomKey(); Console.WriteLine($"key: {expectedKey.ToHexUpperCase()}"); var spn = new SubstitutionPermutationNetwork(expectedKey); var plainTextString = new string('X', SubstitutionPermutationNetwork.BlockSizeBytes); var plainText = Encoding.ASCII.GetBytes(plainTextString); var encryptedBytes = spn.EncryptBlock(plainText); var decryptedBytes = spn.DecryptBlock(encryptedBytes); var decryptedString = Encoding.ASCII.GetString(decryptedBytes); Console.WriteLine($"{plainTextString} -> {encryptedBytes.ToHexUpperCase()} -> {decryptedString}"); HackCipher(spn, expectedKey, 6000); }
private static byte[] GetFinalSolution(Dictionary <int, List <byte> > solutionsDict, byte[] ciphertextBlocks, byte[] expectedPlaintextPrefixFrom4) { var key = new byte[SubstitutionPermutationNetwork.KeySizeBytes]; byte b = 0; var keyLengthInHex = SubstitutionPermutationNetwork.KeySizeBytes * 8 / SBox.BitSize; for (int hexNumPos = 0; hexNumPos < keyLengthInHex; hexNumPos++) { byte hexNum = 0; if (solutionsDict.ContainsKey(hexNumPos)) { hexNum = solutionsDict[hexNumPos].First(); //TODO this position definitely needs to be bruted } b |= (byte)(hexNum << (hexNumPos % 2 == 0 ? 4 : 0)); if (hexNumPos % 2 == 1) { key[hexNumPos / 2] = b; b = 0; } } var spn = new SubstitutionPermutationNetwork(key); for (int d1pos = 0; d1pos < keyLengthInHex; d1pos++) { for (int d2pos = d1pos + 1; d2pos < keyLengthInHex; d2pos++) { for (int d3pos = d2pos + 1; d3pos < keyLengthInHex; d3pos++) { var d1prev = GetHex(key, d1pos); //TODO itarate solutionsDict, not full brute! for (byte d1v = 0; d1v < 16; d1v++) { SetHex(key, d1pos, d1v); var d2prev = GetHex(key, d2pos); for (byte d2v = 0; d2v < 16; d2v++) { SetHex(key, d2pos, d2v); byte d3prev = GetHex(key, d3pos); for (byte d3v = 0; d3v < 16; d3v++) { SetHex(key, d3pos, d3v); spn.MasterKey = key; var plaintextBlocks = spn.DecryptCBC(ciphertextBlocks); if (StartsWith(plaintextBlocks, 4, expectedPlaintextPrefixFrom4)) { return(key); } } SetHex(key, d3pos, d3prev); } SetHex(key, d2pos, d2prev); } SetHex(key, d1pos, d1prev); } } } return(null); }
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"); } }
public static int ProcessPut(string host, string id, string flag) { try { var tcpClient = ConnectToService(host, PUT_PORT); using (var stream = tcpClient.GetStream()) { var xA = DH.GenerateRandomXA(DH_x_bitsCount); var yA = DH.CalculateYA(xA); stream.WriteBigEndian(yA); var yB = stream.ReadBigIntBigEndian(NetworkStreamExtensions.DH_y_bytesCount); var keyMaterial = DH.DeriveKey(yB, xA).ToByteArray(isBigEndian: true, isUnsigned: true); var masterKey = SubstitutionPermutationNetwork.CalcMasterKey(keyMaterial); var flagPicture = FlagsPainter.DrawFlag(flag); var spn = new SubstitutionPermutationNetwork(masterKey); var encryptedData = spn.EncryptWithPadding(flagPicture, SubstitutionPermutationNetwork.GenerateRandomIV()); stream.WriteLengthFieldAware(encryptedData); var imageId = stream.ReadIntBigEndian(); Console.Error.WriteLine($"Got image id {imageId}"); string imageHash; try { imageHash = CalcImageBytesHash(flagPicture); } catch (Exception e) { throw new ServiceException(ExitCode.CHECKER_ERROR, "Failed to calc hash of generated image", innerException: e); } var state = new State { FileId = imageId, MasterKeyHex = Convert.ToBase64String(masterKey), SourceImageHash = imageHash }; var lastImageId = FindLastId(host); SaveLastFileId(host, imageId); if (lastImageId != null) { if (Math.Abs(lastImageId.Value - imageId) > MaxConsecutiveFileIdsDiff) { throw new ServiceException(ExitCode.MUMBLE, $"LastImageId {lastImageId}, got new imageId {imageId}, difference is more than threshold {MaxConsecutiveFileIdsDiff}. Possibly service was 'patched' to make ids non-predictable. It's not fairplay, so punishing service's SLA", "Unexpected image id"); } } Console.WriteLine(state.ToJsonString().ToBase64String()); return((int)ExitCode.OK); } } catch (ServiceException) { throw; } catch (Exception e) { throw new ServiceException(ExitCode.DOWN, string.Format("General failure"), innerException: e); } }