在上一篇中,说了说数字签名。
数字签名是建立在密钥对体系基础上的:数字签名(信息摘要,私钥),验证签名(数字签名,公钥)。
对于公钥和私钥可以这样理解:
密文=加密(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)
结果:
信息摘要:CBFC425ADABD72095739CB
数字签名:BA
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);
//--------------------------------------------
}
结果:
加密后的数据:A9B15B
C487E1BE
5EC
920FAC642D
B0CF
解密后的数据: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方法,这个方法用于释放资源并清除密钥容器