【发布时间】: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。
关于方法的两个观察:
-
.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
- 公钥为 259 字节。
- 额外的 17 个字节似乎位于二进制 blob 的标头中。
-
担忧
由此,有两个担忧:
- 指数不是随机的可以吗?
- 如果指数被定义为一个常数,那么我似乎可以再减少 3 个字节的序列化?
- 另一个问题Should RSA public exponent be only in {3, 5, 17, 257 or 65537} due to security considerations? 似乎表明 $\left{3, 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 并从序列化中省略它。
【问题讨论】:
标签: encryption rsa public-key implementation