LoginSignup
4
7

More than 3 years have passed since last update.

[C#]データをAESで暗号化してファイルに保存する

Posted at

やりたいこと

テキストとして読まれたくないが、ファイル保存しておきたい文字列があるときに、暗号化してファイル保存して、使うときに復号化するようなことがしたい。

やり方

AesCngというクラスを使用して、暗号化・復号化を行う。

サンプルコード

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace ConsoleApp9
{
    class Program
    {
        static void Main(string[] args)
        {
            // "あいうえお"を暗号化
            AesEncrypter.WriteAesEncryptedBytesToFile("あいうえお", @"C:\work\test.bin");

            // 暗号化したデータを読み出し復号化する
            var d = AesEncrypter.ReadAesEncryptedBytesFromFile(@"C:\work\test.bin");

            Console.WriteLine(d);
            Console.ReadLine();
        }
    }

    public class AesEncrypter
    {
        ///IV 半角16文字のランダムな文字列
        private static readonly string AesIV = @"xxxxxxxxxxxxxxxx";

        // キー 半角32文字のランダムな文字列
        // (1文字あたり8bit→8*32=256bit→キーサイズ)
        private static readonly string AesKey = @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

        // キーサイズ(bit)
        private static readonly int KeySize = 256;

        // ブロックサイズ
        private static readonly int BlockSize = 128;

        // 暗号化
        public static byte[] Encrypt(string value)
        {
            // AESオブジェクトを取得
            var aes = GetAesCng();

            // 対象の文字列をバイトデータに変換
            var byteValue = Encoding.UTF8.GetBytes(value);

            // バイトデータの長さを取得
            var byteLength = byteValue.Length;

            // 暗号化オブジェクトを取得
            var encryptor = aes.CreateEncryptor();

            // 暗号化
            return encryptor.TransformFinalBlock(byteValue, 0, byteLength);
        }

        // 復号化
        public static string Decrypt(byte[] encryptValue)
        {
            // AESオブジェクトを取得
            var aes = GetAesCng();

            // 復号化オブジェクトを取得
            var decryptor = aes.CreateDecryptor();

            // 復号化
            var decryptValue = decryptor.TransformFinalBlock(encryptValue, 0, encryptValue.Length);

            // 復号化されたバイトデータを文字列に変換
            var stringValue = Encoding.UTF8.GetString(decryptValue);

            return stringValue;
        }

        // AESオブジェクトを取得
        private static AesCng GetAesCng()
        {
            // AESオブジェクトを生成し、パラメータを設定します。
            var aes = new AesCng();
            aes.KeySize = KeySize;
            aes.BlockSize = BlockSize;
            aes.Mode = CipherMode.CBC;
            aes.IV = Encoding.UTF8.GetBytes(AesIV);
            aes.Key = Encoding.UTF8.GetBytes(AesKey);
            aes.Padding = PaddingMode.PKCS7;

            return aes;
        }

        // 文字列を暗号化してファイルに書き出す
        // targetString 暗号化したい文字列
        // keyFilePath 暗号化した文字列を書き込むファイル
        public static void WriteAesEncryptedBytesToFile(string targetString, string keyFilePath)
        {
            byte[] encrypted;

            try
            {
                encrypted = Encrypt(targetString);

                string folderPath = Path.GetDirectoryName(keyFilePath);
                if (!Directory.Exists(folderPath))
                {
                    Directory.CreateDirectory(folderPath);
                }

                using (var fs = new FileStream(keyFilePath, FileMode.Create))
                using (var bw = new BinaryWriter(fs))
                {
                    bw.Write(encrypted);
                }
            }
            catch
            {
                throw;
            }
        }

        // 暗号化されたファイルからキーを読を復号して返す
        // keyFilePath キーファイルパス
        // return : 復号化された文字列
        public static string ReadAesEncryptedBytesFromFile(string keyFilePath)
        {
            string roundtrip;

            try
            {
                using (var fs = new FileStream(keyFilePath, FileMode.Open))
                using (var br = new BinaryReader(fs))
                {
                    var encrypted = new byte[fs.Length];
                    br.Read(encrypted, 0, (int)fs.Length);

                    roundtrip = Decrypt(encrypted);
                }
            }
            catch
            {
                throw;
            }

            return roundtrip;
        }
    }
}

注意

暗号化の際、IVやキーが必要になるため、コードの中に「AesIV」「AesKey」として埋め込まれているが、キーなどの値がわかってしまうと、簡単に解読(復号)されてしまう。
.NETのコードは、ILSpyなどのツールを使うと簡単にコードが読めるようにできてしまうため、このコードをこのまま使うようなら、難読化などの対策が必要。

メモ

下記のクラスでも、同じようにAESの暗号化が行える

  • AesCryptoServiceProvider(.NET Framework3.5以降で使用できるクラス。)
  • AesManaged(.NET Framework3.5以降で使用できるクラス。これはマネージドコードで全部書かれてるらしい)
  • AesCng(.NET Framework4.6.2以降で使用できる、現段階(2019年)で新しいクラス。)

また、上記のAesCngクラスの継承元のAesクラスの、さらに継承元のSymmetricAlgorithmというクラスがある。これを継承して、AESだけでなく、DES、RC2、Rijndael、TripleDESなどの暗号化用のクラスが用意されている。

参考

AesCng Class
https://docs.microsoft.com/ja-jp/dotnet/api/system.security.cryptography.aescng?view=netframework-4.8

C#で文字列を暗号化・復号化する。
ほぼほぼこちらを参考にさせてもらってます。
https://paveway.hatenablog.com/entry/2019/04/08/csharp_encrypt

Rijndaelクラスを使ったAES暗号化
https://qiita.com/kz-rv04/items/62a56bd4cd149e36ca70

4
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
7