RSACryptoServiceProvider是否正常工作?

时间:2017-01-18 11:45:57

标签: encryption rsa public-key implementation

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

背景

使用具有2048位关键字大小的System.Security.Cryptography.RSACryptoServiceProvider来执行非对称加密/ decrpytion,最初遵循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的标题处。
  3. 关注

    由此,有两个问题:

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

      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并从序列化中省略它。

1 个答案:

答案 0 :(得分:4)

报告的所有内容都是正常的,并且不会令人担忧。

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

不,公钥中的17个额外字节不太可能是信息泄露;它们更可能是您使用的软件为RSA公钥选择的数据格式的标题部分。我的猜测是你遇到了这个answer中详细描述的特定于MS的格式(可能在endianness中),它也精确地使用276个字节作为具有2048位公共模数的RSA公钥。在这种情况下,您应该发现额外的字节总是相同的(因此它们确实没有泄漏)。并且有无数更微妙的方法来泄露有关私钥的信息,例如公共模数本身。

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