19

クライアントなどを追跡するための証明書配布システムを作成しています。

何が起こるか:

  • クライアントが CSR をサーバーに送信する
  • サーバーは証明書をチェックして署名します
  • サーバーは署名付き証明書をクライアントに送信します
  • クライアントは署名付き証明書と秘密鍵を Windows ストアに置きます。

したがって、クライアントでは次のことが起こります。

//Pseudo Server Object:
Server s = new Server();  

//Requested Certificate Name and things
X509Name name = new X509Name("CN=Client Cert, C=NL");  

//Key generation 2048bits
RsaKeyPairGenerator rkpg = new RsaKeyPairGenerator();
rkpg.Init(new KeyGenerationParameters(new SecureRandom(), 2048));
AsymmetricCipherKeyPair ackp = rkpg.GenerateKeyPair();  

//PKCS #10 Certificate Signing Request
Pkcs10CertificationRequest csr = new Pkcs10CertificationRequest("SHA1WITHRSA", name, ackp.Public, null, ackp.Private);  

//Make it a nice PEM thingie
StringBuilder sb = new StringBuilder();
PemWriter pemwrit = new PemWriter(new StringWriter(b));
pemwrit.WriteObject(csr);
pemwrit.Writer.Flush();
s.SendRequest(sb.ToSting());

わかりましたので、サーバーサイドをスキップします。サーバーが証明書に署名してクライアントに送り返すことを信じてください。それが私が行動を起こすところです。

PemReader pr = new PemReader(new StringReader(b.ToString()));
X509Certificate cert = (X509Certificate)pr.ReadObject();  

//So lets asume I saved the AsymmetricCipherKeyPair (ackp) from before
//I have now the certificate and my private key;

//first I make it a "Microsoft" x509cert.
//This however does not have a PrivateKey thats in the AsymmetricCipherKeyPair (ackp)
System.Security.Cryptography.X509Certificates.X509Certificate2 netcert = DotNetUtilities.ToX509Certificate(cert);

//So here comes the RSACryptoServerProvider:
System.Security.Cryptography.RSACryptoServiceProvider rcsp = new System.Security.Cryptography.RSACryptoServiceProvider();  

//And the privateKeyParameters
System.Security.Cryptography.RSAParameters parms = new System.Security.Cryptography.RSAParameters();  

//now I have to translate ackp.PrivateKey to parms;
RsaPrivateCrtKeyParameters BCKeyParms = ((RsaPrivateCrtKeyParameters)ackp1.Private);  

//D is the private exponent
parms.Modulus   = BCKeyParms.Modulus.ToByteArray();
parms.P         = BCKeyParms.P.ToByteArray();
parms.Q         = BCKeyParms.Q.ToByteArray();
parms.DP        = BCKeyParms.DP.ToByteArray();
parms.DQ        = BCKeyParms.DQ.ToByteArray();
parms.InverseQ  = BCKeyParms.QInv.ToByteArray();
parms.D         = BCKeyParms.Exponent.ToByteArray();
parms.Exponent  = BCKeyParms.PublicExponent.ToByteArray();  

//Now I should be able to import the RSAParameters into the RSACryptoServiceProvider
rcsp.ImportParameters(parms);  

//<em><b>not really</b></em> This breaks says "Bad Data" and not much more. I'll Post the 
//stacktrace at the end  

//I open up the windows cert store because thats where I want to save it.
//Add it and save it this works fine without the privkey.
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.MaxAllowed);
store.Add(netcert);
store.Close();

おそらく、サーバー側で何か問題が発生しているに違いないと考えているでしょう。まあそれは私も思ったことですが、この証明書からpfxファイルを作成し、手動でインポートするとうまくいきました....

どういうわけか、.NET RSA 秘密鍵と BouncyCastle RSA 秘密鍵との間に違いがあり、私はそれを指で示すことができません。

おそらく、pfx をインポートしてから、X509Store 経由でそこから秘密鍵を取得することをお勧めします。私は試した。:S そして失敗しました。ExportParameters(true)プライベートパラメーターを含めることの真の意味を理解しようとするとすぐに。「指定された状態での使用には有効なキーではありません。」と表示されます。最後に完全な例外を参照してください。

この豚を以前に殺したことがあるか、私を助けてくれる人がいるといいのですが。

***Exceptions:***

System.Security.Cryptography.CryptographicException was unhandled
  Message="Key not valid for use in specified state.\r\n"
  Source="mscorlib"
  StackTrace:
       at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
       at System.Security.Cryptography.Utils._ExportKey(SafeKeyHandle hKey, Int32 blobType, Object cspObject)
       at System.Security.Cryptography.RSACryptoServiceProvider.ExportParameters(Boolean includePrivateParameters)
  InnerException: 

***And the other one:***

System.Security.Cryptography.CryptographicException was unhandled
  Message="Bad Data.\r\n"
  Source="mscorlib"
  StackTrace:
       at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
       at System.Security.Cryptography.Utils._ImportKey(SafeProvHandle hCSP, Int32 keyNumber, CspProviderFlags flags, Object cspObject, SafeKeyHandle& hKey)
       at System.Security.Cryptography.RSACryptoServiceProvider.ImportParameters(RSAParameters parameters)
  InnerException: 
4

5 に答える 5

12

(ユーザー名からの)答えは正しい方向を指しています:padding

git からの Bouncy-castle の最新バージョンには、次のコードがあります。

public static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey)
{
   RSAParameters rp = new RSAParameters();
   rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
   rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
   rp.P = privKey.P.ToByteArrayUnsigned();
   rp.Q = privKey.Q.ToByteArrayUnsigned();
   rp.D = ConvertRSAParametersField(privKey.Exponent, rp.Modulus.Length);
   rp.DP = ConvertRSAParametersField(privKey.DP, rp.P.Length);
   rp.DQ = ConvertRSAParametersField(privKey.DQ, rp.Q.Length);
   rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.Q.Length);
   return rp;
}

private static byte[] ConvertRSAParametersField(BigInteger n, int size)
{
   byte[] bs = n.ToByteArrayUnsigned();
   if (bs.Length == size)
      return bs;
   if (bs.Length > size)
      throw new ArgumentException("Specified size too small", "size");
   byte[] padded = new byte[size];
   Array.Copy(bs, 0, padded, size - bs.Length, bs.Length);
   return padded;
}

注: このコードは、弾む城の nuget バージョン (2011) には含まれていません。または、ほとんどのコード サンプルでは、​​RSA パラメーターが単純にコピーされています。

このコードは、基本的に重要なパラメーターをコピー/貼り付けする他の場所で見られるコードとは異なり、余分なパディング手順を実行しません。

于 2015-02-07T21:37:28.787 に答える
12

参考までに、この機能を Org.BouncyCastle.Security.DotNetUtilities クラスに追加しました。まもなくリリース 1.6 になります。

于 2010-02-02T15:11:02.943 に答える
7

見つけた!

または少なくともその一部:)

まだ動作しPrivateKey.ExportToParameters(true)ませんが、これはキーが 2048 ビットだったという事実と関係があります。1024ビットに変更するとうまくいったからです。だから誰かが理由を見つけたら、私を投稿し続けてください.

それでは、また行きます。

//BouncyCastle's Key objects
RsaPrivateCrtKeyParameters rpckp = ((RsaPrivateCrtKeyParameters)ackp.Private);

//.NET RSA Key objects
System.Security.Cryptography.RSACryptoServiceProvider rcsp = new System.Security.Cryptography.RSACryptoServiceProvider();
System.Security.Cryptography.RSAParameters parms = new System.Security.Cryptography.RSAParameters();

//So the thing changed is offcourse the ToByteArrayUnsigned() instead of
//ToByteArray()
parms.Modulus   = rpckp.Modulus.ToByteArrayUnsigned();
parms.P         = rpckp.P.ToByteArrayUnsigned();
parms.Q         = rpckp.Q.ToByteArrayUnsigned();
parms.DP        = rpckp.DP.ToByteArrayUnsigned();
parms.DQ        = rpckp.DQ.ToByteArrayUnsigned();
parms.InverseQ  = rpckp.QInv.ToByteArrayUnsigned();
parms.D         = rpckp.Exponent.ToByteArrayUnsigned();
parms.Exponent  = rpckp.PublicExponent.ToByteArrayUnsigned();

//So now this now appears to work.
rcsp.ImportParameters(parms);

これで、完全な証明書をストアに追加できます:)

于 2009-06-04T14:26:22.377 に答える
4

この問題の解決策を見つけたと思います。キーパーとは関係ありませんが、X509KeyStorageFlags.Exportable フラグで作成する必要がある X509Certificate2 オブジェクトとは関係ありません。

この場合、X509Certificate2 は次の方法で作成されました。 System.Security.Cryptography.X509Certificates.X509Certificate2 netcert = DotNetUtilities.ToX509Certificate(cert);

そのため、そのメソッドの X509Certificate2 のコンストラクターにエクスポート可能フラグを渡すようにしてください。私の状況では、PFX ファイルにある秘密鍵を使用してデータに署名する必要があったため、次のように記述しなければなりませんでした。

X509KeyStorageFlags flags = X509KeyStorageFlags.Exportable;
X509Certificate2 cert = new X509Certificate2("my.pfx", "somepass", flags);

今、私はできる
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
RSAParameters rsaParam = rsa.ExportParameters(true);

HTH、

ステファン

于 2010-02-13T22:51:52.313 に答える
2

どちらのソリューションもうまくいきませんでした。しかし、次の配列のいずれかの場合、常に例外がスローされることに気付きました。

parms.Modulus   = rpckp.Modulus.ToByteArrayUnsigned();
parms.P         = rpckp.P.ToByteArrayUnsigned();
parms.Q         = rpckp.Q.ToByteArrayUnsigned();
parms.DP        = rpckp.DP.ToByteArrayUnsigned();
parms.DQ        = rpckp.DQ.ToByteArrayUnsigned();
parms.InverseQ  = rpckp.QInv.ToByteArrayUnsigned();
parms.D         = rpckp.Exponent.ToByteArrayUnsigned();
parms.Exponent  = rpckp.PublicExponent.ToByteArrayUnsigned();

隣のサイズとはサイズが異なります:

DP, DQ, InverseQ, P, Q

またはダブルサイズ:

D, Modulus

これら 2 つのグループのそれぞれについて、最大長を計算し、各配列の先頭に余分なゼロを追加して、同じ長さ (各グループで同じ) にしました。これは機能しImportParametersます。それらが同じ長さであることを確認すると思います(残念ながら、コードにアクセスできませんImportParameters。ネイティブライブラリを呼び出しているようです)。

私はBouncyCastle.Crypto.dll ver 1.7を使用しています

于 2012-05-28T16:00:56.450 に答える