【问题标题】:Importing and Exporting RSA Keys in C#在 C# 中导入和导出 RSA 密钥
【发布时间】:2021-09-17 02:07:17
【问题描述】:

我正在尝试导出和重新导入公共和私人 RSA 密钥。我使用 System.Security.Cryptography.RSA 类来做到这一点。但它没有按预期工作。请假设以下代码示例

RSA rsa = RSA.Create();
File.WriteAllBytes("TestPrivateKey", rsa.ExportRSAPrivateKey());
File.WriteAllBytes("TestPublicKey", rsa.ExportRSAPublicKey());
rsa.ImportRSAPrivateKey(File.ReadAllBytes("TestPrivateKey"), out _);
rsa.ImportRSAPublicKey(File.ReadAllBytes("TestPublicKey"), out _);

string textToBeEncrypted = "Hello World";
byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(textToBeEncrypted);
byte[] encryptedBytes = rsa.Encrypt(bytesToBeEncrypted, RSAEncryptionPadding.OaepSHA256);

byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA256);
string result = Encoding.UTF8.GetString(decryptedBytes);

当我不使用导出和导入时,加密和解密工作正常。但是当我使用它们时,我得到一个 Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException 说明在 rsa.Decrypt 函数上找不到密钥。 我不是密码学专家,我知道还有其他方法可以实现我正在做的事情(有很多例子),但它们都有些复杂。这在这里看起来很简单。但为什么它不起作用?重新导入后key不应该一样吗?

【问题讨论】:

  • 你调试过文件中的密钥吗?
  • “调试密钥”是什么意思?密钥是一段数据,而不是代码
  • 第二次导入会覆盖第一次导入,因此只导入了公钥。因此,加密有效,解密失败。修复:加密后导入私钥。
  • 关于您的倒数第二条评论:私钥也包含公钥,因此原则上也可以使用私钥进行加密。 Create() 使用私钥的信息生成一个密钥。因此,加密和解密无需导入和导入私钥即可工作。
  • @user9014097 有趣的问题和答案,你能从你的 cmets 中创建一个答案吗?就我个人而言,我总是使用单独的密码实例(在这种情况下为rsa)进行加密和解密。这些密码实例几乎不包含任何状态,因此创建起来非常便宜;所有真实信息都在密钥中,而那些可以被重用。您可以每次创建一个新的rsa,只要立即导入,您就不会注意到任何性能差异。

标签: c# .net-core encryption rsa private-key


【解决方案1】:

RSA.Create() 返回一个封装了私钥的对象。对象的类型取决于平台,例如在 Windows 10 机器上的 .NET Core 3.1 下,会创建一个 RsaCng 实例,该实例封装了一个私有 2048 位密钥。在下文中,该对象被表示为 RSA 对象

从这样一个创建的 RSA 对象中,可以以不同的格式导出 RSA 私钥。由于私钥也包含公钥数据,所以也可以导出公钥。
同样,可以将私有或公共 RSA 密钥导入 RSA 对象。因此,先前的密钥将被覆盖。这也发生在双重导入的情况下。第二次导入的键会覆盖第一次导入的键 (1)。
为了完整性:导出/导入方法使用 PKCS#1 格式的导出/导入私钥和公钥,DER 编码。它们仅在 .NET Core 中受支持,此处仅从 3.0 版本开始。

此外,.NET 允许使用封装了私钥的 RSA 对象进行加密 (2)。这纯粹是正式的,为了加密,使用了公钥的数据(如前所述,私钥也包含),即在这种情况下有效它是用公钥加密的。

这样就可以解释贴出代码中抛出的异常了:
使用 RSA.Create() 创建一个带有私钥的 RSA 对象。私钥和公钥再次导出和导入,首先是私钥,然后是公钥。双重导入导致私钥被公钥覆盖,因此实际上只导入了公钥(第 1 节)。这允许加密但不允许解密,这会导致相应的异常。

正如评论中已经提到的,使用单独的 RSA 对象进行加密和解密是有意义的,这样每个 RSA 对象只需要一次导入。这会自动避免一个导入在错误的时间覆盖另一个。此外,这种实现更加现实,因为加密和解密通常是分开实现的,因此不可避免地会使用不同的 RSA 对象。


编辑:关于 cmets 中的场景:

cmets中描述的场景也可以解释一下:
如果导入以相反的顺序进行,即首先是公钥,然后是私钥,则实际上只导入私钥(第 1 节)。这可用于加密(第 2 节)和解密。
如果根本不进行导出/导入,则 RSA 对象会封装初始私钥,该私钥也可用于加密和解密。
所以两者都可以工作并且不会抛出异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 2020-03-20
    • 2010-10-21
    • 1970-01-01
    • 1970-01-01
    • 2018-05-20
    • 2023-01-17
    相关资源
    最近更新 更多