バイナリデータの暗号化/復号化

未分類

バイナリデータの暗号化と復号化を行います。

以前、文字列の暗号化/復号化を以下の記事で行いました。

やりかたは文字列の時とほぼ変わりません。

バイナリデータとして今回は画像を使いますが、どんな型でも同様に処理できます。

バイナリデータの暗号化

今回は、文字列の暗号化の時に使った対象暗号化で行おうと思います。
非対称暗号化も同様の方法で行うことができると思います。

まずは、オブジェクトをバイト配列に変換する関数を作成します。

/// <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://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;

まとめ

暗号化Keyに使用している文字列は好きに変えてください。注意点は文字数がKeySizeプロパティで決まってしまうので注意です。

この記事が皆様のお役に立てたら幸いです。

タイトルとURLをコピーしました