2009-06-02 27 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) 

receiveFileのusingステートメントの最後に例外がスローされます。転送されました。

Webを検索しようとしましたが、1つの文字列を暗号化および復号化するときにエンコードを使用するときに発生する問題に対する答えが見つかりました。私は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あなたのしていることに対するセキュリティの点で。少なくとも実際にIVを使用し、各ブロックを前のブロックに依存させるCipherMode.CBC(暗号ブロック連鎖)を使用してください。

EDIT:暗号化ストリームは読み取りモードです。その場合は、readBytesの後に停止するのではなく、CryptoStreamが最後のブロックを処理できるようにEOFに確実に読み替える必要があります。書き込みモードで暗号化ストリームを実行すると、制御が簡単になるでしょう。

もう1つのメモ:等しいバイト数のバイトが出ていると見なすことはできません。ブロック暗号は処理する固定ブロックサイズを持ち、ブロック暗号をストリーム暗号に変換する暗号モードを使用しない限り、暗号文を平文より長くするためのパディングがあります。

+1

FlushFinalBlock()メソッドは、私はCipherModeを変更します

using(stream) { // } // calls Close() -> FlushFinalBlock()
使用して文の「クローズセクション」で呼び出されますが、私はいずれかの私の暗号を初期化しないことを知っているので、私は一例として、それを入力します"奇妙な"方法。 sendFile()のreadBytesはまだ使用されていませんが、削除するのを忘れていました。私はファイルの最後まで読んでいるので、ここでは問題にはならないはずです。
cipher.Padding = PaddingMode.ISO10126;
さんがパディングを担当していたと思いますか?それを機能させるために私は何を変えることができますか? – Patrick

+0

暗号化ストリームが読み取りモードの場合、最後のブロックは廃棄すると失われます。最終的なブロックを生成するためには、実際にファイルの終わりを元のソースストリームから読み取る必要があります。 –

+0

Jeffreyへの応答:stream.FlushFinalBlock()を呼び出そうとすると、NonSupportedExceptionと表示されます。同じストリームでFlushFinalBlockを2回呼び出すことはできません。これは、ファイルの終わりが読み取られ(そして送信された)ことを意味しませんか? – Patrick

0
cipher.Mode = CipherMode.ECB; 

Argh!あなた自身のセキュリティコードをローリングすることは、ほとんど常に悪い考えです。

+1

?????ハァッ?彼はRijndaelを使用していますか?これは「あなた自身のロール」ではありません。しかし、開発者は暗号の使い方に注意する必要があります。 – Cheeso

+0

各ブロックが独立して暗号化されているため、ECBはここで失敗します。 –

+0

私はどのCipherModeを使用しても問題はありませんが、私はまだ "デ​​ータの長さ..."例外を受け取ります... – Patrick

1

はジェフリーHantinによって行われたコメントの後、私はので、私はdidnの今までとても親切パディングの

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; 
     } 
    } 
} 

出来上がり、彼女の作品(にreceiveFileでいくつかの行を変更しました以前は気にしない)。すべてのデータが転送されていなくてもAvailableが0を返す場合はどうなるのかよく分かりませんが、後でそのようになる傾向があります。助けてくれてありがとうJeffrey!

よろしくお願いいたします。

0

鉱山は、私はちょうど詰め物を取り出して、それがこのコメントアウト

に動作します - cipher.Padding = PaddingMode。ISO10126;

関連する問題