转载自:http://www.cnblogs.com/jams742003/archive/2010/04/09/1708315.html
在上一篇中,说了说数字签名。
数字签名是建立在密钥对体系基础上的:数字签名(信息摘要,私钥),验证签名(数字签名,公钥)。
对于公钥和私钥可以这样理解:
密文=加密(A,B,原文),原文=解密(A,B,密文),其中A和B就是密钥对。
.net下的System.Security.Cryptography 名字空间是提供加密服务的一个空间。在边有大量用于实现加密服务的类,例如哈希散列,随机数字等。这个在前边两篇(1)和(2)中进行了说明。
公钥加密又叫非对称加密,即由一个密钥(公钥)加密,须由另一个密钥(私钥)解密。.net下的非对称加密提供了DSA和 RSA加密。
DSA,是Digital Signature Algorithm的缩写,是一种签名算法。RSA,是一种可以用于签名,也可以用于加密的一种算法。
这个空间提供了DSA加密的类型:
System.Security.Cryptography.DSA
System.Security.Cryptography.DSACryptoServiceProvider
若是DSA是一个抽象基类。通过DSA算法可以创建数字签名,用于保护数据的完整性。支持的密钥长度为512到1024,以64位的整数倍递增。
RSA加密的类型:
System.Security.Cryptography.RSA
System.Security.Cryptography.RSACryptoServiceProvider
这里引用一段话:
与非托管 CAPI 中的 RSA 实现不同的是,RSACryptoServiceProvider 类会在加密之后、解密之前颠倒被加密数组的字节顺序。默认情况下,CAPI CryptDecrypt 函数无法解密由 RSACryptoServiceProvider 类加密的数据,RSACryptoServiceProvider 类无法解密由 CAPI CryptEncrypt 方法加密的数据。如果在 API 之间互相操作时没有对颠倒的顺序进行补偿,RSACryptoServiceProvider 类会引发 CryptographicException。要同 CAPI 相互操作,必须在加密数据与其他 API 相互操作之前,手动颠倒加密字节的顺序。通过调用 Array.Reverse 方法可轻松颠倒托管字节数组的顺序。
它支持384到1024位密钥,以8位的整数倍递增。
现在来为一段数据进行数字签名,这里用到的类是DSA驱动提供的方法:
数字签名=加密(信息摘要,私钥),信息摘要=hash(数据)
public void TestDSADigitalSignature()
{
// 原文
string strContent = " 12345abc " ;
// 信息摘要,sha1
SHA1 _sha1 = new SHA1CryptoServiceProvider();
Encoding _encoding = Encoding.Default;
byte [] bb = _encoding.GetBytes(strContent);
byte [] bMessageDigest = _sha1.ComputeHash(bb);
DSACryptoServiceProvider _DSA = new DSACryptoServiceProvider();
Console.WriteLine( " 信息摘要:{0} " ,
BitConverter.ToString(bMessageDigest).Replace( " - " , string .Empty));
// 通过私钥进行签名
// --------------------------------------------
DSAParameters _privateKey = _DSA.ExportParameters( true );
_DSA.ImportParameters(_privateKey);
DSASignatureFormatter DSAFormatter = new DSASignatureFormatter(_DSA);
DSAFormatter.SetHashAlgorithm( " sha1 " );
byte [] bSignature = DSAFormatter.CreateSignature(bMessageDigest);
Console.WriteLine( " 数字签名:{0} " ,
BitConverter.ToString(bSignature).Replace( " - " , string .Empty));
// --------------------------------------------
// 通过公钥进行验证签名
// --------------------------------------------
DSAParameters _publicKey = _DSA.ExportParameters( false );
_DSA.ImportParameters(_privateKey);
DSASignatureDeformatter DSADeformatter = new DSASignatureDeformatter(_DSA);
DSADeformatter.SetHashAlgorithm( " sha1 " );
bool bCheck = DSADeformatter.VerifySignature(bMessageDigest, bSignature);
Console.WriteLine( " 验证签名是否通过:{0} " ,bCheck == true ? " 是 " : " 否 " );
// --------------------------------------------
}
说明一下:
·私钥生成:ExportParameters(true)
·公钥生成:ExportParameters(false)
·生成签名:DSAFormatter.CreateSignature(bMessageDigest)
·验证签名:
DSADeformatter.VerifySignature(bMessageDigest, bSignature)
结果:
信息摘要:CBFC425ADABD72095739CB720F5BB7026
数字签名:BA069C3DEB188D03362B10668ABF67031455E47E40
3B94380E132B62EFE621051356397EC7E05D
验证签名是否通过:是
RSA驱动提供的也以这个示例:
{
// 原文
string strContent = " 12345abc " ;
Encoding _encoding = Encoding.Default;
byte [] bb = _encoding.GetBytes(strContent);
byte [] bEncrypt;
byte [] bDecrypt;
RSACryptoServiceProvider _RSA = new RSACryptoServiceProvider();
RSAParameters _publicKey = _RSA.ExportParameters( false );
RSAParameters _privateKey = _RSA.ExportParameters( true );
// 用公钥,加密
// --------------------------------------------
RSACryptoServiceProvider _RSA1 = new RSACryptoServiceProvider();
_RSA1.ImportParameters(_publicKey);
bEncrypt = _RSA1.Encrypt(bb, false );
Console.WriteLine( " 加密后的数据:{0} " ,
BitConverter.ToString(bEncrypt).Replace( " - " , string .Empty));
// --------------------------------------------
// 通过私钥进行解密
// --------------------------------------------
RSACryptoServiceProvider _RSA2 = new RSACryptoServiceProvider();
_RSA2.ImportParameters(_privateKey);
bDecrypt = _RSA.Decrypt(bEncrypt, false );
string str = _encoding.GetString(bDecrypt);
Console.WriteLine( " 解密后的数据:{0} " , str);
// --------------------------------------------
}
结果:
加密后的数据:A9B15B4A0C2C976A8C990E739DFE6CD192EE2ACB00EA
C487E1BE2128A3E8241EFAF0F98AC88C4A53ADC48D9AA9D9585A4D0FB5
5EC6651C40ADB88EE2C28032A84C25B70103233BADEB518F97E54F3CF9
920FAC642D79F0BCB37BF7E22054CE44CD5B8295F7CDC034299D4F836D
B0CF48C0011CE148D6AD5FF5C892A1B90F81BB
解密后的数据:abc
对于非对称加密的密钥的存储
对私钥来说可以存放到容器中。之前先看一下.net提供的非对称加密类型的构造器,以RSA为例:
RSACryptoServiceProvider(CspParameters)
RSACryptoServiceProvider(Int32)
RSACryptoServiceProvider(Int32, CspParameters)
这是它的四个构造器,以第二个为例:
下面生成密钥并存放到容器中:
cspParams.KeyContainerName = " selfContainer " ;
// 创建一个key,并添加到容器中
RSACryptoServiceProvider _key = new RSACryptoServiceProvider(cspParams);
一个完整的示例:
{
Encoding _encoding = Encoding.Default;
string strContent = " 12345abc " ;
byte [] dataToEncrypt = _encoding.GetBytes(strContent);
byte [] encryptedData;
byte [] decryptedData;
// 容器
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = " selfContainer " ;
// 创建一个key,并添加到容器中
RSACryptoServiceProvider _key = new RSACryptoServiceProvider(cspParams);
// 加密
RSACryptoServiceProvider _RSA1 = new RSACryptoServiceProvider(cspParams);
encryptedData = _RSA1.Encrypt(dataToEncrypt, false );
// 解密
RSACryptoServiceProvider _RSA2 = new RSACryptoServiceProvider(cspParams);
decryptedData = _RSA1.Decrypt(encryptedData, false );
string str = _encoding.GetString(decryptedData);
Console.WriteLine(str);
}
(1)创建非对称密钥并保存在容器中的步骤:
·创建CspParameters类的实例,且设置其KeyContainerName属性
·通过带有CspParameters参数的构造器来创建实例从AsymmetricAlgorithm类派生的类的实例,通常是RSA或DSA实例,参数就是上一步中的CspParameters对象
(2)从容器中删除非对称密钥
·创建CspParameters类实例,且为其属性KeyContainerName指定名字
·通过带CspParameters参数的构造器创建从AsymmetricAlgorithm类派生的类的实例,派生类一般指RSA,DSA
·设置派生类实例的属性PersistKeyInCSP为false
·调用派生类的Clear方法,这个方法用于释放资源并清除密钥容器