I hope someone can explain to me where I have made a mistake. I always thought that when I export a certificate with a private key and import it again, the private key is stable and does not change. Especially across computers.
Now I have been proven wrong and I don't understand it.
Given a certificate Z. Which contains a private key pk. I import this certificate onto a computer C1 and onto a computer C2.
I get the parameters of the private key on both.
Result on C1:
Exponent : {1, 0, 1}
Modulus : {148, 19, 118, 153...}
P : {246, 42, 172, 195...}
Q : {153, 253, 180, 23...}
DP : {161, 179, 194, 172...}
DQ : {63, 22, 42, 14...}
InverseQ : {170, 228, 238, 93...}
D : {60, 36, 199, 168...}
Result on C2:
Exponent : {1, 0, 1}
Modulus : {148, 19, 118, 153...}
P : {246, 42, 172, 195...}
Q : {153, 253, 180, 23...}
DP : {161, 179, 194, 172...}
DQ : {63, 22, 42, 14...}
InverseQ : {170, 228, 238, 93...}
D : {0, 233, 203, 106...}
Used code:
using (var store = new X509Store(storeNameEnum, storeLocationEnum))
{
X509Certificate2Collection certificates = null;
store.Open(OpenFlags.ReadOnly);
var certificates = store.Certificates;
var cert = certificates.Cast<X509Certificate2>().Single(c => c.SubjectName.Name.ToLower().Contains(subject.ToLower()));
var rsa = cert.GetRSAPrivateKey();
var params = rsa.ExportParameters(true);
}
The D-parts of the RSA parameters differ. Why?
On computer C2 I get the same D as on C1 when I call the following line:
var params (cert.PrivateKey as RSACryptoServiceProvider).ExportParameters(true).D;
But I can't use that because I'm writing a .NetStandard library that is also used in a Net5 project.
Next I tried to read in the PFX directly from file on C2 and check the PK. The following lines give me the PK as on C1.
string pfxPassword = "pw";
Pkcs12Store pkcs12 = new Pkcs12Store(new FileStream(@"C:\tmp\cert.p12", FileMode.Open, FileAccess.Read), pfxPassword.ToArray());
var cert = pkcs12.GetCertificate("certName");
var keyEntry = pkcs12.GetKey("certName");
RSAParameters rsaParams = Org.BouncyCastle.Security.DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)keyEntry.Key);
Console.WriteLine($"=> {String.Join(" ", rsaParams.D)}");
However, when I then convert it to the certifiact in order to import it into the store, the PK changes again as it was originally on C2.
X509Certificate2 certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(Org.BouncyCastle.Security.DotNetUtilities.ToX509Certificate(cert.Certificate));
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(new CspParameters(1, "Microsoft Strong Cryptographic Provider", new Guid().ToString(), new System.Security.AccessControl.CryptoKeySecurity(), null));
csp.ImportParameters(rsaParams);
certificate.PrivateKey = csp;
Console.WriteLine($"=> {String.Join(" ", certificate.GetRSAPrivateKey().ExportParameters(true).D)}");
Apparently some computers are set to always give the same result as C1 others always give the same result as C2. But why do they deliver different results at all? What influences this behaviour?
I am grateful for any hint.