提问者:小点点

根据访问证书私钥的方式更改RSA的D-参数


我希望有人能给我解释一下我哪里弄错了,我一直以为用私钥导出证书,再导入,私钥是稳定的,不会发生变化。尤其是跨电脑。

现在我被证明是错的,我不明白。

给定一个证书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相同的结果。但是为什么它们会给出不同的结果呢?是什么影响了这种行为?

我感谢任何暗示。


共1个答案

匿名用户

基本上,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)),因此公式被重写了。

好吧,这是背景,发生了什么?

  • Windows CAPI(在Windows上支持RSACryptoServiceProvider,在.NETFramework上支持RSA. Create())使用lambda生成密钥,但在导入/导出时保留D值。
  • OpenSSL(RSA类Linux)使用phi生成密钥,但在导入/导出时保留D值。
  • Windows CNG(在Windows上启用RSACng,在Windows上启用RSA. Create()。NET5/。NET核心)使用phi生成密钥,但在导入时丢弃D并从N/E/P/Q重新计算导出。
    • (这里有一些细微差别…我觉得CNG发生了变化,可能保留了Windows 10 20H1周围的D值。)

    所以,我的猜测是C1和C2运行在不同的操作系统上(或者同一OS的不同版本)。

    https://github.com/dotnet/runtime/commit/700a07cae19fe64649c2fb4c6c10e6b9aa85dc29展示了我们如何在NET的测试套件中处理它。对于应用程序代码,我的建议是只信任系统。