40

簡単な文字列暗号化が必要だったので、次のコードを作成しました(ここから多くの「インスピレーション」を得て)。

    // create and initialize a crypto algorithm
    private static SymmetricAlgorithm getAlgorithm(string password) {
        SymmetricAlgorithm algorithm = Rijndael.Create();
        Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes(
            password, new byte[] {
            0x53,0x6f,0x64,0x69,0x75,0x6d,0x20,             // salty goodness
            0x43,0x68,0x6c,0x6f,0x72,0x69,0x64,0x65
        }
        );
        algorithm.Padding = PaddingMode.ISO10126;
        algorithm.Key = rdb.GetBytes(32);
        algorithm.IV = rdb.GetBytes(16);
        return algorithm;
    }

    /* 
     * encryptString
     * provides simple encryption of a string, with a given password
     */
    public static string encryptString(string clearText, string password) {
        SymmetricAlgorithm algorithm = getAlgorithm(password);
        byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, algorithm.CreateEncryptor(), CryptoStreamMode.Write);
        cs.Write(clearBytes, 0, clearBytes.Length);
        cs.Close();
        return Convert.ToBase64String(ms.ToArray());
    }

    /*
     * decryptString
     * provides simple decryption of a string, with a given password
     */
    public static string decryptString(string cipherText, string password) {
        SymmetricAlgorithm algorithm = getAlgorithm(password);
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, algorithm.CreateDecryptor(), CryptoStreamMode.Write);
        cs.Write(cipherBytes, 0, cipherBytes.Length);
        cs.Close();            
        return System.Text.Encoding.Unicode.GetString(ms.ToArray());
    }

間違ったキーでデータを復号化すると、decryptStringのcs.Close()行に「パディングが無効で削除できません」というCryptographicExceptionが発生することを除いて、コードは正常に機能しているように見えます。

サンプルコード:

    string password1 = "password";
    string password2 = "letmein";
    string startClearText = "The quick brown fox jumps over the lazy dog";
    string cipherText = encryptString(startClearText, password1);
    string endClearText = decryptString(cipherText, password2);     // exception thrown

私の質問は、これは予想されることですか?間違ったパスワードで復号化すると、例外ではなく、意味のない出力になると思っていたでしょう。

4

9 に答える 9

27

これはすでに回答されていますが、なぜそれが予想されるのかを説明することは良い考えだと思います.

ほとんどの暗号化フィルターは意味的に安全ではなく、いくつかの形式の暗号攻撃を防ぐため、通常はパディング スキームが適用されます。たとえば、通常、RSA ではOAEPパディング スキームが使用され、ある種の攻撃 (選択された平文攻撃やブラインドなど) を防ぎます。

パディング スキームは、メッセージが送信される前に、(通常は) ランダムなガベージをメッセージ m に追加します。たとえば、OAEP メソッドでは、2 つのオラクルが使用されます (これは単純化した説明です)。

  1. モジュラスのサイズを指定すると、k1 ビットに 0 をパディングし、k0 ビットに乱数をパディングします。
  2. 次に、メッセージに何らかの変換を適用することにより、暗号化されて送信されるパディングされたメッセージを取得します。

これにより、メッセージのランダム化と、メッセージがガベージかどうかをテストする方法が提供されます。パディング スキームは可逆的であるため、メッセージ自体の整合性については何も言えませんが、メッセージを復号化すると、実際には、パディングについて何らかの主張を行うことができるため、メッセージが正しく復号化されたかどうかを知ることができます。または、何か間違ったことをしている (つまり、誰かがメッセージを改ざんしたか、間違ったキーを使用している)

于 2008-08-25T15:46:00.960 に答える
17

同様の「パディングが無効で削除できない」という現象が発生しました。例外ですが、私の場合、キー IV とパディングは正しかったです。

欠けていたのは、暗号ストリームをフラッシュすることだけであることが判明しました。

このような:

            MemoryStream msr3 = new MemoryStream();
            CryptoStream encStream = new CryptoStream(msr3, RijndaelAlg.CreateEncryptor(), CryptoStreamMode.Write);
            encStream.Write(bar2, 0, bar2.Length);
            // unless we flush the stream we would get "Padding is invalid and cannot be removed." exception when decoding
            encStream.FlushFinalBlock();
            byte[] bar3 = msr3.ToArray();
于 2013-11-07T11:44:56.370 に答える
6

使用法を正しくしたい場合は、暗号文に認証を追加して、それが正しいパスワードであること、または暗号文が変更されていないことを確認できるようにする必要があります。ISO10126を使用しているパディングは、最後のバイトがパディングの 16 の有効な値 (0x01-0x10) のいずれかとして復号化されない場合にのみ、例外をスローします。したがって、間違ったパスワードで例外をスローしない可能性は 1/16 です。認証すると、復号化が有効かどうかを決定論的に判断できます。

crypto api の使用は、一見簡単そうに見えて、実際には間違いを犯しやすいです。たとえば、キーと iv の派生に固定ソルトを使用すると、同じパスワードで暗号化されたすべての暗号文がそのキーでその IV を再利用することになり、CBC モードでのセマンティック セキュリティが破られます。IV は予測不能で一意である必要があります。与えられたキー。

間違いを犯しやすいという理由から、私はコード スニペットを持っています。これを見直して最新の状態に保つようにしています (コメント、問題を歓迎します)。

文字列 C# の対称認証暗号化の最新の例。

AESThenHMAC.AesSimpleDecryptWithPassword(ciphertext, password)間違ったパスワードが使用された場合に使用するとnull、暗号化テキストまたは iv が暗号化後に変更されてnull返された場合に返され、ジャンク データが返されたり、パディング例外が返されたりすることはありません。

于 2013-02-20T02:01:15.980 に答える
3

はい、これは予想されることです。少なくとも、暗号化ルーチンが復号化できないデータを取得したときに何が起こるかは正確です。

于 2008-08-14T23:25:22.470 に答える
3

例外のもう 1 つの理由は、復号化ロジックを使用する複数のスレッド間の競合状態である可能性があります。ICryptoTransform のネイティブ実装はスレッドセーフではないため(SymmetricAlgorithm など)、 lockを使用するなど、排他的なセクションに配置する必要があります。詳細については、こちらを参照してください: http://www.make-awesome.com/2011/07/system-security-cryptography-and-thread-safety/

于 2016-10-10T10:43:12.170 に答える
1

CryptoStreamに未読バイトが含まれている可能性があります。ストリームを完全に読み取る前に閉じると、プログラムでエラーが発生していました。

于 2010-08-04T09:16:27.087 に答える
0

同様の問題がありました。復号化メソッドの問題は、空のメモリ ストリームを初期化することでした。次のような暗号テキストバイト配列で初期化したときに機能したとき:

MemoryStream ms = new MemoryStream(cipherText)
于 2015-02-02T12:13:46.263 に答える