C#を使って秘密鍵と公開鍵で暗号・復号

題記の通り、C#を使用した暗号化・復号化の実装。

なるべく簡単に暗号化と復号化の機能を使いたいな、と思って実装してみた。

参考にしたのはMSの以下のサイト。
https://docs.microsoft.com/ja-jp/dotnet/standard/security/encrypting-data

環境はVS2019で .NET Core 3.1を使用。

イメージとしては、以下のようなやり取りを想定してコーディング。

(1) サーバーが秘密鍵と公開鍵を発行する。
(2) クライアントに文字列で公開鍵情報を渡す。
(3) クライアントは公開鍵情報を使ってデータを暗号化、サーバーに送付。
(4) サーバーは秘密鍵情報を使ってデータを復号。

証明書とか使えばいいのかもしれないが、そこら辺の知識はあまりないのでコードだけですべてを完結させたかった････

<details><summary>ソースは以下。(クリックするとソースが表示されます)</summary><div>

```C#
namespace RsaConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            // 暗号化したい文字列をバイト配列に変換
            string encryptWord = "冷やし中華ｧァ～";
            var encByte = Encoding.Unicode.GetBytes(encryptWord);

            // 秘密鍵と公開鍵を生成
            RSA rsa = RSA.Create();

            // 鍵情報を保存
            var publicKey = rsa.ToXmlString(false);
            var privateKey = rsa.ToXmlString(true);

            // 公開鍵情報の文字列からオブジェクトを復元
            byte[] encryptedByte;
            using (RSA encRsa = RSA.Create())
            {
                encRsa.FromXmlString(publicKey);
                encryptedByte = encRsa.Encrypt(encByte, RSAEncryptionPadding.Pkcs1);
            }

            // 暗号化したバイトデータを16進数文字列に変換
            var encByteToString = BitConverter.ToString(encryptedByte);
            Console.WriteLine($"Encrypt: {encByteToString}");

            // 
            // 上記の方法で生成された16進数文字列を外部から受信したと仮定して、
            // 秘密鍵を使って復元する
            //

            // 送信されてきた文字列をバイト配列に変換
            var encStrToBytes = encByteToString.Split('-').Select(r => Convert.ToByte(r, 16)).ToArray();
            byte[] decryptedByte;

            // 秘密鍵情報の文字列からオブジェクトを復元し、復号
            using (RSA decRsa = RSA.Create())
            {
                decRsa.FromXmlString(privateKey);
                decryptedByte = decRsa.Decrypt(encStrToBytes, RSAEncryptionPadding.Pkcs1);
            }

            var decryptedString = Encoding.Unicode.GetString(decryptedByte);

            Console.WriteLine($"Decrypt: {decryptedString}");

            // 試しにテキトーな鍵で復号してみる
            var invalidDec = string.Empty;
            try
            {
                using (RSA invalidRsa = RSA.Create())
                {
                    decryptedByte = invalidRsa.Decrypt(encStrToBytes, RSAEncryptionPadding.Pkcs1);
                }
            }
            catch
            {
                Console.WriteLine("Failed to decrypt.");
            }

            return;
        }
    }
}
```

</div></details>

出力はこんな感じ。

```Console
Encrypt: 6F-5B-B7-F8-3D-C9-00-23-BE-84-29-82-56-7E-BE-7B-79-E8-BB-5F-76-2B-03-A8-49-1C-76-FB-49-56-04-1E-8A-CA-AD-5C-57-F7-21-CC-17-FE-04-C8-FD-F9-D5-0D-7B-2B-2B-3A-34-A0-AE-5D-82-D3-1E-78-55-22-06-DB-C2-AA-99-A8-D1-52-6A-27-0F-A6-86-D9-CA-DA-78-6F-00-D2-6C-1C-51-F2-88-FA-CC-F8-CD-B0-0D-8E-D1-55-89-53-43-4A-92-25-DD-13-55-8E-F4-95-5D-6E-B3-95-89-3A-DE-6A-A1-A5-89-A9-1F-3F-30-6A-04-D0-B0-4E-CF-CA-6E-03-D9-D7-30-2C-48-31-8A-34-4F-0D-5E-1A-19-CF-61-52-A0-AB-20-C0-69-B6-DE-CE-C7-6C-59-C4-C0-64-2A-05-7B-07-96-A0-77-DD-F3-5E-D0-1C-E8-76-3D-A7-6B-51-8C-BC-50-A9-9D-03-31-1C-36-97-DB-F8-63-55-4F-2C-85-FA-C0-03-C6-C8-BE-93-11-DA-67-CD-55-3E-E0-D3-BC-13-FF-26-FD-A6-F2-87-5E-31-01-C0-4C-9D-6F-6A-45-8F-34-A5-07-6B-C3-A7-19-48-77-89-4E-9F-A5-9C-F2-61-83-CE-3E-66-59-47-56-10-F3-03
Decrypt: 冷やし中華ｧァ～
Failed to decrypt.
```

ちゃんと復号できてるし、テキトーな鍵じゃ復号できてませんね(当たり前か)

あとは、メッセージのハッシュ送付とかも一緒にやれば、通信相手の検証もまとめてできるということか～。
そこまでやればまぁまぁ安全ですね～。

以上！