【问题标题】:Is RSACryptoServiceProvider working correctly?RSACryptoServiceProvider 工作正常吗?
【发布时间】:2025-11-29 13:15:01
【问题描述】:

我正在使用 .NET 的 RSA 实现,有两件事对我来说很奇怪。我想确认它运行正常。

背景

使用 System.Security.Cryptography.RSACryptoServiceProvider 和 2048 位关键字大小来执行非对称加密/解密,最初遵循 this question, "AES 256 Encryption: public and private key how can I generate and use it .net" 中的示例。

作为第一个实现,这似乎可行:

public const int  CSPPARAMETERS_FLAG = 1;      // Specifies RSA: https://msdn.microsoft.com/en-us/library/ms148034(v=vs.110).aspx
public const bool USE_OAEP_PADDING   = false;
public const int  KEYWORD_SIZE       = 2048;

public static byte[] Encrypt(byte[] publicKey, byte[] dataToEncrypt)
{
    var cspParameters = new System.Security.Cryptography.CspParameters(CSPPARAMETERS_FLAG);
    byte[] encryptedData = null;

    using (var rsaProvider = new System.Security.Cryptography.RSACryptoServiceProvider(cspParameters))
    {
        try
        {
            rsaProvider.PersistKeyInCsp = false;
            rsaProvider.ImportCspBlob(publicKey);
            encryptedData = rsaProvider.Encrypt(dataToEncrypt, USE_OAEP_PADDING);
        }
        finally
        {
            rsaProvider.PersistKeyInCsp = false;
            rsaProvider.Clear();
        }
    }
    return encryptedData;
}

public static byte[] Decrypt(byte[] privateKey, byte[] dataToDecrypt)
{
    var cspParameters = new System.Security.Cryptography.CspParameters(CSPPARAMETERS_FLAG);
    byte[] encryptedData = null;

    using (var rsaProvider = new System.Security.Cryptography.RSACryptoServiceProvider(cspParameters))
    {
        try
        {
            rsaProvider.PersistKeyInCsp = false;
            rsaProvider.ImportCspBlob(privateKey);
            encryptedData = rsaProvider.Decrypt(dataToDecrypt, USE_OAEP_PADDING);
        }
        finally
        {
            rsaProvider.PersistKeyInCsp = false;
            rsaProvider.Clear();
        }
    }

    return encryptedData;
}

在进一步研究了这些方法之后,我从the example 生成的公钥似乎在开始时有很多非常可预测的数据,它有 276 字节长。

显然rsaProvider.ExportCspBlob(bool includePrivateParameters)rsaProvider.ExportParameters(bool includePrivateParameters) 的功能替代品;主要区别在于 blob 已经序列化为 byte[] 而另一个发出对象版本 RSAParameters

关于方法的两个观察:

  1. .Exponent 始终为 0x010001$=65537$。
  2. 与序列化的类型版本相比,导出的 blob 包含 17 个额外字节。
    • rsaProvider.ExportCspBlob():
      • 公钥为 276 字节。
      • 私钥为 1172 字节。
    • RSAParameters:
      • 公钥为 259 字节。
        • .Exponent.Length = 3
        • .Modulus .Length = 256
      • 私钥为 1155 字节。
        • .D .Length = 256
        • .DP .Length = 128
        • .DQ .Length = 128
        • .Exponent.Length = 3
        • .InverseQ.Length = 128
        • .Modulus .Length = 256
        • .P .Length = 128
        • .Q .Length = 128
    • 额外的 17 个字节似乎位于二进制 blob 的标头中。

担忧

由此,有两个担忧:

  1. 指数不是随机的可以吗?
  2. 额外的 17 个字节是信息泄漏吗?
    • 它们是否代表密钥长度和方法等选项参数?
    • 当我已经知道发送方和接收方都使用相同的硬编码方法时,传输选项参数信息是否是个好主意?

问题

RSACryptoServiceProvider 的行为是否值得关注,或者这些事情是否正常?

更新 1

Should RSA public exponent be only in {3, 5, 17, 257 or 65537} due to security considerations? 中,接受的答案开始于:

对于 RSA 的任何短或长公共指数都没有已知的弱点,只要公共指数是“正确的”(即对于除模的所有素数 p 与 p-1 相对素数)。

如果是这样,那么我猜0x010001$=65537$ 的明显恒定指数就足够了,只要它与 $p-1$ 相对质数。因此,大概 RSA 的 .NET 实现会检查这种情况。

但是,如果条件不满足,RSACryptoServiceProvider 会做什么?如果它选择了不同的指数,那么每当指数不是0x010001 时,它似乎就会泄露有关 $p$ 的信息。或者,如果选择了不同的键,那么我们似乎可以假设指数始终为 0x010001 并从序列化中省略它。

【问题讨论】:

    标签: encryption rsa public-key implementation


    【解决方案1】:

    报告的一切都是正常的,并不令人担忧。

    公共指数 e 短且非随机是完全可以的。 e = 216+1 = 65537 = 0x010001 是常见且安全的。一些当局要求它(或包括它的某些范围)。使用它(或/和显着大于公共模数位大小的东西)可以防止一些最差的 RSA 填充。

    不,公钥中的 17 个额外字节不太可能是信息泄漏;它们更有可能是您使用的软件为 RSA 公钥选择的数据格式的标头部分。我的猜测是您遇到了answer 中详述的特定于 MS 的格式(可能在字节序内),它还使用 276 字节的 RSA 公钥和 2048 位公共模数。在这种情况下,您应该会发现额外的字节总是相同的(因此它们显然不会泄漏任何内容)。还有无数更微妙的方式可以泄露关于私钥的信息,比如在公共模数本身中。

    实践中使用的很多RSA密钥生成器,包括我猜RSACryptoServiceProvider,首先选择e,然后稍微避免生成素数p这样gcd(e , p-1) ≠ 1. 因为 e = 65537 是素数,所以 ( p % e ) ≠ 1,这很容易检查,或者由生成 p 的过程保证。

    【讨论】:

      最近更新 更多