在上一篇中,说了说数字签名。

数字签名是建立在密钥对体系基础上的:数字签名(信息摘要,私钥),验证签名(数字签名,公钥)。

对于公钥和私钥可以这样理解:

密文=加密(AB,原文),原文=解密(AB,密文),其中AB就是密钥对。

 

.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算法可以创建数字签名,用于保护数据的完整性。支持的密钥长度为5121024,以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 方法可轻松颠倒托管字节数组的顺序。

它支持3841024位密钥,以8位的整数倍递增。

 

现在来为一段数据进行数字签名,这里用到的类是DSA驱动提供的方法:

数字签名=加密(信息摘要,私钥),信息摘要=hash(数据)

 

[Test]
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驱动提供的也以这个示例:

public void TestRSADigitalSignature()
{
    
//原文
    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() 
RSACryptoServiceProvider(CspParameters) 
RSACryptoServiceProvider(Int32)
RSACryptoServiceProvider(Int32, CspParameters)

 

这是它的四个构造器,以第二个为例:

public RSACryptoServiceProvider(CspParameters parameters)

 

下面生成密钥并存放到容器中:

CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName 
= "selfContainer";  

//创建一个key,并添加到容器中
RSACryptoServiceProvider _key = new RSACryptoServiceProvider(cspParams);

 

一个完整的示例:

public void TestCreateContainer()
{
    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类派生的类的实例,通常是RSADSA实例,参数就是上一步中的CspParameters对象

2)从容器中删除非对称密钥

·创建CspParameters类实例,且为其属性KeyContainerName指定名字

·通过带CspParameters参数的构造器创建从AsymmetricAlgorithm类派生的类的实例,派生类一般指RSADSA

·设置派生类实例的属性PersistKeyInCSPfalse

·调用派生类的Clear方法,这个方法用于释放资源并清除密钥容器 

 

posted on 2010-04-09 14:44  梅桦  阅读(2527)  评论(1编辑  收藏  举报