示例#1
0
        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));
        }
示例#2
0
        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);
        }
示例#3
0
        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);
            }
        }
示例#4
0
        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);
        }
示例#5
0
        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);
        }
示例#6
0
        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);
        }
示例#7
0
        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");
            }
        }
示例#8
0
        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);
            }
        }