LoginSignup
2
5

More than 3 years have passed since last update.

AES を使って暗号化・復号化をする

Last updated at Posted at 2021-05-17

AES は共通鍵のアルゴリズムで、他の共通鍵の暗号化方式と比べて強力なようです。
今回は、AESS の暗号化・複号化のライブラリの使い方を理解してみたいと思います。

暗号化と復号化のロジック

基本的にとても簡単です。 AesManaged というクラスか、AesCryptoServiceProvider というクラスが存在するので、そのクラスを使って、暗号化、復号化を行います。このライブラリを使う上で重要なコンセプトは、暗号化の Key と、IV (Initialization Vector)というパラメータです。この二つを理解する必要があります。

Key

Key は暗号化を行うときの共通鍵です。このライブラリのキーサイズを見てみると、256 bit です。AesManaged クラスは、初期化した際に、KeyIV は自動作成されるようです。個別に GenerateKey() というメソッドも用意されています。その中のコードを見てみましょう。想像のとり、ランダムな数字のジェネレーターでバイト配列を作成しています。

public sealed override void GenerateKey()
{
    byte[] key = new byte[KeySize / BitsPerByte];
    RandomNumberGenerator.Fill(key);
    Key = key;
}

最終的に internal sealed partial class RandmNumberGeneratorImplementation で実装されているので、外からはうかがい知ることができません。これと似たような実装を外部ですると、次のようになるでしょう。 RNGCryptoServiceProviderはまさにランダムの数字を生成してくれますので、とても良い感じです。GetBytes メソッドで、バイト配列を埋めるところも、結構実装が似ていますね。ちなみに、実装を追っていくと、結局 RandomNumberGeneratorImplementation にたどり着いたので、多分実装は同じですね。私のマシンでは、new byte[16] でないと、256 bit になりませんでしたので、こうしています。

        private static string GenerateKey()
        {
            var buffer = new byte[32]; 
            using (var rng = new RNGCryptoServiceProvider())
            {
                rng.GetBytes(buffer);
                return BitConverter.ToString(buffer).Replace("-", string.Empty);
            }
        }

IV

IV は (Initialization vector) の略です。リンクをした公式ドキュメントには記述してありますが、ASEのアルゴリズムの初期のトランスフォーメーションの初期値として与えられます。ASEのアルゴリズムで、変換を行っていく過程で、前に変換をした値を使うのですが、1回目の時にはその値がありません。ですので、作成して与える必要があります。これが、IVの概要です。細かいことはよく知りませんが、この記事を理解すると、わかるようになると思います。

実装例

ほとんど公式にあるサンプルそのままですが、出力がどんな感じになるのか試しています。ライブラリが勝手に暗号化・復号化してくれうるので楽ですね。

        static void Main(string[] args)
        {
            // AesCryptoServiceProivder を使うときは  CryptoConfig を使うと良い。
            // CryptoConfig cryptoConfig = new CryptoConfig();
            // var aes = (AesCryptoServiceProvider)CryptoConfig.CreateFromName("AES");

            string original = "Here is some data encrypt!";
            using (AesManaged myAes = new AesManaged())
            {
                Console.WriteLine($"KeySize: {myAes.KeySize}");
                Console.WriteLine($"KEY (original) {generatedKey}");
                Console.WriteLine($"KEY: {Convert.ToBase64String(myAes.Key)}");
                Console.WriteLine($"IV: {Convert.ToBase64String(myAes.IV)}");
                byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV);
                string roundtrip = DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV);
                Console.WriteLine($"Original: {original}");
                Console.WriteLine($"Encrypted: {Encoding.ASCII.GetString(encrypted)}");
                Console.Write($"Encrypted (bytes) :");
                foreach (var i in encrypted)
                {
                    Console.Write($"{ConvertToHex(i)}:");
                }
                Console.WriteLine();
                Console.WriteLine($"Encrypted (base64): {Convert.ToBase64String(encrypted)}");
                Console.WriteLine($"Round Trip: {roundtrip}");
            }
        }

        static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
        {
            byte[] encrypted;
            using (AesManaged aesAlg = new AesManaged())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;

                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(plainText);
                        }

                        encrypted = msEncrypt.ToArray();
                    }
                }
            }

            return encrypted;
        }

        static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
        {
            string plaintext = null;
            using (AesManaged aesAlg = new AesManaged())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }

            return plaintext;
        }
    }

すべてのコード

自分がいろいろ試したコードを含めています。キーを自分でジェネレートした例、ライブラリを使ってジェネレートした例

       static void Main(string[] args)
        {
            // CryptoConfig cryptoConfig = new CryptoConfig();
            // var aes = (AesCryptoServiceProvider)CryptoConfig.CreateFromName("AES");
            var generatedKey = GenerateKey();
            Console.WriteLine($"Key Length: {generatedKey.Length}");
            string original = "Here is some data encrypt!";
            using (AesManaged myAes = new AesManaged())
            {
                //         public sealed override void GenerateKey()
                //{
                //    byte[] key = new byte[KeySize / BitsPerByte];
                //    RandomNumberGenerator.Fill(key);
                //    Key = key;
                //}
                myAes.GenerateKey();
                Console.WriteLine($"KeySize: {myAes.KeySize}");

                myAes.Key = GetKeyBytes(generatedKey);
                Console.WriteLine($"KEY (original) {generatedKey}");
                Console.WriteLine($"KEY: {Convert.ToBase64String(myAes.Key)}");
                Console.WriteLine($"IV: {Convert.ToBase64String(myAes.IV)}");
                byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV);
                string roundtrip = DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV);
                Console.WriteLine($"Original: {original}");
                Console.WriteLine($"Encrypted: {Encoding.ASCII.GetString(encrypted)}");
                Console.Write($"Encrypted (bytes) :");
                foreach (var i in encrypted)
                {
                    Console.Write($"{ConvertToHex(i)}:");
                }
                Console.WriteLine();
                Console.WriteLine($"Encrypted (base64): {Convert.ToBase64String(encrypted)}");
                Console.WriteLine($"Round Trip: {roundtrip}");
            }
        }

        // Make the key as 256-bit with the HEX string format
        private static string GenerateKey()
        {
            var buffer = new byte[32]; 
            using (var rng = new RNGCryptoServiceProvider())
            {
                rng.GetBytes(buffer);
                return BitConverter.ToString(buffer).Replace("-", string.Empty);
            }
        }

        public static byte[] GetKeyBytes(string hexOrBase64)
        {
            // only support 32 bytes (256 bits) key length
            if (hexOrBase64.Length == 64)
            {
                return Enumerable.Range(0, hexOrBase64.Length)
                    .Where(x => x % 2 == 0)
                    .Select(x => Convert.ToByte(hexOrBase64.Substring(x, 2), 16))
                    .ToArray();
            }

            return Convert.FromBase64String(hexOrBase64);
        }

        static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
        {
            byte[] encrypted;
            using (AesManaged aesAlg = new AesManaged())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;

                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(plainText);
                        }

                        encrypted = msEncrypt.ToArray();
                    }
                }
            }

            return encrypted;
        }

        static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
        {
            string plaintext = null;
            using (AesManaged aesAlg = new AesManaged())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }

            return plaintext;
        }
    }

実行結果

Key Length: 32
KeySize: 256
KEY (original) 8051E074A3DBAB6A6134F2E267C1FBF3
KEY: 8051E074A3DBAB6A6134F2E267C1FBF3
IV: 4egGQBFkFmiLBhfMvkrtxQ==
Original: Here is some data encrypt!
Encrypted: ?↓?ah→?◄6E??X?K.7*.Wqo???☺?
Encrypted (bytes) :A0:1B:9C:19:A4:94:08:07:61:68:1A:EB:11:36:45:B5:B0:58:94:4B:2E:37:2A:2E:57:71:6F:92:D2:F7:01:88:
Encrypted (base64): oBucGaSUCAdhaBrrETZFtbBYlEsuNyouV3FvktL3AYg=
Round Trip: Here is some data encrypt!

Resource

概要はこちらがわかりやすいです。
https://it-trend.jp/encryption/article/64-0070

2
5
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
2
5