2008-05-26に
「.NET Framework のRSA署名用ハッシュアルゴリズム」を、2009-04-17に
「続 .NET Framework のRSA署名用ハッシュアルゴリズム」を投稿して来ました。間がずいぶん空いてしまいましたが.NET FrameworkによるRSA-SHA2署名が出来るようになりましたのでまとめます。
まずいまだにWindowsXPだろうがWindows7だろうが単純に証明書に関連付いている秘密鍵をRSACryptoServiceProviderクラスとして取り出しても"SHA256"や"SHA512"を指定するとそのままでは
「無効なアルゴリズムが指定されました。」と表示されます。これは標準で指定されている暗号プロバイダが
PROV_RSA_FULL(1) の為です。
PROV_RSA_FULLがサポートするのはSHA(SHA-1)までなので、RSA-SHA2署名が弾かれてしまうと言うことになります。ではRSA-SHA2署名すなわちSHA-2に対応した暗号プロバイダは何かと言えば
PROV_RSA_AES(24) となります。
PROV_RSA_AESはSHA-1とSHA-2の両方をサポートしています。署名を使いたいのに共通鍵方式のAESの名前が付く暗号プロバイダを使う必要があるのは軽い違和感がありますがまあ気にしないで使いましょう。
と言うことでではPROV_RSA_AESで証明書に関連付いた秘密鍵を使う方法をソースコードとして以下にまとめます。証明書クラス X509Certificate2 は適当な方法で用意して下さい。また以下ではエラー判定は行なっていませんし開放もちゃんとやっていませんのでエッセンスのみと考えてご覧下さい。なおC++/CLIです。
// 証明書から関連付いた秘密鍵の取得
X509Certificate2^ cert = certFind(Thumbprint); // dummy
RSACryptoServiceProvider^ rsa = nullptr;
rsa = static_cast<RSACryptoServiceProvider^>(cert->PrivateKey);
// ProviderTypeをPROV_RSA_AESとしたCspParametersの準備
CspParameters^ csp = gcnew CspParameters();
csp->ProviderName = nullptr;
csp->ProviderType = 24; // PROV_RSA_AES
csp->KeyNumber = static_cast<int>(rsa->CspKeyContainerInfo->KeyNumber);
csp->KeyContainerName = rsa->CspKeyContainerInfo->KeyContainerName;
// PROV_RSA_AESにて秘密鍵の再取得
RSACryptoServiceProvider^ rsa2 = gcnew RSACryptoServiceProvider(csp);
// 署名実行
array<Byte>^ sign = rsa2->SignData(data, HashAlgorithm::Create("SHA512"));
ご覧になっていただければお分かりと思いますがまず普通にPROV_RSA_FULLの秘密鍵を取得して、そこからKeyContainerName等のパラメーターをCspParametersに指定してProviderTypeを24のPROV_RSA_AESにして用意して、最後に鍵の再生成を行なえばOKです。ProviderNameは空でKeyNumberは指定(コピー)しないと駄目な場合があります。他にもコピーが必要なパラメーターはあるかもしれませんがこれで私が現在使っている範囲では大丈夫のようです。これで署名した署名データをOpenSSLで検証してみるとValidなので問題は無いと思います。
なお以前はXPでは駄目だろうと書いていましたが、
Windows XP SP3 以降であれば上記のコードは問題無く実行できています。もちろんWindows 7等でも動作確認しています。
2010年問題の為にRSA-2048bitとRSA-SHA2署名への移行準備が必要です。弊社のLe-XAdESライブラリも上記修正済みなので間も無くRSA-SHA2対応版をリリースする予定です。.Net FrameworkによるRSA-SHA2署名の話があまり検索しても出てこないのでご参考になれば幸いです。完結編と書いてしまったので何かミスが無ければ良いのですが(^^;
2012-03-13更新:
「CryptoAPIによるRSA-SHA2署名」を書きました。