目次
概要
暗号化された文字列(Base64形式)を、共通の鍵(Key)と初期化ベクトル(IV)を使用して元の平文に戻す実装です。 復号処理は暗号化の逆の手順となり、CryptoStream を「読み取りモード(Read)」で使用し、暗号化されたバイトデータをストリーム経由で平文に変換してから StreamReader で文字列として取り出します。
仕様(入出力)
- 入力: 暗号化された文字列(Base64)、復号用のKey(バイト配列)、IV(バイト配列)。
- 出力: 復号された平文の文字列。
- 前提: .NET標準ライブラリ(
System.Security.Cryptography)を使用。アルゴリズムはAES。
基本の使い方
復号の流れは以下の3ステップです。
- MemoryStream: 暗号化されたバイト配列を読み込ませる(データソース)。
- CryptoStream:
Readモードを指定し、復号変換(Decryptor)を通すフィルターとして設置する。 - StreamReader: フィルターを通った結果(平文)を文字列として読み取る。
// 1. Base64をバイト配列に戻す
byte[] cipherBytes = Convert.FromBase64String(encryptedString);
// 2. ストリームを構築して読み取る
using var ms = new MemoryStream(cipherBytes);
using var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read);
using var sr = new StreamReader(cs);
// 3. 文字列取得
string plainText = sr.ReadToEnd();
コード全文
入力されたコードの誤字やクラス名の不整合を修正し、単体で動作するように整形した実装です。 KeyとIVは暗号化時と完全に一致している必要があります。
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
class Program
{
static void Main()
{
// 動作確認のため、正規の長さのKeyとIVを生成して使用します
// (本来は暗号化時に使用したものを設定します)
using var aes = Aes.Create();
aes.KeySize = 256;
aes.GenerateKey();
aes.GenerateIV();
byte[] myKey = aes.Key;
byte[] myIV = aes.IV;
// クラスの初期化
var encryptor = new StringEncrypter(myKey, myIV);
// テスト用に一度暗号化します("Hello World" を暗号化)
// ※解説のため暗号化メソッドの実装も簡易的に含めていますが、主眼はDecryptです
string original = "Hello World";
string encrypted = encryptor.Encrypt(original);
Console.WriteLine($"暗号文: {encrypted}");
// --- 復号処理の実行 ---
string decrypted = encryptor.Decrypt(encrypted);
Console.WriteLine($"復号文: {decrypted}");
}
}
public class StringEncrypter
{
public byte[] Key { get; private set; }
public byte[] IV { get; private set; }
// コンストラクタ
public StringEncrypter(byte[] key = null, byte[] iv = null)
{
using var aes = Aes.Create();
// 引数がnullなら自動生成されたものを使用、指定があればそれを使用
Key = key ?? aes.Key;
IV = iv ?? aes.IV;
}
// 復号メソッド
public string Decrypt(string encryptedText)
{
// 文字列が空なら即リターン
if (string.IsNullOrEmpty(encryptedText)) return string.Empty;
// 1. Base64文字列をバイト配列に変換
var cipherBytes = Convert.FromBase64String(encryptedText);
// 2. AESオブジェクトの準備
using var aes = Aes.Create();
aes.Key = Key;
aes.IV = IV;
// 3. 復号器(Decryptor)を作成
using var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
// 4. ストリームチェーンの構築
// MemoryStream(暗号データ) -> CryptoStream(復号) -> StreamReader(文字列化)
using var memStream = new MemoryStream(cipherBytes);
using var cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read);
using var reader = new StreamReader(cryptoStream);
// 5. 復号されたデータを最後まで読み取る
return reader.ReadToEnd();
}
// (参考) 暗号化メソッド
public string Encrypt(string plainText)
{
if (string.IsNullOrEmpty(plainText)) return string.Empty;
using var aes = Aes.Create();
using var encryptor = aes.CreateEncryptor(Key, IV);
using var ms = new MemoryStream();
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
using (var sw = new StreamWriter(cs))
{
sw.Write(plainText);
}
return Convert.ToBase64String(ms.ToArray());
}
}
カスタムポイント
- ストリームの読み書きモード: 暗号化時は
CryptoStreamMode.Writeを使いますが、復号時はあるデータソースから読み出して変換するためCryptoStreamMode.Readを使用するのが一般的です。 - エンコーディング:
StreamReaderはデフォルトでUTF-8を使用します。もしShift-JISなどで暗号化されたデータを復元する場合は、new StreamReader(cryptoStream, Encoding.GetEncoding("Shift_JIS"))のようにエンコーディングを指定する必要があります。
注意点
- パディングエラー: キーやIVが間違っている場合や、データが破損している場合、
sr.ReadToEnd()の実行時にCryptographicException: Padding is invalid...(パディングが無効です)という例外が発生します。 - Base64形式:
Decryptメソッドに渡す文字列は、有効なBase64文字列である必要があります。URL用Base64など、記号が置換されている場合は事前に標準Base64に戻す処理が必要です。
まとめ
共有キー暗号方式における文字列の復号は、暗号化データをバイナリに戻した後、CryptoStream を読み取りモードで通過させることで実現します。この際、暗号化時と完全に同一のKeyとIVを使用することが必須条件であり、これらが不一致の場合は例外が発生し、元のデータを復元することはできません。
