做了个小测试,发现 RSACryptoServiceProvider,及其内核 Microsoft Cryptography API,完全可以轻松泄露私钥:
代码如下:
CspParameters cspParam = new CspParameters( 1, null, "x-user" );
RSACryptoServiceProvider ras = new RSACryptoServiceProvider( cspParam );
bool bset = ras.PersistKeyInCsp;
bset = ras.PublicOnly;
string key1 = ras.KeyExchangeAlgorithm;
key1 = ras.SignatureAlgorithm;
byte[] blob = ras.ExportCspBlob( true );
StreamWriter blbWriter = new StreamWriter( "e:\\blob.txt" );
for( int mm = 0; mm < blob.Length; mm++ )
{
blbWriter.Write( "{0:x2} ", blob[mm] );
if( (mm + 1) % 20 == 0 )
blbWriter.WriteLine();
}
blbWriter.Dispose();
如果你将这个程序运行两次,你会发现,不仅私钥可以被输出,而且两次的私钥内容完全一样。
因为公约和私钥对,永久驻留在 Windows 系统中,就算你重启 windows,它俩的数据保持不变。
换句话说,上述名字为 “x-user” 的密钥容器中的密钥永远不会改变,而且还可以被输出。
那就完蛋了,只要你用过 RSACryptoServiceProvider 来进行过非对称加密,人家拿到你密钥容器的名字,就可以把你的私钥输出来。
而拿到你密钥容器的名字易如反掌,只要反编译你的 C# 代码,或者查找程序集中的常量字符串,就知道了
问题的根源不在于 .NET 的 RSACryptoServiceProvider 类,而是在于 Windows 提供的 Microsoft Cryptography API,它本身就是永久保存密钥对,并可以输出私钥。
我又用 VC 调用这个 API 做了个测试,密钥容器名字仍使用 x-user,发现输出的密钥对,完全同上述一样。
各位想象一下,这有多危险
------解决思路----------------------
CSP本来就是服务器端保存私钥用的,你的程序本来就是服务器端程序。客户端程序根本不是你那种编程方法,它只收到公钥、只能加密而不能解密。
RSA是不对称的操作。你只是看到了RSA编程的三分之一的例子就以为看懂了RSA了。