【C#】共通鍵暗号(AES)で文字列を暗号化する方法

目次

概要

.NETで文字列を暗号化するには、CryptoStream クラスを使用してデータの流れ(ストリーム)に対して暗号化処理を適用します。 文字列をそのまま暗号化することはできないため、「文字列 → バイト列 → 暗号化ストリーム → 暗号化されたバイト列」という変換プロセスを経ます。

仕様(入出力)

  • 入力: 暗号化したい文字列(平文)。
  • 出力: 暗号化された文字列(Base64形式)。
  • 前提: AESアルゴリズムを使用。KeyとIVは自動生成または指定可能とする。

基本の使い方

ストリームを3層構造にして書き込みます。

  1. MemoryStream: 最終的な暗号データを受け取る場所(土台)。
  2. CryptoStream: データを通過させて暗号化するフィルター。
  3. 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 (保存) の順序が重要です。逆にすると動きません。

注意点

  1. CryptoStreamのクローズ: CryptoStream は、すべてのデータを書き終えた後に必ず閉じる(Disposeする)必要があります。これにより「パディング(データ長を揃えるための埋め草)」処理などが行われ、暗号化が完了します。using ブロックを使うことで自動的に処理されます。
  2. Dispose後のアクセス: 通常、StreamはDispose後にアクセスできませんが、MemoryStream.ToArray() は例外的にDispose後でもデータを取得できる仕様になっています。ただし、コードの可読性のため using のスコープ内で行うか、上記コードのように適切にブロック分けするのが安全です。

まとめ

文字列の暗号化は「ストリームを重ねて処理する」のがC#の標準的な手法です。CreateEncryptor で作成した変換機能を CryptoStream に渡し、そこにテキストを流し込むことで、メモリ上に暗号化されたバイトデータが蓄積されます。KeyとIVはこの暗号文を元に戻すための唯一の鍵となるため、安全な場所に保管・共有する必要があります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次