C# で AES暗号 (共通鍵暗号) を 利用 する 方法

0 件のコメント

AES暗号 を 利用して暗号化および復号を行うとき、具体的にどのようなコードを実装すればよいかをまとめてみました。 暗号技術の詳細には触れず、実装する場合にどうしたら良いか、という観点でまとめました。

概要

"AES暗号" は 共通鍵暗号 の一種です。 学術的な詳細は分かりませんが… "DES暗号" よりは安全な暗号方法です。

AES暗号の仕様として以下のルールが決まっているので、利用する際は設定を間違えないように気を付けます。

ブロック長
128bit
鍵長
128/192/256bit

実際に実装で利用する共通鍵は「IV (Initialize Vector/初期化ベクタ)」と「Key (鍵)」の2項目になります。 これらを公開鍵暗号等であらかじめ交換しておきます。

共通鍵

  • IV
  • Key

鍵作成

鍵(IV、Key)の生成は何もしなければ自動生成されます。 生成された鍵はプロパティから取得できます。 また、手動で鍵を生成したい場合は Rfc2898DeriveBytes クラス を利用します。

自動生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
using System.Security.Cryptography;
 
public void CreateKey1(out string iv, out string key)
{
    var BLOCK_SIZE = 128;   // 128bit 固定
    var KEY_SIZE = 128;     // 128/192/256bit から選択
 
    // AES暗号サービスを生成
    var csp = new AesCryptoServiceProvider();
    csp.BlockSize = BLOCK_SIZE;
    csp.KeySize = KEY_SIZE;
    csp.Mode = CipherMode.CBC;
    csp.Padding = PaddingMode.PKCS7;
 
    // IV および 鍵 を自動生成
    csp.GenerateIV();
    csp.GenerateKey();
 
    // 鍵を出力;
    iv = Convert.ToBase64String(csp.IV);
    key = Convert.ToBase64String(csp.Key);
}

手動生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
using System.Security.Cryptography;
 
public void CreateKey2(string ivPassword, out string iv, string keyPassword, out string key)
{
    var BLOCK_SIZE = 128;   // 128bit 固定
    var KEY_SIZE = 128;     // 128/192/256bit から選択
 
    // IV を生成
    var rfcBlock = new Rfc2898DeriveBytes(ivPassword, BLOCK_SIZE / 8);
    var arrBlock = rfcBlock.GetBytes(BLOCK_SIZE / 8);
    iv = Convert.ToBase64String(arrBlock);
 
    // Key を生成
    var rfcKey = new Rfc2898DeriveBytes(keyPassword, KEY_SIZE / 8);
    var arrKey = rfcKey.GetBytes(KEY_SIZE / 8);
    key = Convert.ToBase64String(arrKey);
}

暗号化

上述の 鍵生成 で生成した IV および Key を利用して文字列を暗号化します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;
using System.IO;
using System.Security.Cryptography;
 
public string Encrypt(string plainText, string iv, string key)
{
    var cipherText = string.Empty;
 
    var BLOCK_SIZE = 128;   // 128bit 固定
    var KEY_SIZE = 128;     // 128/192/256bit から選択
 
    var csp = new AesCryptoServiceProvider();
    csp.BlockSize = BLOCK_SIZE;
    csp.KeySize = KEY_SIZE;
    csp.Mode = CipherMode.CBC;
    csp.Padding = PaddingMode.PKCS7;
    csp.IV = Convert.FromBase64String(iv);
    csp.Key = Convert.FromBase64String(key);
 
    using (var outms = new MemoryStream())           
    using (var encryptor = csp.CreateEncryptor())
    using (var cs = new CryptoStream(outms, encryptor, CryptoStreamMode.Write))
    using (var writer = new StreamWriter(cs))
    {
        writer.Write(plainText);
        cipherText = Convert.ToBase64String(outms.ToArray());
    }
 
    return cipherText;
}

復号

上述の 鍵生成 で生成した IV および Key を利用して、 暗号化 で暗号化した文字列を復号します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.IO;
using System.Security.Cryptography;
 
public string Decrypt(string cipherText, string iv, string key)
{
    var plainText = string.Empty;
 
    var BLOCK_SIZE = 128;   // 128bit 固定
    var KEY_SIZE = 128;     // 128/192/256bit から選択
 
    var csp = new AesCryptoServiceProvider();
    csp.BlockSize = BLOCK_SIZE;
    csp.KeySize = KEY_SIZE;
    csp.Mode = CipherMode.CBC;
    csp.Padding = PaddingMode.PKCS7;
    csp.IV = Convert.FromBase64String(iv);
    csp.Key = Convert.FromBase64String(key);
 
    using (var inms = new MemoryStream(Convert.FromBase64String(cipherText)))
    using (var decryptor = csp.CreateDecryptor())
    using (var cs = new CryptoStream(inms, decryptor, CryptoStreamMode.Read))
    using (var reader = new StreamReader(cs))
    {
        plainText = reader.ReadToEnd();
    }
 
    return plainText;
}

[おまけ] サンプルコード

鍵生成、暗号化、複合をまとめて利用しやすくしたサンプルコードを以下に掲載します。 基本的にはコピペで動きます。

AesCryptgraphy.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System;
using System.IO;
using System.Security.Cryptography;
 
public class AesCryptgraphy
{
    /// <summary>
    /// AesCryptgraphy クラスのインスタンスを初期化します。
    /// </summary>
    public AesCryptgraphy()
    {
        this.BlockSize = 128;
        this.KeySize = 256;
    }
 
    /// <summary>
    /// キー長を指定して AesCryptgraphy クラス のインスタンスを初期化します。
    /// </summary>
    /// <param name="keySize"></param>
    public AesCryptgraphy(int keySize)
    {
        this.BlockSize = 128;
        this.KeySize = KeySize;
    }
 
    /// <summary>
    /// ブロック長を取得または設定します。
    /// ※値は 128bit 固定です。
    /// </summary>
    public int BlockSize { get; set; }
 
    /// <summary>
    /// キー長を取得または設定します。
    /// ※値は 128 / 192 / 256 bit から選択します。
    /// </summary>
    public int KeySize { get; set; }
 
    /// <summary>
    /// 共通鍵(IV, キー)を自動生成します。
    /// </summary>
    /// <param name="iv">IV</param>
    /// <param name="key">キー</param>
    public void CreateKey(out string iv, out string key)
    {
        // AES暗号サービスを生成
        var csp = new AesCryptoServiceProvider();
        csp.BlockSize = this.BlockSize;
        csp.KeySize = this.KeySize;
        csp.Mode = CipherMode.CBC;
        csp.Padding = PaddingMode.PKCS7;
 
        // IV および 鍵 を自動生成
        csp.GenerateIV();
        csp.GenerateKey();
 
        // 鍵を出力;
        iv = Convert.ToBase64String(csp.IV);
        key = Convert.ToBase64String(csp.Key);
    }
 
    /// <summary>
    /// 共通鍵を派生させるパスワードを指定して共通鍵(IV, キー)を生成します。
    /// </summary>
    /// <param name="ivPassword">IVを派生させるパスワード</param>
    /// <param name="iv">IV</param>
    /// <param name="keyPassword">キーを派生させるパスワード</param>
    /// <param name="key">キー</param>
    public void CreateKey(string ivPassword, out string iv, string keyPassword, out string key)
    {
        // IV を生成
        var rfcBlock = new Rfc2898DeriveBytes(ivPassword, this.BlockSize / 8);
        var arrBlock = rfcBlock.GetBytes(this.BlockSize / 8);
        iv = Convert.ToBase64String(arrBlock);
 
        // Key を生成
        var rfcKey = new Rfc2898DeriveBytes(keyPassword, this.KeySize / 8);
        var arrKey = rfcKey.GetBytes(this.BlockSize / 8);
        key = Convert.ToBase64String(arrKey);
    }
 
    /// <summary>
    /// IV、キーを指定して文字列の暗号化を行います。
    /// </summary>
    /// <param name="plainText">暗号化したい文字列</param>
    /// <param name="iv">IV</param>
    /// <param name="key">キー</param>
    /// <returns>暗号化された文字列</returns>
    public string Encrypt(string plainText, string iv, string key)
    {
        var cipherText = string.Empty;
 
        var csp = new AesCryptoServiceProvider();
        csp.BlockSize = this.BlockSize;
        csp.KeySize = this.KeySize;
        csp.Mode = CipherMode.CBC;
        csp.Padding = PaddingMode.PKCS7;
        csp.IV = Convert.FromBase64String(iv);
        csp.Key = Convert.FromBase64String(key);
 
        using (var outms = new MemoryStream())           
        using (var encryptor = csp.CreateEncryptor())
        using (var cs = new CryptoStream(outms, encryptor, CryptoStreamMode.Write))
        {
            using (var writer = new StreamWriter(cs))
            {
                writer.Write(plainText);
            }
            cipherText = Convert.ToBase64String(outms.ToArray());
        }
 
        return cipherText;
    }
 
    /// <summary>
    /// IV、キーを指定して暗号化された文字列の複合を行います。
    /// </summary>
    /// <param name="cipherText">暗号化された文字列</param>
    /// <param name="iv">IV</param>
    /// <param name="key">キー</param>
    /// <returns>復号された文字列</returns>
    public string Decrypt(string cipherText, string iv, string key)
    {
        var plainText = string.Empty;
 
        var csp = new AesCryptoServiceProvider();
        csp.BlockSize = this.BlockSize;
        csp.KeySize = this.KeySize;
        csp.Mode = CipherMode.CBC;
        csp.Padding = PaddingMode.PKCS7;
        csp.IV = Convert.FromBase64String(iv);
        csp.Key = Convert.FromBase64String(key);
 
        using (var inms = new MemoryStream(Convert.FromBase64String(cipherText)))
        using (var decryptor = csp.CreateDecryptor())
        using (var cs = new CryptoStream(inms, decryptor, CryptoStreamMode.Read))
        using (var reader = new StreamReader(cs))
        {
            plainText = reader.ReadToEnd();
        }
 
        return plainText;
    }
}

参考記事

最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!