#System.Security.Cryptography
.NET(や、.NET Core, .Net Framework)には、System.Security.Cryptographyという名前空間があります。
ドキュメントを見てみると、大量のクラスが出てきて圧倒されます。暗号を知らない人が暗号化しようとしたときに、どれを選ぶのかよくわからないこともあるかと思います。
#暗号の分類
と、クラスの説明をする前に暗号を分類しておきましょう。
大きくわけると、
- 共通鍵暗号
- 公開鍵暗号
- ハッシュ関数
があります。
##共通鍵暗号
いわゆる、暗号としてイメージするものはこれです。暗号をかけるための鍵を双方で共有し、決まった方法で暗号化、あるいはその逆手順の復号を行います。
代表的なアルゴリズムに、米国標準(そして、世界でのデファクトスタンダードである) - AES
や、それの前世代の - DES
が挙げられます。
##公開鍵暗号
暗号をかけるための鍵(暗号化鍵)と復号のための鍵(復号鍵)が異なるものととらえると理解がしやすいと思います。暗号をかけるための鍵は暗号化できますが、それで作った暗号文を復号できません。
この性質から、暗号化鍵の配布が容易であるという利点があります。
また、電子署名に使われることがあります。
代表的なアルゴリズムでは、デファクトスタンダードである - RSA
- DH(ElGammal)
- ECDH(楕円ElGamal)
や、米国標準である - DSA
- ECDSA
などが挙げられます。
##ハッシュ関数
ハッシュ関数は厳密には暗号ではないのですが、セキュリティや暗号に利用されるため、ここで触れます。
ハッシュ関数とは、任意長のデータを決まった大きさのデータ(ハッシュ値)に変換する関数です。
暗号の文脈で使われるときはさらに、「同じハッシュ値を出す入力を探すのが困難である」という性質が望まれます。
もちろん、ハッシュ値は決まった大きさであるにもかかわらず入力は任意長のデータであるため、必ず同じハッシュ値を出す入力は存在します。(これを衝突という)
このハッシュ関数は、改ざん検出によく使われます。
代表的なアルゴリズムには、 - MD5
- SHA1
- SHA256
- SHA384
- SHA512
- SHA3
などが挙げられます。
#まず何を使えばいいのか
決まった鍵でデータを秘匿したいという目的に使う場合、共通鍵暗号を使うのが正解です。なぜなら共通鍵暗号は公開鍵暗号より速いからです。逆に、鍵を共有する手段がないのであれば、公開鍵暗号を使わざるを得ません。しかし、公開鍵暗号は遅いので、公開鍵暗号でデータを暗号化するのではなく、ランダムに生成した鍵を暗号化し、その鍵でデータを暗号化するといった使い方をします。この使い方をハイブリッド暗号と言います。
#共通鍵暗号に何を使うのか
ざっと、System.Security.Cryptography名前空間にある共通鍵暗号アルゴリズムは、
- AES
- DES
- RC2
- Rijndael
- TripleDES
の5種類になります。ただし、Rijndaelは事実上AESと同じ。RC2とDESは既に解読可能、TripleDESも推奨されないということで、結論としては、AES一択ということになります。
AESにかかわるクラスは、
- Aes
- AesCng
- AesCryptoServiceProvider
- AesManaged
の4つになります。このうち、一番上のAesは抽象基底クラスですので使用できません。残りの3つは歴史的経緯で実現方法が違います。
##AesCng
一番最初ですが、これを選ぶのが正解です。Windows用のCryptoAPI:Next Generation(CNG)のAESを呼び出す形で実装されています。
##AesCryptoServiceProvider
これは、CNGがリリースされる前のCryptoAPI(CAPI)のAESを呼び出す形で実装されています。.NET 4.6以前の開発に使うという理由がない限りは推奨しません。
##AesManaged
.NETで記述されたAESです。どうしても、.NET上で完結したいという理由でなければお勧めしません。
Windowsセキュリティポリシーには、FIPS準拠アルゴリズムのみを使用するというオプションがあります(レジストリで設定する)。このオプションが設定されているとAesManagedは(AESはFIPS準拠アルゴリズムであるにもかかわらず)CryptographicException例外を吐きます。これがお勧めしない理由です。
#公開鍵暗号に何を使うのか
ざっと、System.Security.Cryptography名前空間にある公開鍵暗号アルゴリズムは、
- RSA
- DSA
- ECDH
- ECDSA
の4つです。しかし、DSAとECDSAは電子署名専用アルゴリズムですので、鍵の暗号化には使用できません。そうすると、RSAとECDHの二択になりますが、鍵のサイズがたかだか256ビットであり、RSAは暗号文サイズが大きくなるという性質からお勧めしません。つまり、ECDHを推奨します。
ECDHを取り扱うクラスは、
- ECDiffieHellman
- ECDiffieHellmanCng
の2つですが、ECDiffieHellmanは抽象基底クラスですので使用できません。というわけで、ECDiffieHellmanCngの一択となります。また、鍵サイズが選べますが、これはAESの鍵サイズの2倍__以上__のサイズにしてください。なぜ2倍なのかという話は長くなるので、ここでは省略します。ただし、どうも、Xamarinに入ってないっぽいので、その場合は、RSACngを使ってください。RSAでの鍵サイズの選択はもっと長くなるのでその2以降で記述します。
#ハッシュ関数に何を使うのか、
ざっと、System.Security.Cryptography名前空間にあるハッシュ関数アルゴリズムは、
- MD5
- SHA1
- SHA256
- SHA384
- SHA512
になります。用途にもよりますが、MD5は衝突が容易に発見できるので推奨しません。SHA1以降はどれも使えますが、ハッシュ関数を何に使うかによって選択を変えてください。
なお、それぞれ抽象基底クラス、CryptoServiceProviderで呼び出すものとManagedクラスがあります。Windowsのみで使うなら、CryptoServiceProviderを、Xamarinで使うならManagedクラスがよいと思います。上手くどれを選べばいいというのが断言できないのですが、.NET 5になれば、全部CryptoServiceProviderを使用するべきだと思います。これは、Managedクラスは上記のCryptographicException例外を吐く可能性があるという理由からです。