2009-06-02 6 views
11

Я пытаюсь зашифровать и расшифровать файл поток через сокет с помощью RijndaelManaged, но я задеваю за исключениеДлина данных для расшифровки недействителена

CryptographicException: Length of the data to decrypt is invalid. 
    at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) 
    at System.Security.Cryptography.CryptoStream.FlushFinalBlock() 
    at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing) 

Исключения брошенного в конце оператор using в getFile, когда весь файл был передан.

Я попытался найти в Интернете, но нашел ответы на проблемы, возникающие при использовании кодирования при шифровании и расшифровке одной строки. Я использую FileStream, поэтому я не указываю кодировку, которая будет использоваться, поэтому это не должно быть проблемой. Это мои методы:

private void transferFile(FileInfo file, long position, long readBytes) 
{ 
    // transfer on socket stream 
    Stream stream = new FileStream(file.FullName, FileMode.Open); 
    if (position > 0) 
    { 
     stream.Seek(position, SeekOrigin.Begin); 
    } 
    // if this should be encrypted, wrap the encryptor stream 
    if (UseCipher) 
    { 
     stream = new CryptoStream(stream, streamEncryptor, CryptoStreamMode.Read); 
    } 
    using (stream) 
    { 
     int read; 
     byte[] array = new byte[8096]; 
     while ((read = stream.Read(array, 0, array.Length)) > 0) 
     { 
      streamSocket.Send(array, 0, read, SocketFlags.None); 
      position += read; 
     } 
    } 
} 

private void receiveFile(FileInfo transferFile) 
{ 
    byte[] array = new byte[8096]; 
    // receive file 
    Stream stream = new FileStream(transferFile.FullName, FileMode.Append); 
    if (UseCipher) 
    { 
     stream = new CryptoStream(stream, streamDecryptor, CryptoStreamMode.Write); 
    } 
    using (stream) 
    { 
     long position = new FileInfo(transferFile.Path).Length; 
     while (position < transferFile.Length) 
     { 
      int maxRead = Math.Min(array.Length, (int)(transferFile.Length - position)); 
      int read = position < array.Length 
         ? streamSocket.Receive(array, maxRead, SocketFlags.None) 
         : streamSocket.Receive(array, SocketFlags.None); 
      stream.Write(array, 0, read); 
      position += read; 
     } 
    } 
} 

Это метод, который я использую для настройки шифров. byte [] init - это сгенерированный массив байтов.

private void setupStreamCipher(byte[] init) 
{ 
    RijndaelManaged cipher = new RijndaelManaged(); 
    cipher.KeySize = cipher.BlockSize = 256; // bit size 
    cipher.Mode = CipherMode.ECB; 
    cipher.Padding = PaddingMode.ISO10126; 
    byte[] keyBytes = new byte[32]; 
    byte[] ivBytes = new byte[32]; 

    Array.Copy(init, keyBytes, 32); 
    Array.Copy(init, 32, ivBytes, 0, 32); 

    streamEncryptor = cipher.CreateEncryptor(keyBytes, ivBytes); 
    streamDecryptor = cipher.CreateDecryptor(keyBytes, ivBytes); 
} 

У кого-нибудь есть идея в том, что я могу делать неправильно?

ответ

6

Мне кажется, что вы не отправляете окончательный блок должным образом. Вам необходимо как минимум FlushFinalBlock() отправить CryptoStream, чтобы гарантировать, что отправляется последний блок (который ищет приемный поток).

Кстати, CipherMode.ECB is more than likely an epic fail с точки зрения безопасности за то, что вы делаете. По крайней мере, используйте CipherMode.CBC (цепочка цепей шифрования), которая фактически использует IV и делает каждый блок зависимым от предыдущего.

РЕДАКТИРОВАТЬ: Упс, поток шифрования находится в режиме чтения. В этом случае вам нужно убедиться, что вы читаете EOF, чтобы CryptoStream мог иметь дело с окончательным блоком, а не останавливаться после readBytes. Вероятно, легче управлять, если вы запускаете поток шифрования в режиме записи.

Еще одно примечание: вы не можете предположить, что байты в байтах равны. Блокированные шифры имеют фиксированный размер блока, который они обрабатывают, и если вы не используете режим шифрования, который преобразует блок-шифр в потоковый шифр, будет добавление, которое зашифрует более длинный текст.

+1

FlushFinalBlock() вызывается в «закрытии раздела» частей с помощью заявления

using(stream) { // } // calls Close() -> FlushFinalBlock()
Я изменит CipherMode, я просто вошел в него в качестве примера, чтобы вы знали, что я не инициализировать мой шифр в любом «странный» путь. ReadBytes в sendFile() еще не используется, я забыл его удалить. Я читал до конца файла, так что это не должно быть проблемой здесь. Я думал, что
cipher.Padding = PaddingMode.ISO10126;
заботился о прокладке? Что я могу изменить, чтобы заставить его работать? – Patrick

+0

Если поток шифрования находится в режиме чтения, последний блок будет потерян, если вы упустите его; он должен фактически прочитать конец файла из своего исходного потока источника, чтобы создать окончательный блок. –

+0

В ответ на Джеффри: Если я попытаюсь вызвать stream.FlushFinalBlock(), это говорит NonSupportedException: FlushFinalBlock нельзя вызывать дважды в одном потоке. Разве это не означает, что конец файла был прочитан (и отправлен)? – Patrick

0
cipher.Mode = CipherMode.ECB; 

Argh! Прокрутка собственного кода безопасности почти всегда плохая идея.

+1

????? да? Он использует Rijndael? это не «сворачивать». Хотя, есть хороший момент, чтобы сделать, что разработчики должны быть осторожны в том, как они используют шифрование. – Cheeso

+0

ECB здесь не работает, потому что каждый блок независимо зашифрован. –

+0

Не имеет значения, какой CipherMode я использую, я все равно получаю исключение «Длина данных ...» ... – Patrick

1

После замечания Джеффри Hantin, я изменил некоторые строки в receiveFile к

using (stream) { 
    FileInfo finfo = new FileInfo(transferFile.Path); 
    long position = finfo.Length; 
    while (position < transferFile.Length) { 
     int maxRead = Math.Min(array.Length, (int)(transferFile.Length - position)); 
     int read = position < array.Length 
        ? streamSocket.Receive(array, maxRead, SocketFlags.None) 
        : streamSocket.Receive(array, SocketFlags.None); 
     stream.Write(array, 0, read); 
     position += read; 
    } 
} 

->

using (stream) { 
    int read = array.Length; 
    while ((read = streamSocket.Receive(array, read, SocketFlags.None)) > 0) { 
     stream.Write(array, 0, read); 
     if ((read = streamSocket.Available) == 0) { 
      break; 
     } 
    } 
} 

И вуаля, она работает (из-за очень любезное дополнение, которые я Бесполезным не стоит беспокоиться об этом раньше). Я не уверен, что произойдет, если Available вернет 0, хотя все данные не были переданы, но я буду склонен к этому позже в этом случае. Спасибо за помощь Джеффри!

С уважением.

0

Mine я просто удалил отступы, и она работает

Ответил на это - cipher.Padding = PaddingMode.ISO10126; Метод

 Смежные вопросы

  • Нет связанных вопросов^_^