如何有效地恢复 RSA 中的公钥或私钥?

Posted

技术标签:

【中文标题】如何有效地恢复 RSA 中的公钥或私钥?【英文标题】:How to efficiently restore public or private key in RSA? 【发布时间】:2020-06-04 15:37:23 【问题描述】:

我发现很多帖子如何通过 RSACryptoServiceProvider 做到这一点,但他们都缺少一件可能是次要的事情。尽管它是次要的,但我想问是否有人知道如何有效地做到这一点。

当您实例化 RSACryptoServiceProvider 时,它会生成一个私钥/公钥。对象上有一些导入方法,允许您导入另一个密钥。例如 ImportCspBlob。困扰我的是,即使我不需要它们,它也会在执行构造函数时生成私钥/公钥对。无论如何,我计划导入另一个密钥。问题是如何在执行构造函数时避免生成密钥或将我的密钥传递给构造函数,从而有效地避免生成新的对?

另外,我知道密钥容器并阅读了有关如何使用它将 CspParameters 传递给构造函数的信息,但在我的情况下,我将公钥传递给另一个应用程序或系统,这意味着容器无论如何都是空的。

【问题讨论】:

...当您实例化 RSACryptoServiceProvider 时,它会生成一个私钥/公钥...它不会。文档令人困惑,但我似乎很清楚,无参数构造函数在实例化时不会生成密钥对。 【参考方案1】:

RSACryptoServiceProvider 构造函数确实根据简短的构造函数文档创建了一个密钥对:

使用随机密钥对初始化 RSACryptoServiceProvider 类的新实例。

但是,如果您单击构造函数,然后阅读完整文档,那么即使是下面的示例代码,您也会得到这句话:

此构造函数不会立即生成新的公钥/私钥对。如果没有通过ImportParameters 方法或任何其他密钥导入方法加载密钥,则在需要密钥之前,会按需创建一个 1024 位的临时密钥。

换句话说,它使用密钥对字段的惰性实例化。

所以你的假设是错误的,但你有一个很大的借口来犯错:.NET 加密类的文档仍然没有达到应有的水平。

【讨论】:

【参考方案2】:

此帐户的文档不清楚,但看起来密钥对实际上是在构造函数中创建的。这是构造函数

    [SecurityCritical]
private RSACryptoServiceProvider(
  int dwKeySize,
  CspParameters parameters,
  bool useDefaultKeySize)

  if (dwKeySize < 0)
    throw new ArgumentOutOfRangeException(nameof (dwKeySize), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  this._parameters = Utils.SaveCspParameters(CspAlgorithmType.Rsa, parameters, RSACryptoServiceProvider.s_UseMachineKeyStore, ref this._randomKeyContainer);
  this.LegalKeySizesValue = new KeySizes[1]
  
    new KeySizes(384, 16384, 8)
  ;
  this._dwKeySize = useDefaultKeySize ? 1024 : dwKeySize;
  if (this._randomKeyContainer && !Environment.GetCompatibilityFlag(CompatibilityFlag.EagerlyGenerateRandomAsymmKeys))
    return;
  this.GetKeyPair();

最后它调用GetKeyPair。最终它调用 GetKeyPairHelper 并且在我看到的那个方法的中间

      int userKey = Utils._GetUserKey(safeProvHandle, parameters.KeyNumber, ref invalidHandle);
  if (userKey != 0)
  
    if ((parameters.Flags & CspProviderFlags.UseExistingKey) != CspProviderFlags.NoFlags || userKey != -2146893811)
      throw new CryptographicException(userKey);
    Utils._GenerateKey(safeProvHandle, parameters.KeyNumber, parameters.Flags, dwKeySize, ref invalidHandle);
  

注意 Utils._GenerateKey。这让我相信至少在某些情况下它会生成密钥。我不清楚在我的特定条件下执行哪个代码块,我的示例可能完全脱离上下文。我试图了解我必须如何编写代码以确保未在构造函数中创建密钥对。

还有这个文档https://docs.microsoft.com/en-us/dotnet/standard/security/generating-keys-for-encryption-and-decryption 说

每当创建非对称算法类的新实例时,都会生成公钥/私钥对。

所以,一切都相当混乱。

【讨论】:

抱歉,如果有导入密钥的方法,为什么还要使用特定的构造函数?有没有具体的参数需要提前设置? 这是我的问题的一部分。我不知道。有没有办法创建 RSACryptoServiceProvider 将私有/公共对传递给它? 你真的看过我的回答吗?有无参构造函数,有导入方法,对吧?

以上是关于如何有效地恢复 RSA 中的公钥或私钥?的主要内容,如果未能解决你的问题,请参考以下文章

Android加密篇 RSA

RSA已知明文和公钥能得到私钥加密的密文吗

java 中的Cipher类RSA方式能不能用私钥加密公钥解密,完整解释下

如何存储/检索 RSA 公钥/私钥

rsa 公钥 私钥 生成 需要些啥参数

如何使用openssl生成RSA公钥和私钥对 / 蓝讯