12

RijndaelManagedを使用してソケットを介してファイルストリームを暗号化および復号化しようとしていますが、例外にぶつかり続けます

CryptographicException:復号化するデータの長さが無効です。
    System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte [] inputBuffer、Int32 inputOffset、Int32 inputCount)で
    System.Security.Cryptography.CryptoStream.FlushFinalBlock()で
    System.Security.Cryptography.CryptoStream.Dispose(ブール値の破棄)で

ファイル全体が転送されると、receiveFileのusingステートメントの最後に例外がスローされます。

Webを検索してみましたが、単一の文字列を暗号化および復号化するときにエンコーディングを使用するときに発生する問題に対する回答しか見つかりませんでした。私は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);
}

誰かが私が間違っているかもしれないことについて考えを持っていますか?

4

4 に答える 4

6

最終ブロックを適切に送信していないようです。最終ブロック (受信ストリームが探しているブロック) が確実に送信されるようにするには、少なくともFlushFinalBlock()送信する必要があります。CryptoStream

ところで、あなたがやっていることのセキュリティに関してはCipherMode.ECB、壮大な失敗である可能性が高いです. 少なくともCipherMode.CBC、実際に IV を使用し、各ブロックを前のブロックに依存させる (暗号ブロック連鎖) を使用します。

編集: おっと、暗号化ストリームは読み取りモードです。その場合、CryptoStream が の後に停止するのではなく、最終ブロックを処理できるように、必ず EOF まで読み取る必要がありますreadBytes。暗号化ストリームを書き込みモードで実行すると、おそらく制御が容易になります。

もう 1 つ注意: バイト インがバイト アウトに等しいと仮定することはできません。ブロック暗号は処理するブロック サイズが固定されており、ブロック暗号をストリーム暗号に変換する暗号モードを使用していない限り、暗号文が平文よりも長くなるパディングがあります。

于 2009-06-02T22:21:08.490 に答える
1

Jeffrey 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 を返した場合に何が起こるかはわかりませんが、その場合は後で対処します。助けてくれてありがとうジェフリー!

よろしく。

于 2009-06-04T16:41:38.700 に答える
0

私のパディングを削除しただけで動作します

これをコメントアウトしました - cipher.Padding = PaddingMode.ISO10126;

于 2016-07-08T01:02:16.317 に答える
0
cipher.Mode = CipherMode.ECB;

ああ!独自のセキュリティ コードを展開することは、ほとんどの場合、悪い考えです。

于 2009-06-02T23:40:59.077 に答える