iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 21
0
Security

資料安全與簡單加密演算法見面會 系列 第 21

[Day21] 資料傳輸安全(完整性)數位簽章

我們進入資料傳輸安全後,陸續複習了簡單雜湊(Hash)及訊息驗證(authication check),而除了這兩天複習的訊息驗證碼(MAC)可以強化雜湊驗證的識別性外,還有一種數位簽章(Digital Signature)也可以確保我們在檔案傳輸時的完整性及身份識別。

數位簽章 (Digital Signature)


數位簽章(Digital Signature)也是出道很久的安全技術,她是一種電子式的簽名機制,概念是根據檔案內容運算出一個加密後的雜湊驗證值讓資料接收端驗證,可以確保檔案是由正確的來源(避免身分偽冒)而且內容有完整的傳遞。

數位簽章主要使用雜湊與加密演算法的組合,雜湊(hash)可以確保完整,透過安全的金鑰加密雜湊則可以確保正確的識別

數位簽章與訊息驗證碼(MAC)雖然功能類似,但在金鑰的使用以及演算法上還是有些不同的地方:

  • 訊息驗證碼(MAC)主要使用XOR計算與對稱式加密家族(symmetric-key algorithm)下的DES加密演算法
  • 數位簽章則使用雜湊(Hash)及公開金鑰密碼系統下的RSA加密演算法對雜湊值加密。
    (公開金鑰密碼系統也就是非對稱式加密:asymmetric-key algorithm,是一種天上一對,地上一雙的組合)

C#中可選擇的Library

  • RSA:RSACryptoServiceProvider
  • DSA:DSACryptoServiceProvider 也可以使用,但較舊,已不建議使用

這邊我們舉RSA的演算法為範例。

未加密前的測試檔案


為了方便我們聚焦在數位簽章的使用,先把寫出測試檔並回傳檔案內容的功能撰寫好。

public string getFile()
{
    List<string> datas = new List<string>()
    {
        "4567-1111-2222-3333,高雄台鋁生活商場,1000",
        "4567-1111-2222-3333,台北微風信義分店,2000",
        "5567-1111-2222-3333,台南南紡購物中心,3000",
        "END,3,6000"
    };

    StringBuilder sb = new StringBuilder();
    using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\temp\transaction.txt", false))
    {
        foreach (var data in datas)
        {
            sb.AppendLine(data);
            byte[] bdata = Encoding.Default.GetBytes(data);
            file.WriteLine($"{data}");
        }
    }
    return sb.ToString();
}

加密流程


1.請款廠商建立一組RSA的公鑰及私鑰。
2.檔案內容先經過雜湊(這邊假設我們選擇SHA256)後,取出雜湊值。
3.然後使用私鑰以RSA加密演算法加密。
4.加密後的結果合併在原始檔案之後。

簡單畫一個加密流程圖:
http://ithelp.ithome.com.tw/upload/images/20170105/20103434kYaCdgtWGx.jpg

雖然這次數位簽章使用的是RSA加密演算法,不過這邊在加密時並不是使用檔案接收端公開出去的公鑰而是請款檔案的廠商的私鑰

好!來寫程式測試了。

[TestMethod]
public void TestEncrypt()
{
    //建立RSA演算法物件
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    
    //顯示公開金鑰
    Console.WriteLine($"public key:{rsa.ToXmlString(false)}");
    //顯示私有金鑰
    Console.WriteLine($"private key:{rsa.ToXmlString(true)}");

    //讀取本文資料
    byte[] plainText = Encoding.Unicode.GetBytes(getFile());

    //進行簽章(假設我們使用SHA256)
    byte[] signText = rsa.SignData(plainText, new SHA256CryptoServiceProvider());

    //寫出簽章檔案
    using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\temp\transaction.txt", true))
    {
        file.WriteLine("\t" + Convert.ToBase64String(signText));
    }
}

加密後的檔案驗證結果:
http://ithelp.ithome.com.tw/upload/images/20170105/20103434PQOlKO2JMl.png

確保檔案是請款廠商給的,而且檔案未遭竄改。

我們在測試時先簡單建立RSA演算法所使用的參數,但實際操作時請必須把金鑰儲存在憑證中,我們只要在建立RSA演算法物件帶入csp參數並指定金鑰容器及儲存位置。

CspParameters param = new CspParameters();
param.KeyContainerName = "TestDigitalSignature";
param.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param);

驗證流程


1.取得請款廠商的公開金鑰(或是安裝廠商的憑證)。
2.將檔案內容以分隔符號拆解成原始檔案內容加密後的雜湊值兩部分。
3.原始檔案內容先經過雜湊後只取出雜湊值,然後再以RSA加密演算法解密。
4.然後比較加密後的雜湊值是否與步驟3相符。

簡單畫一個解密驗證流程圖:
http://ithelp.ithome.com.tw/upload/images/20170105/20103434I4cir0QmpB.jpg

 [TestMethod]
 public void TestVerify()
 {

     //建立RSA演算法物件
     RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();

     //假設我們已經安裝了這家商店的憑證,也就是我們本來就有公鑰
     //public key
     string pk = @"<RSAKeyValue>
                   <Modulus>qRE+tUrBv52zLWcVmB24uR3dDkLrhmdzxKy9eJCKW7cuFz+DTOrJKqF+l0ek+JJELVx8VbzSLsFP5s/uVMpSZXN3r23EHC8cQ5nfUfT2C5kT6URdhB6Ucx9TB4TlVLwv3iaLXfdAtnoUpDVhmIXOScvewRAlwV+e5zlIMsOzG2U=</Modulus>
                     <Exponent>AQAB</Exponent>
                   </RSAKeyValue>";

     //載入公開金鑰
     rsa.FromXmlString(pk);     //讀取公開金鑰

     //讀取本文資料
     string AllText = System.IO.File.ReadAllText(@"C:\temp\transaction.txt");

     //使用分隔符號拆解
     if (!AllText.Contains("\t"))
     {
         Console.WriteLine("明文與簽章資料缺少分隔符號\t");
         return;
     }

     byte[] DataText = Encoding.Unicode.GetBytes(AllText.Split('\t')[0]);
     byte[] signText = Convert.FromBase64String(AllText.Split('\t')[1]);

     //驗證數位簽章正確性
     if (rsa.VerifyData(DataText, new SHA256CryptoServiceProvider(), signText))
     {
         Console.WriteLine("驗證成功!");
     }
     else
     {
         Console.WriteLine("驗證失敗!");
     }

 }

驗證成功!
http://ithelp.ithome.com.tw/upload/images/20170105/201034345ZxmRSF2e8.png

數位簽章希望全世界都能確認自己的身份,而一般RSA加密演算法則希望別人給自己資料時的機密性,所以在公開金鑰與私有金鑰的使用有很大的差異。

  • 數位簽章:以私有金鑰加密,公開金鑰解密。
  • 一般RSA:公開金鑰開始,私有金鑰解密。

參考:


DSACryptoServiceProvider
https://msdn.microsoft.com/zh-tw/library/system.security.cryptography.dsacryptoserviceprovider(v=vs.110).aspx

RSACryptoServiceProvider
https://msdn.microsoft.com/zh-tw/library/system.security.cryptography.rsacryptoserviceprovider(v=vs.110).aspx

余小章 @ 大內殿堂 [C#.NET] 字串及檔案,利用 RSA 演算法加解密
https://dotblogs.com.tw/yc421206/archive/2012/06/25/73041.aspx


每天早上4.5點起來很拚,來掛上新竹馬拉松的完賽御守加持。

http://ithelp.ithome.com.tw/upload/images/20170105/20103434bySckE6VGn.jpg


上一篇
[Day20] 資料傳輸安全(完整性)MAC訊息驗證碼 (下)
下一篇
[Day22] 資料傳輸安全(機密性) RSA x AES 混搭風(上)
系列文
資料安全與簡單加密演算法見面會 30

尚未有邦友留言

立即登入留言