예제 #1
0
        public bool Decrypt(string FilePath, byte[] Key, int Rounds, Mode Mode, EncryptionMode EncrMode)
        {
            var fm = new FileManagement();
            SerpentAlgorithm sa;

            switch (Mode)
            {
            case Mode.Standard:
                sa = new SerpentStandardMode();
                break;

            case Mode.BitSlice:
                sa = new SerpentBitSliceMode();
                break;

            default:
                MessageBox.Show("Selected algorithm type is not implemented. ", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return(false);
            }

            var       position     = 0;
            var       destFilePath = string.Empty;
            var       fi           = new FileInfo(FilePath);
            const int fragmentSize = 1024 * 1024; // 1 MB (musi dać się wyciągnąć pierwiastek czwartego stopnia)
            Encoding  enc          = new UTF8Encoding();

            sa.Rounds    = Rounds;
            sa.BlockSize = BlockSize;
            var tempFilePath = FilePath + ".temp";

            var iv = fm.GetFileFragment(FilePath, 0, BlockSize, out var errorCodeIv);
            var plainControlSum            = fm.GetFileFragment(FilePath, BlockSize, BlockSize, out var errorCode);
            var roundBytesFromPtControlSum = Array.Empty <byte>();
            var previousBlock = Array.Empty <byte>();

            if (errorCodeIv == ErrorCode.GetFileFailed || errorCode == ErrorCode.GetFileFailed)
            {
                MessageBox.Show("File couldn't be loaded.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return(false);
            }

            var listRoundsBytesFromPtControlSum = new List <byte>();

            for (var i = 0; i < BlockSize; i++)
            {
                if (plainControlSum[i] != 3)
                {
                    listRoundsBytesFromPtControlSum.Add(plainControlSum[i]);
                }
                else
                {
                    roundBytesFromPtControlSum = listRoundsBytesFromPtControlSum.ToArray();
                    break;
                }
            }

            var areRoundsFromPtControlSumParsable = int.TryParse(enc.GetString(roundBytesFromPtControlSum), out var readRoundsFromPtControlSum);

            if (!areRoundsFromPtControlSumParsable || readRoundsFromPtControlSum > 64)
            {
                MessageBox.Show("File isn't encrypted or it was encrypted with different algorithm.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return(false);
            }

            if (readRoundsFromPtControlSum != Rounds)
            {
                if (Mode != Mode.Standard)
                {
                    var result = MessageBox.Show(string.Format("File was encrypted with different number of rounds ({0}) of Serpent algorithm than the one specified ({1}) and in algorithm type different than `Standard` it is impossible to decrypt by using this number of rounds. Do you want to change alogorithm type to 'Standard' and number of rounds to {0}? (WARNING: Decryption may take a long time for big files). ", readRoundsFromPtControlSum, Rounds), "Warning", MessageBoxButton.YesNo, MessageBoxImage.Warning);
                    return(result == MessageBoxResult.Yes && Decrypt(FilePath, Key, readRoundsFromPtControlSum, Mode.Standard, EncrMode));
                }
                else
                {
                    var result = MessageBox.Show(string.Format("It looks like the file was encrypted with different number of rounds ({0}) of Serpent algorithm than the one specified ({1}) or file is not encrypted at all. Do you want to change the number of rounds to {0}?", readRoundsFromPtControlSum, Rounds), "Warning", MessageBoxButton.YesNo, MessageBoxImage.Question);

                    if (result == MessageBoxResult.Yes)
                    {
                        Rounds    = readRoundsFromPtControlSum;
                        sa.Rounds = readRoundsFromPtControlSum;
                    }
                }
            }

            var expandedKey = sa.MakeKey(Key);

            fm.ShiftBytesFromFile(FilePath, tempFilePath, BlockSize * 2, out errorCode); // usuń z pliku dwa bloki - sumę kontrolną i initalization vector

            if (errorCode == ErrorCode.ShiftFileFailed)
            {
                MessageBox.Show("File couldn't be modified.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return(false);
            }

            do
            {
                var InputFileFragment = fm.GetFileFragment(tempFilePath, position, fragmentSize, out errorCode).ToList();

                if (errorCode == ErrorCode.GetFileFailed)
                {
                    MessageBox.Show("File couldn't be loaded'.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    return(false);
                }

                var OutputFileFragment = new List <byte>();

                // DESZYFROWANIE BLOKU

                for (var i = 0; i < InputFileFragment.Count; i += BlockSize)
                {
                    switch (EncrMode)
                    {
                    case EncryptionMode.ECB:
                        OutputFileFragment.AddRange(sa.BlockDecrypt(InputFileFragment.GetRange(i, BlockSize).ToArray(), 0, expandedKey));
                        break;

                    case EncryptionMode.CBC:
                    {
                        if (position == 0 && i == 0)
                        {
                            previousBlock = iv;
                        }
                        var cipherText = InputFileFragment.GetRange(i, BlockSize).ToArray();
                        var currBlock  = sa.BlockDecrypt(cipherText, 0, expandedKey);
                        var plainText  = currBlock.XOR(previousBlock);
                        OutputFileFragment.AddRange(plainText);
                        previousBlock = cipherText;
                        break;
                    }

                    default:
                        MessageBox.Show("Selected ciphering type is not implemented. ", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                        return(false);
                    }
                }

                // ===================

                if (position == 0)                                               // jeśli odszyfrowałem pierwszy fragment pliku, przed zapisaniem usuwam z tablicy bajty dodane przy szyfrowaniu
                {
                    int shiftedbytes        = OutputFileFragment[BlockSize * 2]; // zawartość 32 bajtu, 0 - 15 deszyfrowana suma kontrolna, 16-31 rozszerzenie i ilość rund
                    var decryptedControlSum = new byte[BlockSize];
                    var extBytes            = new byte[1];
                    var roundBytes          = new byte[1];
                    var i = 0;

                    for (; i < BlockSize; i++) // zczytaj sumę kontrolną
                    {
                        decryptedControlSum[i] = OutputFileFragment[i];
                    }

                    var listExtbytes = new List <byte>();

                    for (; i < BlockSize * 2; i++) // zczytaj rozszerzenie
                    {
                        if (OutputFileFragment[i] != 3)
                        {
                            listExtbytes.Add(OutputFileFragment[i]);
                        }
                        else
                        {
                            extBytes = listExtbytes.ToArray();
                            break;
                        }
                    }

                    i++;
                    var listRoundsBytes = new List <byte>();

                    for (; i < BlockSize * 2; i++)  // zczytaj zaszyfrowaną ilość rund
                    {
                        if (OutputFileFragment[i] != 3)
                        {
                            listRoundsBytes.Add(OutputFileFragment[i]);
                        }
                        else
                        {
                            roundBytes = listRoundsBytes.ToArray();
                            break;
                        }
                    }

                    var outputExtension = enc.GetString(extBytes);
                    destFilePath = Path.ChangeExtension(FilePath, outputExtension);
                    var areRoundsParsable = int.TryParse(enc.GetString(roundBytes), out var readRounds);

                    if (!plainControlSum.SequenceEqual(decryptedControlSum) || !areRoundsParsable || shiftedbytes > 16 || readRounds != Rounds)
                    {
                        fm.DeleteTempFile(tempFilePath, out errorCode);
                        if (errorCode == ErrorCode.DeletingTempFileFailed)
                        {
                            MessageBox.Show("Temporary file couldn't be deleted", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
                        }

                        MessageBox.Show("Key is invalid.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);

                        return(false);
                    }

                    var shiftedBytesAndInfoBytes = shiftedbytes + BlockSize * 2;

                    for (; shiftedBytesAndInfoBytes > 0; shiftedBytesAndInfoBytes--)
                    {
                        OutputFileFragment.RemoveAt(0);
                    }
                }

                fm.SaveFileFragment(destFilePath, position, OutputFileFragment.ToArray(), out errorCode); // zapisuję kolejną część pliku do pliku docelowego

                if (errorCode == ErrorCode.SaveFileFailed)                                                // w razie błędu szyfrowanie nie powiodło się
                {
                    MessageBox.Show("FIle couldn't be saved. ", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    return(false);
                }

                position += fragmentSize;                                                                                                                            // ustaw pozycję kolejnego fragmentu
                var encryptionProgressChangedEventData = new EncryptionProgressChangedEventArgs((int)((double)position / fi.Length * 100.0), ActionType.Decryption); // inicjalizuję dane dla event handlera (obliczony postęp, typ - szyfrowanie czy deszyfrowanie)
                OnEncryptionProgressChanging(encryptionProgressChangedEventData);                                                                                    // wywołuję zdarzenie z utworzonymi wcześniej parametrami
            }while (position <= fi.Length);                                                                                                                          // pętlę powtarzam dopóki nie skończy się plik

            fm.DeleteTempFile(tempFilePath, out errorCode);                                                                                                          // usuń plik tymczasowy

            if (errorCode == ErrorCode.DeletingTempFileFailed)
            {
                MessageBox.Show("Temporary file couldn't be deleted.", "Ostrzeżenie", MessageBoxButton.OK, MessageBoxImage.Warning);
            }

            return(true);
        }
예제 #2
0
        public bool Encrypt(string FilePath, byte[] Key, int Rounds, Mode Mode, EncryptionMode EncrMode)
        {
            var fm = new FileManagement();
            SerpentAlgorithm sa;
            var saltBytes = new byte[BlockSize];

            rng.GetNonZeroBytes(saltBytes);
            var iv = new byte[BlockSize];

            rng.GetBytes(iv);

            switch (Mode)
            {
            case Mode.Standard:
                sa = new SerpentStandardMode();
                break;

            case Mode.BitSlice:
                sa = new SerpentBitSliceMode();
                break;

            default:
                MessageBox.Show("Selected algorithm type is not implemented. ", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return(false);
            }

            var      position      = 0;
            var      destFilePath  = Path.ChangeExtension(FilePath, ".serpent");
            var      fi            = new FileInfo(FilePath);
            var      fragmentSize  = 1024 * 1024; // 1 MB (musi dać się wyciągnąć pierwiastek czwartego stopnia)
            var      tempFilePath  = FilePath + ".temp";
            var      tempFilePath2 = FilePath + ".temp2";
            Encoding enc           = new UTF8Encoding();

            sa.Rounds    = Rounds;
            sa.BlockSize = BlockSize;
            var previousBlock = Array.Empty <byte>();

            var roundsBytes = enc.GetBytes(Rounds.ToString());

            for (var i = 0; i < roundsBytes.Length; i++)
            {
                saltBytes[i] = roundsBytes[i];

                if (i >= roundsBytes.Length - 1)
                {
                    saltBytes[i + 1] = 3;
                }
            }

            var expandedKey = sa.MakeKey(Key);

            var leadingBytes = new byte[BlockSize - fi.Length % BlockSize];

            rng.GetBytes(leadingBytes);
            leadingBytes[0] = (byte)leadingBytes.Length;

            fm.UnshiftBytesToFile(FilePath, tempFilePath, leadingBytes, out var errorCode); // po czym dodaję go do pliku tymczasowego

            if (errorCode == ErrorCode.ExpandFileFailed)
            {
                MessageBox.Show("File couldn't be modified.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return(false);
            }

            do
            {
                if (position == 0) // dodaj do pliku informację o rozszerzeniu, ilości rund i sumę kontrolną
                {
                    var infoBytes = new List <byte>();

                    infoBytes.AddRange(saltBytes);

                    var extension = Path.GetExtension(FilePath);
                    extension = extension.Replace(".", "");
                    infoBytes.AddRange(enc.GetBytes(extension));
                    infoBytes.Add(3); // EOT byte
                    infoBytes.AddRange(enc.GetBytes(Rounds.ToString()));
                    infoBytes.Add(3);

                    if (BlockSize < infoBytes.Count - saltBytes.Length)
                    {
                        MessageBox.Show("FIle extension is too long.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                        return(false);
                    }

                    var rndBytes = new byte[BlockSize - (infoBytes.Count - saltBytes.Length)];
                    rng.GetNonZeroBytes(rndBytes);
                    infoBytes.AddRange(rndBytes);

                    fm.UnshiftBytesToFile(tempFilePath, tempFilePath2, infoBytes.ToArray(), out errorCode);

                    if (errorCode == ErrorCode.ExpandFileFailed)
                    {
                        MessageBox.Show("File couldn't be modified.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                        return(false);
                    }

                    fm.DeleteTempFile(tempFilePath, out errorCode);

                    if (errorCode == ErrorCode.DeletingTempFileFailed) // w razie błędu szyfrowanie nie powiodło się
                    {
                        MessageBox.Show("Temporary file couldn't be deleted.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
                        return(false);
                    }

                    File.Move(tempFilePath2, tempFilePath);
                }

                var InputFileFragment = fm.GetFileFragment(tempFilePath, position, fragmentSize, out errorCode).ToList();

                if (errorCode == ErrorCode.GetFileFailed)
                {
                    MessageBox.Show("File couldn't be loaded.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    return(false);
                }

                var OutputFileFragment = new List <byte>();

                // SZYFROWANIE BLOKU

                for (var i = 0; i < InputFileFragment.Count; i += BlockSize)
                {
                    if (EncrMode == EncryptionMode.ECB)
                    {
                        OutputFileFragment.AddRange(sa.BlockEncrypt(InputFileFragment.GetRange(i, BlockSize).ToArray(), 0, expandedKey));
                    }
                    else if (EncrMode == EncryptionMode.CBC)
                    {
                        if (position == 0 && i == 0) // inicjalizuję iv tylko raz
                        {
                            previousBlock = iv;
                        }

                        var plainText  = InputFileFragment.GetRange(i, BlockSize).ToArray();
                        var currBlock  = plainText.XOR(previousBlock); // do plaintextu xorujemy poprzedni zaszyfrowany blok
                        var cipherText = sa.BlockEncrypt(currBlock, 0, expandedKey);
                        OutputFileFragment.AddRange(cipherText);
                        previousBlock = cipherText;
                    }
                    else
                    {
                        MessageBox.Show("Selected ciphering type is not implemented. ", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                        return(false);
                    }
                }

                // =================

                fm.SaveFileFragment(destFilePath, position, OutputFileFragment.ToArray(), out errorCode); // zapisuję kolejną część pliku do pliku docelowego

                if (errorCode == ErrorCode.SaveFileFailed)                                                // w razie błędu szyfrowanie nie powiodło się
                {
                    MessageBox.Show("File couldn't be saved. ", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    return(false);
                }

                position += fragmentSize;                                                                                                                              // ustaw pozycję kolejnego fragmentu
                var encryptionProgressChangedEventData = new EncryptionProgressChangedEventArgs(((int)((double)position / fi.Length * 100.0)), ActionType.Encryption); // inicjalizuję dane dla event handlera (obliczony postęp, typ - szyfrowanie czy deszyfrowanie)
                OnEncryptionProgressChanging(encryptionProgressChangedEventData);                                                                                      // wywołuję zdarzenie z utworzonymi wcześniej parametrami
            }while (position <= fi.Length);                                                                                                                            // pętlę powtarzam dopóki nie skończy się plik

            fm.DeleteTempFile(tempFilePath, out errorCode);                                                                                                            // usuń plik tymczasowy

            if (errorCode == ErrorCode.DeletingTempFileFailed)                                                                                                         // w razie błędu szyfrowanie nie powiodło się
            {
                MessageBox.Show("Temporary file couldn't be deleted.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return(false);
            }

            var ivAndSalt = new byte[iv.Length + saltBytes.Length];

            iv.CopyTo(ivAndSalt, 0);
            saltBytes.CopyTo(ivAndSalt, iv.Length);

            fm.UnshiftBytesToFile(destFilePath, tempFilePath, ivAndSalt, out errorCode); // suma kontrolna

            if (errorCode == ErrorCode.ExpandFileFailed)
            {
                MessageBox.Show("File couldn't be modified.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return(false);
            }

            fm.DeleteTempFile(destFilePath, out errorCode);    // usuń plik tymczasowy

            if (errorCode == ErrorCode.DeletingTempFileFailed) // w razie błędu szyfrowanie nie powiodło się
            {
                MessageBox.Show("Temporary file couldn't be deleted.", "Ostrzeżenie", MessageBoxButton.OK, MessageBoxImage.Warning);
            }

            File.Move(tempFilePath, destFilePath);

            return(true);
        }