バイナリデータの暗号化と復号化を行います。
以前、文字列の暗号化/復号化を以下の記事で行いました。
やりかたは文字列の時とほぼ変わりません。
バイナリデータとして今回は画像を使いますが、どんな型でも同様に処理できます。
バイナリデータの暗号化
今回は、文字列の暗号化の時に使った対象暗号化で行おうと思います。
非対称暗号化も同様の方法で行うことができると思います。
まずは、オブジェクトをバイト配列に変換する関数を作成します。
/// <summary>
/// オブジェクトをバイト配列に変換
/// </summary>
/// <param name="obj">バイト配列に変換するオブジェクト</param>
/// <returns>バイト配列</returns>
public byte[] ObjectToByteArray(object obj)
{
//オブジェクトがnullの場合は、処理しないでnullを返す
if (obj == null) return null;
//byte配列にする
BinaryFormatter bf = new BinaryFormatter();
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
次にバイト配列化したデータを暗号化するための関数を作成します。
/// <summary>
/// 対称鍵暗号を使って文字列を暗号化する
/// </summary>
/// <param name="bytes">暗号化するバイト配列</param>
/// <param name="key">対称アルゴリズムの共有鍵</param>
/// <param name="iv">(out)対称アルゴリズムの初期ベクター</param>
/// <returns>暗号化された文字列</returns>
public static string EncryptAesCng(byte[] bytes, string key, out string iv)
{
//Advanced Encryption Standard (AES) アルゴリズムの Cryptography Next Generation (CNG) 実装
using (AesCng aes = new AesCng())
{
aes.BlockSize = 128; //ブロックサイズ(Bit)
aes.KeySize = 128; //キーサイズ(Bit)・・・有効なキーサイズは 128、192、および 256 ビット
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.GenerateIV(); //初期ベクトル生成
iv = System.Convert.ToBase64String(aes.IV);
aes.Key = Encoding.UTF8.GetBytes(key); //暗号化キーをセット
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
//暗号化処理
byte[] encrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
return (System.Convert.ToBase64String(encrypted));
}
}
上記で作成した関数を使って、画像ファイルを暗号化するコーディングしてみます。
string iv; //初期ベクトル
string key = "8nCcT7wVXdRWicxz"; //KeySize = 128なので16文字
//画像ファイルの読込
Image bitmap = System.Drawing.Bitmap.FromFile(@"D:\Pictures\sample-a.jpg");
//画面に表示
this.picSrc.Image = bitmap;
//バイト配列の変換
byte[] b = ObjectToByteArray(bitmap);
//暗号化
string encrypt = EncryptAesCng(b, key, out iv);
//出力
this.txtBase64.Text = encrypt;
this.txtVec.Text = iv;
実際に実行した結果が以下の赤枠内になります。
![](https://csharp.nomux2.net/wp-content/uploads/2023/05/image-6.png)
画像引用:ぶたどん様
https://www.ac-illust.com/main/detail.php?id=23847104&word=%E5%A4%A7%E3%81%8D%E3%81%AA%E8%88%B9%EF%BC%BF%E3%82%A2%E3%83%8B%E3%83%A1
大きな船_アニメ
バイナリデータの復号化
続いて暗号化したバイナリデータを文字列に戻す方法を説明します。
復号化するには、暗号化したときの工程の逆を行うようにします。
まず暗号化文字列を復号化しバイト配列に戻す関数を作成します。
/// <summary>
/// 対称鍵暗号を使って暗号文を復号する
/// </summary>
/// <param name="cipher">暗号化された文字列</param>
/// <param name="iv">対称アルゴリズムの初期ベクター</param>
/// <param name="key">対称アルゴリズムの共有鍵</param>
/// <returns>復号された文字列</returns>
public static byte[] DecryptAesCng(string cipher, string iv, string key)
{
using (AesCng aes = new AesCng())
{
aes.BlockSize = 128;
aes.KeySize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
//初期ベクトルと共通鍵をセット
aes.IV = System.Convert.FromBase64String(iv);
aes.Key = Encoding.UTF8.GetBytes(key);
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
//暗号化文字列をバイト配列に戻す
byte[] encypted = System.Convert.FromBase64String(cipher);
//復号化処理
byte[] plains = decryptor.TransformFinalBlock(encypted, 0, encypted.Length);
//バイト配列を文字列に戻す
return plains;
}
}
復号化して取得したバイト配列を指定した型に戻します。
/// <summary>
/// バイト配列を指定の型に変換
/// </summary>
/// <param name="bytes">バイト配列</param>
/// <returns>オブジェクト</returns>
public T ByteArrayToObject<T>(byte[] bytes)
{
//オブジェクトがnullの場合は、処理しないで返す。
if (bytes == null) return default(T);
//byte配列からオブジェクトに戻す
BinaryFormatter bf = new BinaryFormatter();
using (System.IO.MemoryStream ms = new System.IO.MemoryStream(bytes))
{
return (T)bf.Deserialize(ms);
}
}
実際に実行してみます。
string iv = this.txtVec.Text; //初期ベクトル(テキストボックスから取得しています。)
string key = "8nCcT7wVXdRWicxz"; //KeySize = 128なので16文字
//Base64からデコード
byte[] decode = DecryptAesCng(encrypt, iv, key);
//Imageに戻す
Image img = ByteArrayToObject<Image>(decode);
//画面に表示
this.picdest.Image = img;
![](https://csharp.nomux2.net/wp-content/uploads/2023/05/image-7.png)
まとめ
暗号化Keyに使用している文字列は好きに変えてください。注意点は文字数がKeySizeプロパティで決まってしまうので注意です。
この記事が皆様のお役に立てたら幸いです。