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; } } |
参考記事
- HIBARA Software - C#(.NET Framework)のAESを使ってファイルを暗号化してみる
- @IT - 第3回 AES暗号化
- DOBON.NET - パスワードで文字列を暗号化する
- MSDN - Rfc2898DeriveBytes クラス
- MSDN - AesCryptoServiceProvider クラス
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!