V
V
vladimirchelyabinskiy2016-04-22 11:27:39
C++ / C#
vladimirchelyabinskiy, 2016-04-22 11:27:39

C# How to encrypt a file with RC6 algorithm?

There is the following code:
Which correctly encrypts the file, but when decrypting, garbage is added to the end of the file.
If there is 1 line in the file like: 123123123 the whole line will be garbage
. If several lines are
123
321
123141124234
23432523
234123421
Then the last 8 or 11 characters are overwritten with garbage.
What is the problem?

class RC6Base
    {
        // Константы для операций свига
        public const int W = 32;
        public const int R = 16;

        // Переменные для работы с файлами
        public Byte[] fileData;
        public uint fileLength;

        // Список расшифрованных / рашифрованных данных
        public List<Byte> resultData = new List<Byte>();

        // Крипто-ключ
        public UInt32[] key = new UInt32[2 * R + 4];

        // Функция записи данных в файл
        public void WriteByteArrayToFile(Byte[] buffer, string fileName)
        {
            try
            {
                FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite);
                BinaryWriter bw = new BinaryWriter(fs);

                for (int i = 0; i < fileLength; i++)
                    bw.Write(buffer[i]);

                bw.Close();
                fs.Close();
            }
            catch (Exception ex)
            {
                // Опущено для реализации под различными типами проектов
            }
        }

        // Функция чтения данных из файла
        public Byte[] ReadByteArrayFromFile(string fileName)
        {
            Byte[] buffer = null;

            try
            {
                FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                BinaryReader br = new BinaryReader(fs);

                long numBytes = new FileInfo(fileName).Length;
                buffer = br.ReadBytes((int)numBytes);

                br.Close();
                fs.Close();
            }
            catch (Exception ex)
            {
                // Опущено для реализации под различными типами проектов
            }

            return buffer;
        }

        // Функция сдвига вправо
        public UInt32 RightShift(UInt32 z_value, int z_shift)
        {
            return ((z_value >> z_shift) | (z_value << (W - z_shift)));
        }

        // Функция сдвига влево
        public UInt32 LeftShift(UInt32 z_value, int z_shift)
        {
            return ((z_value << z_shift) | (z_value >> (W - z_shift)));
        }

        // Функция определения числа сдвигов
        public int OffsetAmount(int dwVar)
        {
            int nLgw = (int)(Math.Log((double)W) / Math.Log(2.0));

            dwVar = dwVar << (W - nLgw);
            dwVar = dwVar >> (W - nLgw);

            return dwVar;
        }

        // Функция генерации ключа
        public void KeyGen(UInt32 dwKey)
        {
            UInt32 P32 = 0xB7E15163;
            UInt32 Q32 = 0x9E3779B9;
            UInt32 i, A, B;
            UInt32 dwByteOne, dwByteTwo, dwByteThree, dwByteFour;

            dwByteOne = dwKey >> 24;
            dwByteTwo = dwKey >> 8;
            dwByteTwo = dwByteTwo & 0x0010;
            dwByteThree = dwKey << 8;
            dwByteThree = dwByteThree & 0x0100;
            dwByteFour = dwKey << 24;

            dwKey = dwByteOne | dwByteTwo | dwByteThree | dwByteFour;

            key[0] = P32;

            for (i = 1; i < 2 * R + 4; i++)
                key[i] = key[i - 1] + Q32;

            i = A = B = 0;

            int v = 3 * Math.Max(1, 2 * R + 4);

            for (int s = 1; s <= v; s++)
            {
                A = key[i] = LeftShift(key[i] + A + B, OffsetAmount(3));
                B = dwKey = LeftShift(dwKey + A + B, OffsetAmount((int)(A + B)));

                i = (i + 1) % (2 * R + 4);
            }
        }

        // Функция преобразования массива UInt32 к списку байт
        public void ConvertFromUInt32ToByteArray(UInt32[] array)
        {
            List<byte> results = new List<byte>();

            foreach (UInt32 value in array)
            {
                byte[] converted = BitConverter.GetBytes(value);
                results.AddRange(converted);
            }

            // Формирование списка зашифрованных / расшифрванных байт данных
            resultData.AddRange(results);
        }

        // Функия преобразования массива байт в массив UInt32 (подогнана под текущую задачу)
        public UInt32[] ConvertFromByteArrayToUIn32(byte[] array, int position)
        {
            List<UInt32> results = new List<UInt32>();
            // Размер блока конвертируемых данных. Читаем по 16 байт.
            int length = position + 16;

            for (int i = position; i < length; i += 4)
            {
                byte[] temp = new byte[4];

                for (int j = 0; j < 4; ++j)
                {
                    if (i + j < array.Length)
                        temp[j] = array[i + j];
                    else
                        temp[j] = 0x00;         // заполняем недостающие блоки в случае достижения
                    // конца файла
                }

                results.Add(BitConverter.ToUInt32(temp, 0));
            }

            return results.ToArray();
        }

        // Функция расшифровки файла
        public void DecodeFile()
        {
            UInt32[] pdwTemp;

            for (int i = 0; i < fileLength; i += 16)
            {
                pdwTemp = ConvertFromByteArrayToUIn32(fileData, i);

                pdwTemp[1] = (pdwTemp[1] + key[0]);
                pdwTemp[3] = (pdwTemp[3] + key[1]);

                for (int j = 1; j <= R; j++)
                {
                    UInt32 t = LeftShift((pdwTemp[1] * (2 * pdwTemp[1] + 1)),
                                        OffsetAmount((int)(Math.Log((double)W) / Math.Log(2.0))));
                    UInt32 u = LeftShift((pdwTemp[3] * (2 * pdwTemp[3] + 1)),
                                        OffsetAmount((int)(Math.Log((double)W) / Math.Log(2.0))));

                    pdwTemp[0] = (LeftShift(pdwTemp[0] ^ t, OffsetAmount((int)u)) + key[2 * j]);
                    pdwTemp[2] = (LeftShift(pdwTemp[2] ^ u, OffsetAmount((int)t)) + key[2 * j + 1]);

                    UInt32 temp = pdwTemp[0];
                    pdwTemp[0] = pdwTemp[1];
                    pdwTemp[1] = pdwTemp[2];
                    pdwTemp[2] = pdwTemp[3];
                    pdwTemp[3] = temp;
                }

                pdwTemp[0] = (pdwTemp[0] + key[2 * R + 2]);
                pdwTemp[2] = (pdwTemp[2] + key[2 * R + 3]);

                // Конвертируем в выходной массив расшифрованных данных
                ConvertFromUInt32ToByteArray(pdwTemp);
            }

            pdwTemp = null;
        }

        // Функция шифрования файла
        public void EncodeFile()
        {
            UInt32[] pdwTemp;

            for (int i = 0; i < fileLength; i += 16)
            {
                pdwTemp = ConvertFromByteArrayToUIn32(fileData, i);

                pdwTemp[0] = (pdwTemp[0] - key[2 * R + 2]);
                pdwTemp[2] = (pdwTemp[2] - key[2 * R + 3]);

                for (int j = R; j >= 1; j--)
                {
                    UInt32 temp = pdwTemp[3];
                    pdwTemp[3] = pdwTemp[2];
                    pdwTemp[2] = pdwTemp[1];
                    pdwTemp[1] = pdwTemp[0];
                    pdwTemp[0] = temp;

                    UInt32 t = LeftShift((pdwTemp[1] * (2 * pdwTemp[1] + 1)),
                                        OffsetAmount((int)(Math.Log((double)W) / Math.Log(2.0))));
                    UInt32 u = LeftShift((pdwTemp[3] * (2 * pdwTemp[3] + 1)),
                                        OffsetAmount((int)(Math.Log((double)W) / Math.Log(2.0))));

                    pdwTemp[0] = (RightShift((pdwTemp[0] - key[2 * j]), OffsetAmount((int)u))) ^ t;
                    pdwTemp[2] = (RightShift((pdwTemp[2] - key[2 * j + 1]), OffsetAmount((int)t))) ^ u;
                }

                pdwTemp[1] = (pdwTemp[1] - key[0]);
                pdwTemp[3] = (pdwTemp[3] - key[1]);

                // Конвертируем в выходной массив зашифрованных данных
                ConvertFromUInt32ToByteArray(pdwTemp);
            }

            pdwTemp = null;
        }
    }

Example:
Console.Write("Enc dec ? 1:2");
            string encdec = Console.ReadLine();

            if (encdec == "1")
                Enc();
            else if (encdec == "2")
                Dec();
            else
                Console.Write("\nError\n");
        }

        public static void Enc()
        {
            var ob = new RC6Base();
            ob.fileData = ob.ReadByteArrayFromFile("test.txt"); // данные из шифруемого файла (path - путь к нему)
            ob.fileLength = (uint)ob.fileData.Length;     // их размер
            ob.KeyGen((UInt32)1);                       // формирование ключа (key - задается пользователем или генерируется)
            ob.EncodeFile();                              // само шифрование
            // ну и запись результирующих данных в файл
            ob.WriteByteArrayToFile(ob.resultData.ToArray(), "Encode.txt");
        }

        public static void Dec()
        {
            var ob2 = new RC6Base();
            ob2.fileData = ob2.ReadByteArrayFromFile("Encode.txt"); // данные из шифруемого файла (path - путь к нему)
            ob2.fileLength = (uint)ob2.fileData.Length;     // их размер
            ob2.KeyGen((UInt32)1);                       // формирование ключа (key - задается пользователем или генерируется)
            ob2.DecodeFile();                              // само шифрование
            // ну и запись результирующих данных в файл
            ob2.WriteByteArrayToFile(ob2.resultData.ToArray(), "Decode.txt");
        }

Answer the question

In order to leave comments, you need to log in

2 answer(s)
V
Vladimir Martyanov, 2016-04-22
@vilgeforce

Judging by the symptoms, you have problems encrypting an incomplete block. The cipher works only in blocks of 8 or 16 bytes, for RC6 you need to look at which value.

A
Alexey, 2016-04-22
@alsopub

I think the point is the following.
When reading, you pad the input to blocks of 16 bytes with zeros.
When decrypting, you do the same, this knocks down the decryption, since there should not be zeros there.
In the output (encrypted) file, you need to write all the data (multiples of 16 bytes) and the file size.
That is, when you save an encrypted file, you lose some of the information.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question