证书加密与验证
网络威胁
1.窃听:网络传输是在公共信道上进行的,特别是HTTP传输大多以明文传输,黑客进行窃听,获取敏感信息。
2.伪装:这个基本每个人都遇到过,早期诈骗,说你账户被盗要求你登录改密码,会进入一个与官网相似的改密码页面来获取你的真实密码。
3.篡改:信息在提交到服务器之前被非法修改,黑客可以盗取用户的Session、Cache信息,来修改提交到服务器的请求信息。
4.抵赖:用户可以否定自己曾经做过的事情。在日常生活中也会遇到同样的问题,比如领导明明安排的一个任务,但你可能忘记了就说不知道,没人通知你,这就叫抵赖
基本概念
证书是针对上述网络威胁建立起来的解决方案,基本概念:
- CA(Certificate Authority):数字证书认证中心。发放、管理、废除数字证书的机构,CA的作用是检查证书持有者身份的合法性,并签发证书(在证书上签字),以防证书被伪造或篡改,以及对证书和密钥进行管理。
- 证书有以下信息:证书颁布机构,证书的有效期,公钥,私钥,签名及所用算法,指纹和指纹算法。
- 证书颁布机构(Issuer):指出是什么机构发布的这个证书,也就是指明这个证书是哪个公司创建的(只是创建证书,不是指证书的使用者)。
- 证书有效期(Valid from , Valid to):证书的使用期限。 过了有效期限,证书就会作废,不能使用了
- 主体(Subject):证书是发布给谁的,或者说证书的所有者
- 签名所使用的算法(Signature algorithm):指的这个数字证书的数字签名所使用的加密算法。
- 指纹及指纹算法(Thumbprint, Thumbprint algorithm):这个是用来保证证书的完整性的,也就是说确保证书没有被修改过。 其原理就是在发布证书时,发布者根据指纹算法(一个hash算法)计算整个证书的hash值(指纹)并和证书放在一起,使用者在打开证书时,自己也根据指纹算法计算一下证书的hash值(指纹),如果和刚开始的值对得上,就说明证书没有被修改过,因为证书的内容被修改后,根据证书的内容计算的出的hash值(指纹)是会变化的。
证书的特性:
- 保密性(Privacy):确认信息的保密,不被窃取。
- 鉴别与授权(Authentication & Authorization):确认对方的身份并确保其不越权
- 完整性(Integrity):确保你收到信息没有被篡改
- 抗抵赖性(Non-Repudiation):有证据保证交易不被否认
证书的常见形式:
.CER,文件是二进制格式,只保存证书,不保存私钥。
.PEM,一般是文本格式,可保存证书,可保存私钥。
.PFX,二进制格式,同时包含证书和私钥,一般有密码保护。
.JKS,二进制格式,同时包含证书和私钥,一般有密码保护。
证书创建
微软官方给了一个证书创建帮助类https://docs.microsoft.com/en-us/archive/blogs/dcook/creating-a-self-signed-certificate-in-c
可以使用其很方便的创建一个证书
/// <summary>
/// 创建证书
/// </summary>
/// <returns></returns>
public bool CreateCertificate()
{
var commonName = m_CertificateCommonName;
var password = m_Password;
var path = m_CertificatePath;
var certificateName = commonName;
if (!commonName.StartsWith("CN=", StringComparison.OrdinalIgnoreCase))
certificateName = "CN=" + commonName;
byte[] certificateData = Certificate.CreateSelfSignCertificatePfx(certificateName, //host name
DateTime.Now, //not valid before
DateTime.Now.AddYears(5), //not valid after
password);
var filename = Path.Combine(path, commonName);
if (!filename.EndsWith(".pfx"))
{
filename = filename + ".pfx";
}
using (BinaryWriter binWriter = new BinaryWriter(File.Open(filename, FileMode.Create)))
{
binWriter.Write(certificateData);
binWriter.Flush();
}
if (TryGetCertificate(out X509Certificate2 cert))
{
selfCertificate = cert;
}
RunInfo = "创建成功";
return true;
}
导出cer证书
/// <summary>
/// 尝试导出cer证书文件,也就是公钥证书
/// </summary>
/// <returns></returns>
public bool TryExportCerFile()
{
if (string.IsNullOrEmpty(m_BinaryExportPath) || string.IsNullOrEmpty(m_BinaryExportName))
{
RunInfo = "请输入参数信息";
return false;
}
//find the certificate
byte[] cerByte = selfCertificate.Export(X509ContentType.Cert);
var filename = Path.Combine(m_BinaryExportPath, m_BinaryExportName);
if (!filename.EndsWith(".cer"))
{
filename = filename + ".cer";
}
using (BinaryWriter binWriter = new BinaryWriter(File.Open(filename, FileMode.Create)))
{
binWriter.Write(cerByte);
binWriter.Flush();
}
RunInfo = "导出成功";
return true;
}
证书加密
/// <summary>
/// 公钥加密
/// </summary>
public void PublicKeyEncryptionMethod()
{
if (string.IsNullOrEmpty(m_PlainText))
{
RunInfo = "请输入需要加密的信息";
return;
}
//公钥加密
byte[] infos = Encoding.UTF8.GetBytes(m_PlainText);
RSACryptoServiceProvider myRSACryptoServiceProvider =
(RSACryptoServiceProvider) selfCertificate.PublicKey.Key;
Byte[] Cryptograph = myRSACryptoServiceProvider.Encrypt(infos, false);
//所以明文不能把128字节占满,实际测试,明文最多为117字节,留下的空间用来填充随机数。
publicKeyEncryption = Cryptograph;
StringBuilder s =new StringBuilder();
foreach (var b in Cryptograph)
{
s.Append(b.ToString("X2") + " ");
}
s.Append("总字节数:" + Cryptograph.Length);
PublicKeyEncryption = s.ToString();
}
/// <summary>
/// 使用私钥解密
/// </summary>
public void PrivateKeyDecryptionMethod()
{
if (publicKeyEncryption == null)
{
RunInfo = "请先进行公钥加密";
return;
}
//私钥进行解密
RSACryptoServiceProvider myRSACryptoServiceProvider = (RSACryptoServiceProvider)selfCertificate.PrivateKey;
byte[] plaintextByte = myRSACryptoServiceProvider.Decrypt(publicKeyEncryption, false);
PrivateKeyDecryption = Encoding.UTF8.GetString(plaintextByte);
}
证书电子签名
/// <summary>
/// 私钥签名
/// </summary>
public void PrivateKeyEnSignatureMethod()
{
if (string.IsNullOrEmpty(m_PlainText))
{
RunInfo = "请输入需要加密的信息";
return;
}
//明文数据
byte[] infos = Encoding.UTF8.GetBytes(m_PlainText);
//私钥进行摘要算法计算,并将计算值用私钥加密
RSACryptoServiceProvider myRSACryptoServiceProvider =
(RSACryptoServiceProvider)selfCertificate.PrivateKey;
byte[] signs= myRSACryptoServiceProvider.SignData(infos, "MD5");
string signdata = System.Convert.ToBase64String(signs);
privateKeyEnSignature = signs;
StringBuilder s = new StringBuilder();
foreach (var b in signs)
{
s.Append(b.ToString("X2") + " ");
}
s.AppendLine("总字节数:" + signs.Length);
s.AppendLine("ConvertBase64:" + signdata);
PrivateKeyEnSignature = s.ToString();
}
/// <summary>
/// 验证签名方法
/// </summary>
public void PublicKeyDeSignatureMethod()
{
if (privateKeyEnSignature == null)
{
RunInfo = "请先进行私钥加密";
return;
}
//原始数据
byte[] infos = Encoding.UTF8.GetBytes(m_PlainText);
//获取公钥
RSACryptoServiceProvider myRSACryptoServiceProvider = (RSACryptoServiceProvider)selfCertificate.PublicKey.Key;
//验证数据,用公钥对加密的摘要值进行解密,并于原数据计算的摘要值进行比对
if (myRSACryptoServiceProvider.VerifyData(infos, "MD5", privateKeyEnSignature ))
{
PublicKeyDeSignature = "验证成功";
return;
}
PublicKeyDeSignature = "验证失败";
}
总结
既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密;同理,既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证。
参考
https://www.cnblogs.com/yank/p/DigitalCertification.html
https://www.cnblogs.com/yank/p/3533998.html
https://www.cnblogs.com/chnking/archive/2007/08/18/860983.html
您的资助是我最大的动力!
金额随意,欢迎来赏!
出处:https://www.cnblogs.com/lovexinyi/
版权:本文版权归作者和博客园共有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文链接;否则必究法律责任