😊

【C#】共通鍵暗号での暗号化(DOBON.NET互換)

2022/08/26に公開約4,300字

共通鍵暗号での暗号化

For: C# で共通鍵暗号を使いたい人

国内ではDOBON.NET の手法が用いられることも多いと思いますが、現在では System.Security.Cryptography.RijndaelManagedObsolete になっているので対処法を記述します。

DOBON.NET 互換の暗号化

実は System.Security.Cryptography.RijndaelManagedSystem.Security.Cryptography.Aes.Create() に置き換えるだけで互換のある動作になります。

static class Crypt
{
    static void Main()
    {
        const string input = "Input String 文字列";
        const string password = "password";

        var rijndael = new System.Security.Cryptography.RijndaelManaged();
        var aes = System.Security.Cryptography.Aes.Create();

        string encryptedRijndael = rijndael.EncryptString(input, password);
        string encryptedAes = aes.EncryptString(input, password);
        Console.WriteLine($"Rijndael: {encryptedRijndael}");
        Console.WriteLine($"     Aes: {encryptedAes}");

        Console.WriteLine(rijndael.DecryptString(encryptedRijndael, password));
        Console.WriteLine(aes.DecryptString(encryptedRijndael, password));
    }

    /// <summary>
    /// 文字列を暗号化する
    /// </summary>
    /// <param name="sourceString">暗号化する文字列</param>
    /// <param name="password">暗号化に使用するパスワード</param>
    /// <returns>暗号化された文字列</returns>
    public static string EncryptString(this SymmetricAlgorithm algorithm, string sourceString, string password)
    {
        //パスワードから共有キーと初期化ベクタを作成
        byte[] key, iv;
        GenerateKeyFromPassword(
            password, algorithm.KeySize, out key, algorithm.BlockSize, out iv);
        algorithm.Key = key;
        algorithm.IV = iv;

        //文字列をバイト型配列に変換する
        byte[] strBytes = System.Text.Encoding.UTF8.GetBytes(sourceString);

        //対称暗号化オブジェクトの作成
        System.Security.Cryptography.ICryptoTransform encryptor =
            algorithm.CreateEncryptor();
        //バイト型配列を暗号化する
        byte[] encBytes = encryptor.TransformFinalBlock(strBytes, 0, strBytes.Length);
        //閉じる
        encryptor.Dispose();

        //バイト型配列を文字列に変換して返す
        return System.Convert.ToBase64String(encBytes);
    }

    /// <summary>
    /// 暗号化された文字列を復号化する
    /// </summary>
    /// <param name="sourceString">暗号化された文字列</param>
    /// <param name="password">暗号化に使用したパスワード</param>
    /// <returns>復号化された文字列</returns>
    public static string DecryptString(this SymmetricAlgorithm algorithm, string sourceString, string password)
    {
        //パスワードから共有キーと初期化ベクタを作成
        byte[] key, iv;
        GenerateKeyFromPassword(
            password, algorithm.KeySize, out key, algorithm.BlockSize, out iv);
        algorithm.Key = key;
        algorithm.IV = iv;

        //文字列をバイト型配列に戻す
        byte[] strBytes = System.Convert.FromBase64String(sourceString);

        //対称暗号化オブジェクトの作成
        System.Security.Cryptography.ICryptoTransform decryptor =
            algorithm.CreateDecryptor();
        //バイト型配列を復号化する
        //復号化に失敗すると例外CryptographicExceptionが発生
        byte[] decBytes = decryptor.TransformFinalBlock(strBytes, 0, strBytes.Length);
        //閉じる
        decryptor.Dispose();

        //バイト型配列を文字列に戻して返す
        return System.Text.Encoding.UTF8.GetString(decBytes);
    }

    /// <summary>
    /// パスワードから共有キーと初期化ベクタを生成する
    /// </summary>
    /// <param name="password">基になるパスワード</param>
    /// <param name="keySize">共有キーのサイズ(ビット)</param>
    /// <param name="key">作成された共有キー</param>
    /// <param name="blockSize">初期化ベクタのサイズ(ビット)</param>
    /// <param name="iv">作成された初期化ベクタ</param>
    static void GenerateKeyFromPassword(string password,
       int keySize, out byte[] key, int blockSize, out byte[] iv)
    {
        //パスワードから共有キーと初期化ベクタを作成する
        //saltを決める
        byte[] salt = System.Text.Encoding.UTF8.GetBytes("saltは必ず8バイト以上");
        //Rfc2898DeriveBytesオブジェクトを作成する
        System.Security.Cryptography.Rfc2898DeriveBytes deriveBytes =
            new System.Security.Cryptography.Rfc2898DeriveBytes(password, salt);
        //.NET Framework 1.1以下の時は、PasswordDeriveBytesを使用する
        //System.Security.Cryptography.PasswordDeriveBytes deriveBytes =
        //    new System.Security.Cryptography.PasswordDeriveBytes(password, salt);
        //反復処理回数を指定する デフォルトで1000回
        deriveBytes.IterationCount = 1000;

        //共有キーと初期化ベクタを生成する
        key = deriveBytes.GetBytes(keySize / 8);
        iv = deriveBytes.GetBytes(blockSize / 8);
    }
}

Discussion

ログインするとコメントできます