AES暗号 を 利用して暗号化および復号を行うとき、具体的にどのようなコードを実装すればよいかをまとめてみました。 暗号技術の詳細には触れず、実装する場合にどうしたら良いか、という観点でまとめました。
目次
概要
"AES暗号" は 共通鍵暗号 の一種です。 学術的な詳細は分かりませんが… "DES暗号" よりは安全な暗号方法です。
AES暗号の仕様として以下のルールが決まっているので、利用する際は設定を間違えないように気を付けます。
- ブロック長
- 128bit
- 鍵長
- 128/192/256bit
実際に実装で利用する共通鍵は「IV (Initialize Vector/初期化ベクタ)」と「Key (鍵)」の2項目になります。 これらを公開鍵暗号等であらかじめ交換しておきます。
共通鍵
- IV
- Key
鍵作成
鍵(IV、Key)の生成は何もしなければ自動生成されます。
生成された鍵はプロパティから取得できます。
また、手動で鍵を生成したい場合は Rfc2898DeriveBytes クラス
を利用します。
自動生成
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); }
手動生成
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 を利用して文字列を暗号化します。
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 を利用して、 暗号化 で暗号化した文字列を復号します。
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
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 の フォロー」 お願いします!!