BouncyCastle RSAPrivateKey 到 .NET RSAPrivateKey
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/949727/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
BouncyCastle RSAPrivateKey to .NET RSAPrivateKey
提问by albertjan
I'm creating a certificate distribution system to keep track of clients and stuff.
我正在创建一个证书分发系统来跟踪客户和东西。
What happens is:
发生的事情是:
- Client send CSR to Server
- Server checks and signs certificate
- Server sends Signed certificate to Client
- Client puts Signed certificate plus Private key in Windows store.
- 客户端向服务器发送 CSR
- 服务器检查并签署证书
- 服务器向客户端发送签名证书
- 客户端将签名证书和私钥放在 Windows 存储中。
So on the client this happens:
所以在客户端会发生这种情况:
//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());
Ok So I'll skip serverside Just trust me the server signs the cert and send it back to the client. Thats where I'll pick up the action.
好的,所以我将跳过服务器端相信我,服务器签署证书并将其发送回客户端。那就是我要采取行动的地方。
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();
Now you're probably thinking there must be something going wrong at the server side. Well thats what I thought too but When I made a pfx file from this cert and imported it by hand it worked fine ....
现在您可能认为服务器端一定有问题。好吧,这也是我的想法,但是当我从该证书制作 pfx 文件并手动导入它时,它运行良好....
Somehow there's a diference bewteen a .NET RSA privatekey and a BouncyCastle RSA privatekey and I can't put my finger on it.
不知何故,.NET RSA 私钥和 BouncyCastle RSA 私钥之间存在差异,我无法理解。
You will probably suggest to import the pfx and then get the private key from it via the X509Store. I tried. :S And failed. As soon as I try to ExportParameters(true)the true stands for including privateparameters. It says "Key not valid for use in specified state.". See for complete exception at the end.
您可能会建议导入 pfx,然后通过 X509Store 从中获取私钥。我试过。:S 并且失败了。一旦我尝试ExportParameters(true)真正代表包含私有参数。它说“密钥在指定状态下无效。”。请参阅最后的完整异常。
I hope some of you have slain this pig before or might be able to help me.
我希望你们中的一些人以前杀过这只猪,或者可以帮助我。
***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:
采纳答案by JB. With Monica.
The answer (from username) points to the right direction: padding.
答案(来自用户名)指向正确的方向:padding。
Bouncy-castle's latest version from git has the following code:
Bouncy-castle 来自 git 的最新版本有以下代码:
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;
}
nb: This code in not in the nuget version (2011) of bouncy castle, or in most code samples were RSA parameters are simply copied.
注意:此代码不在充气城堡的 nuget 版本(2011)中,或者在大多数代码示例中只是简单地复制了 RSA 参数。
This code is different from the code you can see anywhere else which basically copy/paste the key parameters, and does not perform the extra padding step.
此代码与您在其他任何地方都可以看到的代码不同,这些代码基本上是复制/粘贴关键参数,并且不执行额外的填充步骤。
回答by Peter Dettman
FYI, I've added this functionality to the Org.BouncyCastle.Security.DotNetUtilities class; it will be in release 1.6, due soon.
仅供参考,我已将此功能添加到 Org.BouncyCastle.Security.DotNetUtilities 类;它将在 1.6 版中发布,即将发布。
回答by albertjan
I found it!
我找到了!
Or atleast part of it :)
或者至少是它的一部分:)
As for the PrivateKey.ExportToParameters(true)Still doens't work but this has something todo with the fact that the key was 2048 bit. Because when I changed it to 1024bit it did work. So if anyone ever finds out why keep me posted.
至于PrivateKey.ExportToParameters(true)Still 不起作用,但这与密钥是 2048 位的事实有关。因为当我将其更改为 1024 位时,它确实起作用了。所以如果有人知道为什么要通知我。
So here we go again.
所以我们又来了。
//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);
So now I can add the complete Certificate to my store :)
所以现在我可以将完整的证书添加到我的商店:)
回答by stefann
I think I found the solution to this problem. It has nothing to do with the key per, but rather with the X509Certificate2 object which must be created with the X509KeyStorageFlags.Exportable flag.
我想我找到了解决这个问题的方法。它与密钥无关,而是与必须使用 X509KeyStorageFlags.Exportable 标志创建的 X509Certificate2 对象有关。
In this case your X509Certificate2 was created by this method:
System.Security.Cryptography.X509Certificates.X509Certificate2 netcert = DotNetUtilities.ToX509Certificate(cert);
在这种情况下,您的 X509Certificate2 是通过以下方法创建的:
System.Security.Cryptography.X509Certificates.X509Certificate2 netcert = DotNetUtilities.ToX509Certificate(cert);
So make sure you pass the exportable flag in the constructor of the X509Certificate2 in that method. I my situation I needed to sign some data with a private key located in a PFX file so I had to write this:
因此,请确保在该方法的 X509Certificate2 的构造函数中传递可导出标志。我的情况是我需要使用位于 PFX 文件中的私钥对一些数据进行签名,因此我必须这样写:
X509KeyStorageFlags flags = X509KeyStorageFlags.Exportable;
X509Certificate2 cert = new X509Certificate2("my.pfx", "somepass", flags);
X509KeyStorageFlags flags = X509KeyStorageFlags.Exportable;
X509Certificate2 cert = new X509Certificate2("my.pfx", "somepass", flags);
Now I can doRSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
RSAParameters rsaParam = rsa.ExportParameters(true);
现在我可以做RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
RSAParameters rsaParam = rsa.ExportParameters(true);
HTH,
哈,
Stefan
斯特凡
回答by username
Neither of the solutions worked for me. But I've noticed that the exception is always thrown when one of the following arrays:
这两种解决方案都不适合我。但我注意到,当以下数组之一时,总是抛出异常:
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();
has a different size then its neighbor:
与它的邻居有不同的大小:
DP, DQ, InverseQ, P, Q
or double sized:
或双倍尺寸:
D, Modulus
For each of these two groups I have calculated the max length and added extra zeroes at the beginning of each array to make them the same length (the same for each group).
This works, I suppose that ImportParameterschecks that they are of the same length (unfortunately I don't have an access to the ImportParameterscode, it seems that it calls some native library).
对于这两组中的每一组,我都计算了最大长度并在每个数组的开头添加了额外的零,以使它们具有相同的长度(每组相同)。这有效,我想ImportParameters检查它们的长度是否相同(不幸的是我无法访问ImportParameters代码,它似乎调用了一些本机库)。
I'm using BouncyCastle.Crypto.dll ver 1.7
我正在使用 BouncyCastle.Crypto.dll 1.7 版

