Поблочное считывание файла

325
12 августа 2017, 00:46

Дорогие друзья, хочу реализовать шифрование некоторых файлов на языке с# Проблема заключается в том, что ключ имеет длину 64 байта, и мне соответственно нужно считывать файл по 64 байта, и складывать с ключом (согласен, не лучший алгоритм шифрования)

Вопрос 1: как считывать файл массивами по 64 байта

Вопрос 2: Что делать если количество байт в файле не кратно 64 (а это будет очень часто), то есть что делать с последним незаконченным массивом байт

Вот мой говнокодик:

public static void Code(string path, byte[] key)
{
    //Crypting function
    byte[] buffer = new byte[64];
    FileStream f, fo;
    f = File.OpenRead(path);
    fo = File.Create(path + "tex");
    f.Read(buffer, 0, 64);
    fo.Write(buffer, 0, 64);
    f.Close();
    fo.Close();
}

Заранее спасибо.

Answer 1
public static void Code(string path, byte[] key)
{
    const int blockSize = 64;
    //Crypting function
    byte[] buffer = new byte[blockSize];
    using (var f = File.OpenRead(path))
    using (var fo = File.Create(path + "tex"))
    {
        while (true)
        {
            int readed;
            int offset;
            for (offset = 0; offset < blockSize;)
            {
                readed = f.Read(buffer, offset, blockSize - offset);
                if (readed == 0) // End of file
                    break;
                offset += readed;
            }
            Int32 size = offset;
            if (size == 0)
                return; // End of file, nothing to process
            fo.Write(buffer, 0, size);
            if (size < blockSize)
                return; // End of file
        }
    }
}
Answer 2

Вам понадобится такая вспомогательная функция:

static int ReadBlock(Stream s, byte[] block)
{
    int position = 0;
    while (position < block.Length)
    {
        var actuallyRead = s.Read(block, position, block.Length - position);
        if (actuallyRead == 0)
            break;
        position += actuallyRead;
    }
    return position;
}

Она читает блок данных из потока, и возвращает количество реально прочитанных байт. Все блоки, за исключением последнего, будут полными.

Теперь ваш код должен выглядеть как-то так:

using (var infile = File.OpenRead(inpath))
using (var outfile = File.Create(outpath))
{
    byte[] buf = new byte[64];
    while (true)
    {
        var bytesRead = ReadBlock(infile, buf);
        if (bytesRead == 0)
            break;
        // байты с номерами от 0 до bytesRead сложить с соответствующими байтами ключа
        // выравнивание до границы 64 байт не нужно
        outfile.Write(buf, 0, bytesRead);
    }
}

Как правильно подсказывает @PashaPash, трюк с неполным последним блоком сработает лишь в простом случае — когда вы просто складываете текст с ключом побайтно. Для более общего случая, блочному шифру нужно будет ровно 64 байта открытого текста, и вам нужно будет дополнить их чем-то (лучше всего, наверное, криптографически стойкой случайной последовательностью, потому что нули могут вскрыть информацию о вашем ключе), а также где-то хранить исходную длину файла. Впрочем, лучше не доверять себе в тонких вопросах, и воспользоваться готовыми криптографическими функциями, благо в .NET их более чем достаточно.

(По сути тот же код, что и в ответе @LunarWhisper, но немного по-другому организован.)

READ ALSO
Fluent API связь один к одному

Fluent API связь один к одному

Не получается сделать связь один к одному, ошибка :

318
C#. Как отследить использование диска?

C#. Как отследить использование диска?

В диспетчере задач, во вкладке производительность можно нажать на "Диск 0 (c:)"Как получить переменную с его активным временем в процентах?

192
В textbox нет invoke, что делать?

В textbox нет invoke, что делать?

Почему Invoke не идёт в комплект textbox и что можно придумать?

292
Как сделать пароль под AES 256?

Как сделать пароль под AES 256?

Здравствуйте, скажите пожалуйста как сделать 256 битный пароль под AES, на основе пользовательского пароля, длина которого может быть совсем...

481