证书
一般证书由权威机构(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类的方法和属性:
(1)Open
打开或创建新的存储区
其中的OpenFlags枚举如下:
·ReadOnly 以只读打开证书存储区。
·ReadWrite 以读写方式打开证书存储区。
·MaxAllowed 以允许最高级访问的方式打开证书存储区。
·OpenExistingOnly 仅打开现有存储区。如果不存在任何存储区,Open 方法不会创建新的存储区。
·IncludeArchived 打开 X.509 证书存储区并添加存档证书。
使用此方法可打开 X.509 存储区。注意,必须具有 StorePermissionFlags 所指定的附加权限才能枚举存储区中的证书。通过向类构造器传递一个不存在的存储区名称,然后使用除 OpenExistingOnly 之外的任何 OpenFlags 标志,可以创建一个新存储区。
StorePermissionFlags枚举:
NoFlags |
未授予执行任何证书或存储区操作的权限。 |
CreateStore |
新建存储区的能力。 |
DeleteStore |
删除存储区的能力。 |
EnumerateStores |
枚举计算机上的存储区的能力。 |
OpenStore |
打开存储区的能力。 |
AddToStore |
将证书添加到存储区的能力。 |
RemoveFromStore |
从存储区中移除证书的能力。 |
EnumerateCertificates |
枚举存储区中的证书的能力。 |
AllFlags |
执行所有证书和存储区操作的能力。 |
(2)Close
关闭打开的存储区
(3)Add
把证书添加到存储区
它的四个属性:
(1)public X509Certificate2Collection Certificates { get; }
获得存储区的证书集合
(2)public StoreLocation Location { get; }
获得证书存储区位置,分类由StoreLocation枚举表示:
CurrentUser,当前用户使用的证书存储区
LocalMachine,分配给本地计算机的证书存储区
(3)public 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证书存储区。 |
(4)public IntPtr StoreHandle { get; }
获取HCERTSTORE存储区的Intptr句柄
示例。
{
//当前用户(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);
}
{
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管理控制台,添加证书管理的结点。
这里可以管理三个存储区的所有证书:本地计算机,当前用户,服务。以上示例的证书存储位置位于当前用户里中的个人证书区中的证书。通过证书的缩略图来查找证书:0ec
我这张证书打印后的信息是:
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通过对称加密来加密数据,然后通过公钥对对称密钥进行加密,然后数据传递到A,A通过自己的私钥来解密数据,得到对称加密的密钥,然后通过密钥来解密数据,最终得到原文。
2 数字签名可以保证数据的完整性
数字签名是建立在散列算法基础上的,通过sha1,md5等算法对数据进行散列计算,得到固定长度的一组信息(数字身份)。散列算法有两个特性:一是单向性;二是能抵抗冲突。通过对数据签名,得到原始数据的散列码,然后在接收端通过对接收到的数据进行散列计算,比较签名信息与计算之后的值的比较来保证数据没有被窜改,这个过程也叫验证签名。
3 CA的认证证书可以保证用户的身份
证书的颁发一般由第三方实现,而第三方会做为双方都信任的实体存在。这3方构成了信任关系。当接到用户收到信息后(信息内容=数据+证书)后,可以到第三方(CA)去验证证书的真伪。证书包括两部分,其中一部分就是第三方的密钥对中的私钥对A(个人信息和拥有者的公钥)进行的签名。那,如果有签名,那么就会通过验证签名来检测数据的完整性:CA中心的对此证书的公钥来验证证书的真实性,如果验证签名通过,则说明证书的A部分(证书拥有者的个人信息+公钥)是没有进行篡改的,即数据是可信的,公钥是可信的,用户是可信的。
4 不可抵赖性
现实中,个人签字和盖章其中的一个作用就是保证不可抵赖性,例如骑马章。而在虚拟世界中,可以通过类似的手段进行实体对行为的诚实性的判断实现,那就是数字签名。
(一)利用证书进行加密和解密
一般的,证书内含有拥有者的公钥,做为密钥对中的公钥有两个作用:一是用于数据加密,二是验证签名。那么当拥有者对数据进行加密后,把数据与签名、证书发给接收者,那么接收者可以通过证书中的公钥对签名进行验证,来确定发送者的身份。一旦身份确定,就可以通过证书中的公钥对数据进行加密。
现在通过1个例子进行加密解密
{
//查找证书
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的加密和解密,有现成的通过证书来进行的方法,这里就不再赘述。
(二)通过证书来签名和验证签名
{
//查找证书
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文件用法:
{
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("数据被篡改");
}
证书的重点是在于签名部分,即对公钥的归属进行判断。