目次
概要
.NETで文字列を暗号化するには、CryptoStream クラスを使用してデータの流れ(ストリーム)に対して暗号化処理を適用します。 文字列をそのまま暗号化することはできないため、「文字列 → バイト列 → 暗号化ストリーム → 暗号化されたバイト列」という変換プロセスを経ます。
仕様(入出力)
- 入力: 暗号化したい文字列(平文)。
- 出力: 暗号化された文字列(Base64形式)。
- 前提: AESアルゴリズムを使用。KeyとIVは自動生成または指定可能とする。
基本の使い方
ストリームを3層構造にして書き込みます。
- MemoryStream: 最終的な暗号データを受け取る場所(土台)。
- CryptoStream: データを通過させて暗号化するフィルター。
- StreamWriter: 文字列をストリームに書き込むライター。
using var ms = new MemoryStream();
using var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
using var sw = new StreamWriter(cs);
// 書き込むと、sw -> cs(暗号化) -> ms(保存) とデータが流れる
sw.Write("Secret Message");
コード全文
入力コードの不備を修正し、Aes.Create() を使用した推奨パターンに書き換えたクラスです。
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
class Program
{
static void Main()
{
// 1. 暗号化クラスのインスタンス化(KeyとIVは内部で自動生成される)
var encryptor = new StringEncrypter();
string plainText = "これはあなたにあてた秘密のメッセージです。";
// 2. 暗号化の実行
string encryptedText = encryptor.Encrypt(plainText);
// 3. 結果の表示
Console.WriteLine($"Key ({encryptor.Key.Length * 8}bit): {Convert.ToBase64String(encryptor.Key)}");
Console.WriteLine($"IV ({encryptor.IV.Length * 8}bit): {Convert.ToBase64String(encryptor.IV)}");
Console.WriteLine("--- 暗号文 (Base64) ---");
Console.WriteLine(encryptedText);
}
}
public class StringEncrypter
{
// 外部から読み取り可能なプロパティ
public byte[] Key { get; private set; }
public byte[] IV { get; private set; }
// コンストラクタ:KeyとIVがあれば使い、なければ生成する
public StringEncrypter(byte[] key = null, byte[] iv = null)
{
using var aes = Aes.Create();
// keyがnullならAESの自動生成キーを使い、指定があればそれを使う
Key = key ?? aes.Key;
IV = iv ?? aes.IV;
}
// 文字列を暗号化してBase64で返すメソッド
public string Encrypt(string plainText)
{
// 入力チェック
if (string.IsNullOrEmpty(plainText)) return string.Empty;
// 暗号化アルゴリズムのセットアップ
using var aes = Aes.Create();
aes.Key = Key;
aes.IV = IV;
// 暗号化器の作成
using var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
// ストリームの準備
using var memoryStream = new MemoryStream();
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
// 文字列書き込み用のWriterを作成
// StreamWriterが閉じられると、CryptoStreamも閉じられ、最終ブロックが書き込まれる
using (var writer = new StreamWriter(cryptoStream))
{
writer.Write(plainText);
}
// ここに来た時点でストリームは閉じられているが、MemoryStreamの内容は取得可能
byte[] encryptedBytes = memoryStream.ToArray();
return Convert.ToBase64String(encryptedBytes);
}
}
}
カスタムポイント
- Base64の理由: 暗号化されたデータ(
byte[])は、そのままでは画面表示やテキストファイル保存に適さないため、Convert.ToBase64Stringで文字列化して扱うのが一般的です。 - ストリームの順序:
StreamWriter(テキスト) →CryptoStream(暗号化) →MemoryStream(保存) の順序が重要です。逆にすると動きません。
注意点
- CryptoStreamのクローズ:
CryptoStreamは、すべてのデータを書き終えた後に必ず閉じる(Disposeする)必要があります。これにより「パディング(データ長を揃えるための埋め草)」処理などが行われ、暗号化が完了します。usingブロックを使うことで自動的に処理されます。 - Dispose後のアクセス: 通常、StreamはDispose後にアクセスできませんが、
MemoryStream.ToArray()は例外的にDispose後でもデータを取得できる仕様になっています。ただし、コードの可読性のためusingのスコープ内で行うか、上記コードのように適切にブロック分けするのが安全です。
まとめ
文字列の暗号化は「ストリームを重ねて処理する」のがC#の標準的な手法です。CreateEncryptor で作成した変換機能を CryptoStream に渡し、そこにテキストを流し込むことで、メモリ上に暗号化されたバイトデータが蓄積されます。KeyとIVはこの暗号文を元に戻すための唯一の鍵となるため、安全な場所に保管・共有する必要があります。
