證書加密與驗證


網絡威脅

1.竊聽:網絡傳輸是在公共信道上進行的,特別是HTTP傳輸大多以明文傳輸,黑客進行竊聽,獲取敏感信息。

2.偽裝:這個基本每個人都遇到過,早期詐騙,說你賬戶被盜要求你登錄改密碼,會進入一個與官網相似的改密碼頁面來獲取你的真實密碼。

3.篡改:信息在提交到服務器之前被非法修改,黑客可以盜取用戶的Session、Cache信息,來修改提交到服務器的請求信息。

4.抵賴:用戶可以否定自己曾經做過的事情。在日常生活中也會遇到同樣的問題,比如領導明明安排的一個任務,但你可能忘記了就說不知道,沒人通知你,這就叫抵賴

基本概念

證書是針對上述網絡威脅建立起來的解決方案,基本概念:

  1. CA(Certificate Authority):數字證書認證中心。發放、管理、廢除數字證書的機構,CA的作用是檢查證書持有者身份的合法性,並簽發證書(在證書上簽字),以防證書被偽造或篡改,以及對證書和密鑰進行管理。
  2. 證書有以下信息:證書頒布機構,證書的有效期,公鑰,私鑰,簽名及所用算法,指紋和指紋算法。
    1. 證書頒布機構(Issuer):指出是什么機構發布的這個證書,也就是指明這個證書是哪個公司創建的(只是創建證書,不是指證書的使用者)。
    2. 證書有效期(Valid from , Valid to):證書的使用期限。 過了有效期限,證書就會作廢,不能使用了
    3. 主體(Subject):證書是發布給誰的,或者說證書的所有者
    4. 簽名所使用的算法(Signature algorithm):指的這個數字證書的數字簽名所使用的加密算法。
    5. 指紋及指紋算法(Thumbprint, Thumbprint algorithm):這個是用來保證證書的完整性的,也就是說確保證書沒有被修改過。 其原理就是在發布證書時,發布者根據指紋算法(一個hash算法)計算整個證書的hash值(指紋)並和證書放在一起,使用者在打開證書時,自己也根據指紋算法計算一下證書的hash值(指紋),如果和剛開始的值對得上,就說明證書沒有被修改過,因為證書的內容被修改后,根據證書的內容計算的出的hash值(指紋)是會變化的。

證書的特性:

  1. 保密性(Privacy):確認信息的保密,不被竊取。
  2. 鑒別與授權(Authentication & Authorization):確認對方的身份並確保其不越權
  3. 完整性(Integrity):確保你收到信息沒有被篡改
  4. 抗抵賴性(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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM