证书

一般证书由权威机构(CA认证中心)颁发。其中包括个人信息,公钥,CA签名信息(数字签名)和其它信息。用户接到证书后,可以到证书机构(CA)验证证书来获得证书拥有者身份真伪。然后通过其中的公钥来验证签名。这里说一下windows证书和.net下对证书的类实现。

 

(一)再说存储区

使用证书管理单元,可以显示用户、计算机或服务的证书存储区。在.net中,存储区由X509Store类来实现,这个类对应证书的存储和管理。每个存储区都有几个存储单元,例如My。这个可由下表表示:

AddressBook

其他用户的X.509证书存储区。

AuthRoot

第三方证书颁发机构(CA)X.509证书存储区。

CertificateAuthority

中间证书颁发机构(CA)X.509证书存储区。

Disallowed

吊销的证书的X.509证书存储区。

My

个人证书的X.509证书存储区。

Root

受信任的根证书颁发机构(CA)X.509证书存储区。

TrustedPeople

直接受信任的人和资源的X.509证书存储区。

TrustedPublisher

直接受信任的发行者的X.509证书存储区。

 

 

这里列举一些x509store类的方法和属性:

1Open

打开或创建新的存储区

public void Open(OpenFlags flags)

 

其中的OpenFlags枚举如下:

·ReadOnly 以只读打开证书存储区。

·ReadWrite 以读写方式打开证书存储区。

·MaxAllowed 以允许最高级访问的方式打开证书存储区。

·OpenExistingOnly 仅打开现有存储区。如果不存在任何存储区,Open 方法不会创建新的存储区。

·IncludeArchived 打开 X.509 证书存储区并添加存档证书。

 

使用此方法可打开 X.509 存储区。注意,必须具有 StorePermissionFlags 所指定的附加权限才能枚举存储区中的证书。通过向类构造器传递一个不存在的存储区名称,然后使用除 OpenExistingOnly 之外的任何 OpenFlags 标志,可以创建一个新存储区。

StorePermissionFlags枚举:

NoFlags

未授予执行任何证书或存储区操作的权限。

CreateStore

新建存储区的能力。

DeleteStore

删除存储区的能力。

EnumerateStores

枚举计算机上的存储区的能力。

OpenStore

打开存储区的能力。

AddToStore

将证书添加到存储区的能力。

RemoveFromStore

从存储区中移除证书的能力。

EnumerateCertificates

枚举存储区中的证书的能力。

AllFlags

执行所有证书和存储区操作的能力。

 

2Close

关闭打开的存储区

3Add

把证书添加到存储区

public void Add(X509Certificate2 certificate)

 

它的四个属性:

1public X509Certificate2Collection Certificates { get; }

获得存储区的证书集合

2public StoreLocation Location { get; }

获得证书存储区位置,分类由StoreLocation枚举表示:

CurrentUser,当前用户使用的证书存储区

LocalMachine,分配给本地计算机的证书存储区

3public string Name { get; }

获取存储单元的名字,名字是StoreName枚举的一个值:

AddressBook

其他用户的X.509证书存储区。

AuthRoot

第三方证书颁发机构(CA)X.509证书存储区。

CertificateAuthority

中间证书颁发机构(CA)X.509证书存储区。

Disallowed

吊销的证书的X.509证书存储区。

My

个人证书的X.509证书存储区。

Root

受信任的根证书颁发机构(CA)X.509证书存储区。

TrustedPeople

直接受信任的人和资源的X.509证书存储区。

TrustedPublisher

直接受信任的发行者的X.509证书存储区。

 

4public IntPtr StoreHandle { get; }

获取HCERTSTORE存储区的Intptr句柄

 

示例。

public void Test1()
{
    
//当前用户(CurrentUser)的证书存储区中的个人证书区
     X509Store store = new X509Store(StoreName.My.ToString(),StoreLocation.CurrentUser); 

    
//只读打开
    store.Open(OpenFlags.ReadOnly); 

    
//获取此证书存储区的证书集合
    X509Certificate2Collection certificates = store.Certificates;

    
//查找证书
    X509Certificate2Collection certificates2 = certificates.Find(
      X509FindType.FindByThumbprint, 
"0ec45a95928335411a5cfc26d4bfd7f12fec5eed",true);
 

    
//关闭存储区,释放资源
    store.Close(); 

    
//获取证书
    X509Certificate2 cer = new X509Certificate2();
    cer 
= certificates2[0]; 

    
//打印证书相关属性和内容
    ShowMsg(cer);
}

 

public void ShowMsg(X509Certificate2 cer)
{
    Console.WriteLine(
"主题: {0}", cer.Subject);
    Console.WriteLine(
"颁发者: {0}", cer.Issuer);
    Console.WriteLine(
"版本: {0}", cer.Version);
    Console.WriteLine(
"有效日期: {0}", cer.NotBefore);
    Console.WriteLine(
"过期日期: {0}", cer.NotAfter);
    Console.WriteLine(
"指纹: {0}", cer.Thumbprint);
    Console.WriteLine(
"序列号: {0}", cer.SerialNumber);
    Console.WriteLine(
"友好名: {0}", cer.PublicKey.Oid.FriendlyName);
    Console.WriteLine(
"公钥格式: {0}", cer.PublicKey.EncodedKeyValue.Format(true));
    Console.WriteLine(
"原始数据长度: {0}", cer.RawData.Length);
}

 

通过mmc管理控制台,添加证书管理的结点。

这里可以管理三个存储区的所有证书:本地计算机,当前用户,服务。以上示例的证书存储位置位于当前用户里中的个人证书区中的证书。通过证书的缩略图来查找证书:0ec45a95928335411a5cfc26d4bfd7f12fec5eed

我这张证书打印后的信息是: 

主题: E=songjiang@126.com, CN=宋江, OU=董事部, 
O
=梁山, L=无, S=无, C=CN
颁发者: CN
=catest.com
版本: 
3
有效日期: 
2010-4-16 13:56:51
过期日期: 
2011-4-16 14:06:51
指纹: 0EC45A95928335411A5CFC26D4BFD7F12FEC5EED
序列号: 113FC052000000000007
友好名: RSA
公钥格式: 
30 81 89 02 81 81 00 a6 a5 37 ……省略
原始数据长度: 
1072

 

查找证书的X509FindType枚举型有很多选项,在示例中用到的是以缩略图(指纹)来查找证书。详细请见其它文档。 

(二)使用证书

证书一般由CA颁布,但如果是用于自测试,那么可以申请免费的证书,或通过证书工具来制作,也可以由win2003提供的证书服务来制作证书。

证书内容包括:个人信息,拥有者公钥,CA的签名和其它信息。如果用一个图来表示的话,那么,它包括两部分:

证书=A(拥有者个人信息+拥有者密钥对中的公钥)+B(证书的相关信息+证书颁发机构密钥对中的私钥进行的对A部分的签名)

证书是公钥机制和数字签名的结合使用。所以在使用证书时,可以从签名和非对称加密用途的合集来考虑:

1 公钥机制可以保密数据

公钥拥有者加密数据,只有私钥拥有者才能解密数据,即使公钥拥有者加密数据后,自己也不能查看加密后的数据。例如:B(公钥拥有者)向A(私钥拥有者)发送信息:

B通过对称加密来加密数据,然后通过公钥对对称密钥进行加密,然后数据传递到AA通过自己的私钥来解密数据,得到对称加密的密钥,然后通过密钥来解密数据,最终得到原文。

2 数字签名可以保证数据的完整性

数字签名是建立在散列算法基础上的,通过sha1,md5等算法对数据进行散列计算,得到固定长度的一组信息(数字身份)。散列算法有两个特性:一是单向性;二是能抵抗冲突。通过对数据签名,得到原始数据的散列码,然后在接收端通过对接收到的数据进行散列计算,比较签名信息与计算之后的值的比较来保证数据没有被窜改,这个过程也叫验证签名。

3 CA的认证证书可以保证用户的身份

证书的颁发一般由第三方实现,而第三方会做为双方都信任的实体存在。这3方构成了信任关系。当接到用户收到信息后(信息内容=数据+证书)后,可以到第三方(CA)去验证证书的真伪。证书包括两部分,其中一部分就是第三方的密钥对中的私钥对A(个人信息和拥有者的公钥)进行的签名。那,如果有签名,那么就会通过验证签名来检测数据的完整性:CA中心的对此证书的公钥来验证证书的真实性,如果验证签名通过,则说明证书的A部分(证书拥有者的个人信息+公钥)是没有进行篡改的,即数据是可信的,公钥是可信的,用户是可信的。

4 不可抵赖性

现实中,个人签字和盖章其中的一个作用就是保证不可抵赖性,例如骑马章。而在虚拟世界中,可以通过类似的手段进行实体对行为的诚实性的判断实现,那就是数字签名。

(一)利用证书进行加密和解密

一般的,证书内含有拥有者的公钥,做为密钥对中的公钥有两个作用:一是用于数据加密,二是验证签名。那么当拥有者对数据进行加密后,把数据与签名、证书发给接收者,那么接收者可以通过证书中的公钥对签名进行验证,来确定发送者的身份。一旦身份确定,就可以通过证书中的公钥对数据进行加密。

现在通过1个例子进行加密解密

public void TestCSP()
{
    
//查找证书
    X509Store store = new X509Store(StoreName.My,StoreLocation.CurrentUser);

    store.Open(OpenFlags.ReadOnly); 
    X509Certificate2Collection list 
= store.Certificates;
    X509Certificate2 cert 
=list.Find(X509FindType.FindByThumbprint,
                
"ecfa9a0904b90ef221c5629f661da2b2f783d6b7",true)[0];
    store.Close();
 

    
//原文
    Encoding _encoding = Encoding.Default;
    
string strO = "acb231*";
    Console.WriteLine(
"原文:{0}",strO);
    
byte[] bb = _encoding.GetBytes(strO);
    
byte[] bCipher;
    
byte[] bOo;
 

    
//证书中的公钥
    PublicKey _publicKey = cert.PublicKey; 

    
//公钥加密
    RSACryptoServiceProvider rsa = _publicKey.Key as RSACryptoServiceProvider;
    bCipher 
= rsa.Encrypt(bb, false);
    Console.WriteLine(
"密文:{0}",_encoding.GetString(bCipher));    

    
//私钥解密
    if (!cert.HasPrivateKey)
       
return;

    RSACryptoServiceProvider rsaa 
= cert.PrivateKey as RSACryptoServiceProvider;
    bOo 
= rsaa.Decrypt(bCipher,false);
    Console.WriteLine(
"解密后:{0}",_encoding.GetString(bOo));
}

 

这个例子是通过证书中的密钥进行的,对于xml的加密和解密,有现成的通过证书来进行的方法,这里就不再赘述。

(二)通过证书来签名和验证签名

public void TestSign()
{
    
//查找证书
    X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    store.Open(OpenFlags.ReadOnly); 

    X509Certificate2Collection list 
= store.Certificates;
    X509Certificate2 cert 
= list.Find(X509FindType.FindByThumbprint,
               
"ecfa9a0904b90ef221c5629f661da2b2f783d6b7"true)[0];
    store.Close(); 

    
//原文
    Encoding _encoding = Encoding.Default;
    
string strO = "acb231*";
    
byte[] bb = _encoding.GetBytes(strO);
    
byte[] bSign; 

    
//签名
    RSACryptoServiceProvider rsaa = cert.PrivateKey as RSACryptoServiceProvider;
    bSign 
= rsaa.SignData(bb, "md5"); 

    
//验证签名
    PublicKey _publicKey = cert.PublicKey;
    RSACryptoServiceProvider rsa 
= _publicKey.Key as RSACryptoServiceProvider;
    
bool bsign = rsa.VerifyData(bb, "md5", bSign); 

    
if (bsign)
        Console.WriteLine(
"数据完整");
    
else
        Console.WriteLine(
"数据被篡改");
}

 

(三)通过pfx证书来进行签名和验证签名

在证书管理控制台中,可以在任务中导出证书,在导出过程中可以连带私钥导出,在导出过程中可以设置密钥访问密码。这里我导出了一张证书,密码设置为111。文件类型为pfx文件,下面通过签名来示例pfx文件用法:

public void TestPfx()
{
    X509Certificate2 cert 
= new X509Certificate2(@"k:/self.pfx","111"); 

    
//原文
    Encoding _encoding = Encoding.Default;
    
string strO = "acb231*";
    
byte[] bb = _encoding.GetBytes(strO);
    
byte[] bSign; 

    
//签名
    RSACryptoServiceProvider rsaa = cert.PrivateKey as RSACryptoServiceProvider;
    bSign 
= rsaa.SignData(bb, "md5"); 

    
//验证签名
    PublicKey _publicKey = cert.PublicKey;
    RSACryptoServiceProvider rsa 
= _publicKey.Key as RSACryptoServiceProvider;
    
bool bsign = rsa.VerifyData(bb, "md5", bSign); 

    
if (bsign)
        Console.WriteLine(
"数据完整");
    
else
        Console.WriteLine(
"数据被篡改");
}

 

证书的重点是在于签名部分,即对公钥的归属进行判断。

 

posted on 2010-04-20 15:36  梅桦  阅读(2921)  评论(2编辑  收藏  举报