C#でAES-256を利用して文字列を暗号化・復号化する方法を紹介します。
ランダムなIV(初期化ベクトル)を生成し、暗号文の先頭へ付与する実装例です。
サンプルコードを交えながら、暗号化から復号化までの一連の流れを解説します。
C#でAES-256暗号化・復号化を実装する
AES(Advanced Encryption Standard)は、現在広く利用されている共通鍵暗号方式です。
今回は、AES-256を利用して文字列を暗号化・復号化するサンプルを紹介します。
今回のサンプルでは、以下のような流れで処理を行います。
- 32バイトのキーを利用してAES-256で暗号化
- 暗号化時にランダムなIV(初期化ベクトル)を生成
- IVを暗号データの先頭へ付与
- Base64文字列として保存・送信
- 復号時は先頭16バイトのIVを取り出して復号
サンプルコード
以下はサンプルコードです。
サンプルでは暗号化したい文字列や暗号化キーをソースに書いてしまっているので、引数で渡せるようにした方が使いやすくなるかなと思います。
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace AES256
{
internal class Aes256
{
static void Main()
{
string str = "暗号化したい文字列";
string key = "MySecretKey1234567890_1234567890";
string encStr = Encrypt(str, key);
Console.WriteLine("暗号化した文字列:" + encStr);
string decStr = Decrypt(encStr, key);
Console.WriteLine("復号化した文字列:" + decStr);
}
/// <summary>
/// 復号化(AES-256で暗号化されたBase64文字列を復号する)
/// </summary>
/// <param name="cipherTextBase64">暗号化された文字列</param>
/// <param name="password">暗号化パスワード(32バイト)</param>
public static string Decrypt(string cipherTextBase64, string password)
{
if (string.IsNullOrEmpty(cipherTextBase64))
throw new ArgumentNullException(nameof(cipherTextBase64));
if (string.IsNullOrEmpty(password))
throw new ArgumentNullException(nameof(password));
// 全体のバイト配列をBase64からデコード
byte[] allBytes = Convert.FromBase64String(cipherTextBase64);
const int IvLength = 16;
if (allBytes.Length < IvLength)
throw new CryptographicException("暗号データの長さが足りません。");
// 暗号データからIVを抽出
byte[] ivBytes = new byte[IvLength];
Array.Copy(allBytes, 0, ivBytes, 0, IvLength);
byte[] keyBytes = Encoding.UTF8.GetBytes(password);
// 復号処理
using (Aes aes = Aes.Create())
{
aes.Key = keyBytes;
aes.IV = ivBytes;
using (ICryptoTransform decryptor = aes.CreateDecryptor())
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
{
// 暗号データのIV以外の部分(16バイト目以降)を取得
cs.Write(allBytes, IvLength, allBytes.Length - IvLength);
cs.FlushFinalBlock();
}
// 復号した文字列を返す
return Encoding.UTF8.GetString(ms.ToArray());
}
}
}
/// <summary>
/// 暗号化(文字列をAES-256で暗号化し、先頭にIVを付与したBase64文字列を返す)
/// </summary>
/// <param name="plainText">暗号化する元の文字列</param>
/// <param name="password">暗号化パスワード(32バイト)</param>
/// <returns>暗号化されたBase64文字列</returns>
public static string Encrypt(string plainText, string password)
{
if (plainText == null)
throw new ArgumentNullException(nameof(plainText));
if (string.IsNullOrEmpty(password))
throw new ArgumentNullException(nameof(password));
byte[] keyBytes = Encoding.UTF8.GetBytes(password);
// 暗号化処理
using (Aes aes = Aes.Create())
{
aes.Key = keyBytes;
// ランダムなIVの生成
byte[] ivBytes = aes.IV;
using (ICryptoTransform encryptor = aes.CreateEncryptor())
using (MemoryStream ms = new MemoryStream())
{
// 先頭にIV(16バイト)を書き込む
ms.Write(ivBytes, 0, ivBytes.Length);
// IVに続けて暗号文を書き込む
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
cs.Write(plainBytes, 0, plainBytes.Length);
cs.FlushFinalBlock();
}
// 暗号データ(IVと暗号文)をBase64に変換して返す
return Convert.ToBase64String(ms.ToArray());
}
}
}
}
}実行例
実行すると、以下のように表示されます。
暗号化した文字列:3M3U5tjIs3IiupH9TNWcyxgKp+BpFc5gvIl6FVdzlq++G8sL23etcG+0eY/s2Qzl 復号化した文字列:暗号化したい文字列
※暗号化結果は毎回ランダムなIVが生成されるため、実行のたびに異なります。
処理のポイント
・ランダムなIVを利用する
暗号化するたびにIVをランダム生成しているため、同じ文字列を同じキーで暗号化しても、毎回異なる暗号文になります。
byte[] ivBytes = aes.IV;
・IVを暗号文に付与する
復号には暗号化時のIVが必要になるため、サンプルでは暗号文の先頭へ16バイトのIVを書き込んでいます。
ms.Write(ivBytes, 0, ivBytes.Length);
・復号時はIVを取り出す
復号時はBase64をデコードし、先頭16バイトをIVとして取り出してから復号を行います。
まとめ
C#ではSystem.Security.Cryptography名前空間を利用することで、比較的簡単にAES-256による暗号化・復号化を実装できます。
今回紹介した方法では、IVを暗号データに含める一般的な実装となっているため、文字列の保存や通信時の暗号化処理にも応用できるため、ぜひ使ってみてください。



コメント