業界トップクラスの求人数を誇る転職エージェントPR

リクルートグループのコネクションを活かした非公開求人も充実、他にはない好条件の求人と出会える

5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

.NETで暗号化するときの注意点~こうしてあなたは罠に嵌る

Posted at

はじめに

唐突ですが、今からよく似たコードを2種類提示します。
どちらかが正しく動き、どちらかがランタイムエラーとなります。

A

パターンA.cs
public static class Cipher
{
    private static readonly byte[] InitialzationVector = Encoding.UTF8.GetBytes(@"xxxxxxxxxxxxxxxx");
    private static readonly byte[] SharedKey = Encoding.UTF8.GetBytes(@"xxxxxxxxxxxxxxxx");
    private static readonly int BlockSize = InitialzationVector.Length * 8;
    private static readonly int KeySize = SharedKey.Length * 8;

    public static string Encrypt(string plainText)
    {
        using var rijndael = new RijndaelManaged
        {
            BlockSize = BlockSize,
            KeySize = KeySize,
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
            IV = InitialzationVector,
            Key = SharedKey,
        };

        using var encryptor = rijndael.CreateEncryptor();
        var bytes = Encoding.UTF8.GetBytes(plainText);
        return Convert.ToBase64String(encryptor.TransformFinalBlock(bytes, 0, bytes.Length));
    }

    public static string Decrypt(string cipherText)
    {
        using var rijndael = new RijndaelManaged
        {
            BlockSize = BlockSize,
            KeySize = KeySize,
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
            IV = InitialzationVector,
            Key = SharedKey,
        };

        using var decryptor = rijndael.CreateDecryptor();
        var bytes = Convert.FromBase64String(cipherText);
        var plain = decryptor.TransformFinalBlock(bytes, 0, bytes.Length);
        return Encoding.UTF8.GetString(plain);
    }
}

B

パターンB.cs
public static class Cipher
{
    private static readonly byte[] InitialzationVector = Encoding.UTF8.GetBytes(@"xxxxxxxxxxxxxxxx");
    private static readonly byte[] SharedKey = Encoding.UTF8.GetBytes(@"xxxxxxxxxxxxxxxx");
    private static readonly int BlockSize = InitialzationVector.Length * 8;
    private static readonly int KeySize = SharedKey.Length * 8;

    public static string Encrypt(string plainText)
    {
        using var rijndael = new RijndaelManaged
        {
            IV = InitialzationVector,
            Key = SharedKey,
            BlockSize = BlockSize,
            KeySize = KeySize,
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
        };

        using var encryptor = rijndael.CreateEncryptor();
        var bytes = Encoding.UTF8.GetBytes(plainText);
        return Convert.ToBase64String(encryptor.TransformFinalBlock(bytes, 0, bytes.Length));
    }

    public static string Decrypt(string cipherText)
    {
        using var rijndael = new RijndaelManaged
        {
            IV = InitialzationVector,
            Key = SharedKey
            BlockSize = BlockSize,
            KeySize = KeySize,
            Mode = CipherMode.CBC,
            Padding = PaddingMode.PKCS7,
        };

        using var decryptor = rijndael.CreateDecryptor();
        var bytes = Convert.FromBase64String(cipherText);
        var plain = decryptor.TransformFinalBlock(bytes, 0, bytes.Length);
        return Encoding.UTF8.GetString(plain);
    }
}

結果

答えは Aが正しく動作する でした。
以上!!

...というだけでは寂しいので少しだけ補足をします。

ちなみに違いは BlockSize / KeySize を先に初期化 するか、IV / Keyを先に初期化 するかの違いしかありません。

発生する例外

例外はどうやら Decrypt のときに発生しているようです。
image.png

そこで 公式ドキュメント を見に行ってみると、どうやらこの例外は「inputCount パラメーターの長さが、入力ブロック サイズで割り切れない場合」に発生するようです。

じゃあ、実際にどうなっているのか変数をウォッチしてみました。
image.png

画像では閉じている項目も比較してみましたが同じ値でした😇

どうやら、ローカルウォッチでは見えないところで何やらあやしいことをしているようです。
闇に片足を突っ込む気がしたので、これ以上は追うのをやめました。

おわりに

プロパティに setter を設ける場合は、利用者側がどういった順序で値を入れていくかは不定なので、こういった設計をしてはいけません。

これは明らかに 悪い設計 なので自分がクラスを作成する際は気をつけましょう。
もし万が一こういった作りをしてしまった場合は、ドキュメントに必ず呼び出し順序の規約を明記しておきましょう。

それがないと誰も仕様がわかりませんし、あなたの考えていることなどエスパーではないので誰も察してくれません。

また、昨今のトレンドで言えばそもそも Immutable にしていこうという流れなので、setter などという諸悪の根源たる機能を使ってはなりません(過激派)。

自戒も込めて、肝に銘じておきましょう。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Qiita Conference 2025 will be held!: 4/23(wed) - 4/25(Fri)

Qiita Conference is the largest tech conference in Qiita!

Keynote Speaker

ymrl、Masanobu Naruse, Takeshi Kano, Junichi Ito, uhyo, Hiroshi Tokumaru, MinoDriven, Minorun, Hiroyuki Sakuraba, tenntenn, drken, konifar

View event details
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?