私はかなり長い間これを見つめていましたが、 MSDNドキュメント のおかげで、何が起こっているのか本当に理解できません。基本的に、ディスクからPFXファイルを_X509Certificate2
_にロードし、公開鍵を使用して文字列を暗号化し、秘密鍵を使用して復号化しようとしています。
なぜ困惑しているのか:RSACryptoServiceProvider
自体への参照を渡すと、暗号化/復号化が機能します。
_byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider);
string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider);
_
ただし、RSAParameter
をエクスポートして渡す場合:
_byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false));
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true));
_
...「指定された状態での使用には無効なキー」をスローします。秘密キーをRSAParameter
にエクスポートしようとしたときの例外。 PFXの生成元の証明書はエクスポート可能とマークされていることに注意してください(つまり、証明書の作成中にpeフラグを使用しました)。例外の原因は何ですか?
_ static void Main(string[] args)
{
X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test");
x.FriendlyName = "My test Cert";
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
try
{
store.Add(x);
}
finally
{
store.Close();
}
byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider);
string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider);
byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false));
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true));
}
private static byte[] EncryptRSA(string data, RSAParameters rsaParameters)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] plainData = bytConvertor.GetBytes(data);
RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider();
publicKey.ImportParameters(rsaParameters);
return publicKey.Encrypt(plainData, true);
}
private static string DecryptRSA(byte[] data, RSAParameters rsaParameters)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
RSACryptoServiceProvider privateKey = new RSACryptoServiceProvider();
privateKey.ImportParameters(rsaParameters);
byte[] deData = privateKey.Decrypt(data, true);
return bytConvertor.GetString(deData);
}
private static byte[] EncryptRSA(string data, RSACryptoServiceProvider publicKey)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] plainData = bytConvertor.GetBytes(data);
return publicKey.Encrypt(plainData, true);
}
private static string DecryptRSA(byte[] data, RSACryptoServiceProvider privateKey)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] deData = privateKey.Decrypt(data, true);
return bytConvertor.GetString(deData);
}
_
上記のコードで明確にするために、太字部分がスローされています:string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider)**.ExportParameters(true)**);
問題は、キーがエクスポート可能としてマークされていないことだと考えています。 X509Certificate2
には、X509KeyStorageFlags列挙型を取る別のコンストラクターがあります。行を置き換えてみてください:
X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test");
これとともに:
X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test", X509KeyStorageFlags.Exportable);
同様の問題に遭遇し、X509KeyStorageFlags.Exportable
は私の問題を解決しました。
私はこれらのことの正確な専門家ではありませんが、簡単なグーグルをして、これを見つけました:
http://social.msdn.Microsoft.com/Forums/en/clr/thread/4e3ada0a-bcaf-4c67-bdef-a6b15f5bfdce
「RSACryptoServiceProvider.Encrypt(byte [] rgb、bool fOAEP)メソッドに渡すバイト配列に245バイト以上ある場合、例外がスローされます。」
Googleを介してここにたどり着くが、X509Certificate2を使用しない他のユーザーについては、RSACryptoServiceProviderでToXmlStringを呼び出し、公開キーのみをロードした場合、このメッセージも表示されます。修正はこれです(最後の行に注意してください):
var rsaAlg = new RSACryptoServiceProvider();
rsaAlg.ImportParameters(rsaParameters);
var xml = rsaAlg.ToXmlString(!rsaAlg.PublicOnly);
私の知る限り、これは動作するはずであり、おそらくバグ/いくつかの制限にぶつかっています。問題の場所を特定するのに役立ついくつかの質問を次に示します。
PKCS#12(PFX)ファイルをどのように作成しましたか? CryptoAPIが気に入らないキーをいくつか見ました(珍しいRSAパラメーター)。 (念のため)別のツールを使用できますか?
PrivateKey
インスタンスをXMLにエクスポートできますか。 ToXmlString(true)
、それからこの方法でロード(インポート)しますか?
古いバージョンのフレームワークには、現在のインスタンスとは異なるサイズ(デフォルトでは1024ビット)のキーをインポートする際にいくつかの問題がありました。証明書内のRSA公開キーのサイズは?
また、これはRSAを使用してデータを暗号化する方法notであることに注意してください。生の暗号化のサイズは、使用されている公開キーによって制限されます。この制限をループすると、実際に悪いパフォーマンスしか得られません。
トリックは、対称アルゴリズム([〜#〜] aes [〜#〜]など)とtotallyを使用することですランダムキーを選択し、RSA公開キーを使用してこのキーを暗号化(ラップ)します。私の古い ブログエントリ でそのためのC#コードを見つけることができます。