RSACryptoServiceProvider 工作正常吗?
Posted
技术标签:
【中文标题】RSACryptoServiceProvider 工作正常吗?【英文标题】:Is RSACryptoServiceProvider working correctly? 【发布时间】:2017-01-18 11:45:57 【问题描述】:我正在使用 .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
。
关于方法的两个观察:
.Exponent
始终为 0x010001
$=65537$。
与序列化的类型版本相比,导出的 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 个字节的序列化?
另一个问题Should RSA public exponent be only in 3, 5, 17, 257 or 65537 due to security considerations? 似乎表明 $\left3, 5, 17, 257, 65537\right$ 都是指数的常见值,所以
0x101
$=65537$ 似乎是合理的,如果确实,始终使用相同的常数指数并没有什么坏处。
额外的 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
并从序列化中省略它。
【问题讨论】:
【参考方案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 的过程保证。
【讨论】:
以上是关于RSACryptoServiceProvider 工作正常吗?的主要内容,如果未能解决你的问题,请参考以下文章
RSACryptoServiceProvider 工作正常吗?
如何使用先前使用 RSACryptoServiceProvider 加密的 RSACng 解密数据
如何提取 RSACryptoServiceProvider 生成的素数?
C# - RSACryptoServiceProvider - 错误:错误数据