我希望有人能给我解释一下我哪里弄错了,我一直以为用私钥导出证书,再导入,私钥是稳定的,不会发生变化。尤其是跨电脑。
现在我被证明是错的,我不明白。
给定一个证书Z。其中包含一个私钥pk。我将此证书导入计算机C1和计算机C2。
我在两者上获取私钥的参数。
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...}
使用代码:
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);
}
RSA参数的D部分不同。为什么?
在计算机C2上,当我调用以下行时,我得到与C1相同的D:
var params (cert.PrivateKey as RSACryptoServiceProvider).ExportParameters(true).D;
但是我不能使用它,因为我正在编写一个。NetStandard库也用于Net5项目。
接下来,我尝试直接从C2上的文件中读取PFX并检查PK。下面的行给了我和C1一样的PK。
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)}");
但是,当我将其转换为证书以便将其导入商店时,PK再次更改,因为它最初在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)}");
显然,有些计算机总是设置为给出与C1相同的结果,而其他计算机总是给出与C2相同的结果。但是为什么它们会给出不同的结果呢?是什么影响了这种行为?
我感谢任何暗示。
基本上,D
值无关紧要,您正在看到这样做的结果。
"你刚才是说D
值无关紧要吗?RSA不是基于m==modpow(modpow(m, e,n),d,n)
吗?"
是的,是的。但是中国剩余定理为modpow(m, d,n)
提供了更有效的实现,所以没有人真正关心D
。
另一件事是,当导入一个RSA私钥时,你有几个选择: 1)验证n==(p*q)和d/dp/dq/qInv在给定n/e/p/q的情况下是否有意义,如果没有,则失败,2)根据信念导入密钥,处理不一致的后果(垃圾输入,垃圾输出),3)做(1)但修复任何不正确的数据。
好的,所以我们有了值为什么会改变的前提(策略(3)),但是它们为什么会改变呢?
因为D
至少有两种不同的常见答案。(“D不是独一无二的吗?”不。“你不是说D无关紧要吗?”好吧,所以它在计算CRT参数时很重要,那么它就不再重要了。)
最初的RSA论文将D定义为E模的模乘逆,即N的欧拉函数。欧拉函数的常用符号是希腊字母phi。许多聪明人后来将这一说法改为D是e模的模乘逆,即N的卡迈克尔函数。卡迈克尔函数的常用符号是希腊字母lambda。
不同之处在于正方形对矩形。所有D-phi值都适用于RSA,因为e*D-phi===1(mod lambda(N))
。由于所有D-lambda值也适用于RSA,但不符合e*D-lambda===1(mod phi(N))
,因此公式被重写了。
好吧,这是背景,发生了什么?
所以,我的猜测是C1和C2运行在不同的操作系统上(或者同一OS的不同版本)。
https://github.com/dotnet/runtime/commit/700a07cae19fe64649c2fb4c6c10e6b9aa85dc29展示了我们如何在NET的测试套件中处理它。对于应用程序代码,我的建议是只信任系统。