我正在使用.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
。
关于方法的两个观察结果:
.Exponent
始终为0x010001
$ = 65537 $。rsaProvider.ExportCspBlob()
:
RSAParameters
:
.Exponent.Length = 3
.Modulus .Length = 256
.D .Length = 256
.DP .Length = 128
.DQ .Length = 128
.Exponent.Length = 3
.InverseQ.Length = 128
.Modulus .Length = 256
.P .Length = 128
.Q .Length = 128
由此,有两个问题:
0x101
$ = 65537如果确实总是使用相同的常数指数没有坏处,那么$似乎是合理的。 RSACryptoServiceProvider
的行为是否值得关注,或者这些事情是否正常?
在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
并从序列化中省略它。
答案 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 的过程投保。