MAC、雜湊以及簽章

本文討論如何在通用 Windows 平台 (UWP) 應用程式中使用訊息驗證程式碼 (MAC)、雜湊值和簽章來偵測訊息竄改。

訊息驗證碼 (MAC)

加密有助於防止未經授權的個人讀取訊息,但不能防止該個人篡改訊息。 經過修改的訊息,即使這種修改只會帶來無意義的結果,也可能會產生實際成本。 訊息驗證碼 (MAC) 有助於防止訊息被竄改。 例如,請考慮下列案例:

  • Bob 和 Alice 共用秘密金鑰,並同意 MAC 函式使用。
  • Bob 建立一則訊息並將該訊息和金鑰輸入到 MAC 函數中以檢索 MAC 值。
  • Bob 透過網路將 [未加密] 訊息和 MAC 值傳送給 Alice。
  • Alice 會使用秘密金鑰和訊息作為 MAC 函式的輸入。 她將產生的 MAC 值與 Bob 傳送的 MAC 值進行比較。 如果相同,則訊息不會在傳輸中變更。

請注意,第三方竊聽 Bob 與 Alice 之間的交談,無法有效地操作訊息。 Eve 無法存取私鑰,因此無法建立 MAC 值,使被篡改的訊息對 Alice 來說顯得合法。

建立訊息身分驗證代碼僅確保原始訊息未被變更,並且透過使用共用密鑰,訊息雜湊由有權存取該私鑰的人簽署。

您可以使用 MacAlgorithmProvider 列舉可用的 MAC 演算法並產生對稱密鑰。 您可以在 CryptographicEngine 類別上使用靜態方法,以執行建立 MAC 值的必要加密。

數位簽署是相當於私鑰訊息認證碼 (MAC) 的公鑰。 儘管 MAC 使用私鑰使訊息接收者能夠驗證訊息在傳輸過程中沒有被變更,但簽章使用私鑰/公鑰對。

此範例程式碼示範如何使用 MacAlgorithmProvider 類別來建立雜湊訊息驗證碼 (HMAC)。

using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;

namespace SampleMacAlgorithmProvider
{
    sealed partial class MacAlgProviderApp : Application
    {
        public MacAlgProviderApp()
        {
            // Initialize the application.
            this.InitializeComponent();

            // Initialize the hashing process.
            String strMsg = "This is a message to be authenticated";
            String strAlgName = MacAlgorithmNames.HmacSha384;
            IBuffer buffMsg;
            CryptographicKey hmacKey;
            IBuffer buffHMAC;

            // Create a hashed message authentication code (HMAC)
            this.CreateHMAC(
                strMsg,
                strAlgName,
                out buffMsg,
                out hmacKey,
                out buffHMAC);

            // Verify the HMAC.
            this.VerifyHMAC(
                buffMsg,
                hmacKey,
                buffHMAC);
        }

        void CreateHMAC(
            String strMsg,
            String strAlgName,
            out IBuffer buffMsg,
            out CryptographicKey hmacKey,
            out IBuffer buffHMAC)
        {
            // Create a MacAlgorithmProvider object for the specified algorithm.
            MacAlgorithmProvider objMacProv = MacAlgorithmProvider.OpenAlgorithm(strAlgName);

            // Demonstrate how to retrieve the name of the algorithm used.
            String strNameUsed = objMacProv.AlgorithmName;

            // Create a buffer that contains the message to be signed.
            BinaryStringEncoding encoding = BinaryStringEncoding.Utf8;
            buffMsg = CryptographicBuffer.ConvertStringToBinary(strMsg, encoding);

            // Create a key to be signed with the message.
            IBuffer buffKeyMaterial = CryptographicBuffer.GenerateRandom(objMacProv.MacLength);
            hmacKey = objMacProv.CreateKey(buffKeyMaterial);

            // Sign the key and message together.
            buffHMAC = CryptographicEngine.Sign(hmacKey, buffMsg);

            // Verify that the HMAC length is correct for the selected algorithm
            if (buffHMAC.Length != objMacProv.MacLength)
            {
                throw new Exception("Error computing digest");
            }
         }

        public void VerifyHMAC(
            IBuffer buffMsg,
            CryptographicKey hmacKey,
            IBuffer buffHMAC)
        {
            // The input key must be securely shared between the sender of the HMAC and 
            // the recipient. The recipient uses the CryptographicEngine.VerifySignature() 
            // method as follows to verify that the message has not been altered in transit.
            Boolean IsAuthenticated = CryptographicEngine.VerifySignature(hmacKey, buffMsg, buffHMAC);
            if (!IsAuthenticated)
            {
                throw new Exception("The message cannot be verified.");
            }
        }
    }
}

雜湊

加密雜湊函數採用任意長的資料塊並傳回固定大小的位元字串。 雜湊函數通常在對資料進行簽署時使用。 由於大多數公鑰簽署操作都是計算密集型的,因此對訊息雜湊進行簽署 (加密) 通常比對原始訊息進行簽署更有效。 以下過程代表了一個常見但簡化的場景:

  • Bob 和 Alice 共用秘密金鑰,並同意 MAC 函式使用。
  • Bob 建立一則訊息並將該訊息和金鑰輸入到 MAC 函數中以檢索 MAC 值。
  • Bob 透過網路將 [未加密] 訊息和 MAC 值傳送給 Alice。
  • Alice 會使用秘密金鑰和訊息作為 MAC 函式的輸入。 她將產生的 MAC 值與 Bob 傳送的 MAC 值進行比較。 如果相同,則訊息不會在傳輸中變更。

請注意,Alice 傳送了一條未加密的訊息。 僅雜湊被加密。 這個過程僅確保原始訊息未被變更,並且透過使用 Alice 的公鑰,訊息雜湊由有權存取 Alice 私鑰的人 (大概是 Alice) 簽署。

您可以使用 HashAlgorithmProvider 類別枚舉可用的雜湊演算法並建立 CryptographicHash 值。

數位簽署是相當於私鑰訊息認證碼 (MAC) 的公鑰。 儘管 MAC 使用私鑰使訊息接收者能夠驗證訊息在傳輸過程中沒有被變更,但簽章使用私鑰/公鑰對。

CryptographicHash.GetValueAndReset 物件可用於重複雜湊不同的數據,而無需為每次使用重新建立物件。 Append 方法將新資料新增至要進行雜湊處理的緩衝區。 GetValueAndReset 方法對資料進行雜湊處理並重設物件以供其他用途。 下列範例會顯示這一點。

public void SampleReusableHash()
{
    // Create a string that contains the name of the hashing algorithm to use.
    String strAlgName = HashAlgorithmNames.Sha512;

    // Create a HashAlgorithmProvider object.
    HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm(strAlgName);

    // Create a CryptographicHash object. This object can be reused to continually
    // hash new messages.
    CryptographicHash objHash = objAlgProv.CreateHash();

    // Hash message 1.
    String strMsg1 = "This is message 1.";
    IBuffer buffMsg1 = CryptographicBuffer.ConvertStringToBinary(strMsg1, BinaryStringEncoding.Utf16BE);
    objHash.Append(buffMsg1);
    IBuffer buffHash1 = objHash.GetValueAndReset();

    // Hash message 2.
    String strMsg2 = "This is message 2.";
    IBuffer buffMsg2 = CryptographicBuffer.ConvertStringToBinary(strMsg2, BinaryStringEncoding.Utf16BE);
    objHash.Append(buffMsg2);
    IBuffer buffHash2 = objHash.GetValueAndReset();

    // Hash message 3.
    String strMsg3 = "This is message 3.";
    IBuffer buffMsg3 = CryptographicBuffer.ConvertStringToBinary(strMsg3, BinaryStringEncoding.Utf16BE);
    objHash.Append(buffMsg3);
    IBuffer buffHash3 = objHash.GetValueAndReset();

    // Convert the hashes to string values (for display);
    String strHash1 = CryptographicBuffer.EncodeToBase64String(buffHash1);
    String strHash2 = CryptographicBuffer.EncodeToBase64String(buffHash2);
    String strHash3 = CryptographicBuffer.EncodeToBase64String(buffHash3);
}

數位簽章

數位簽署是相當於私鑰訊息認證碼 (MAC) 的公鑰。 儘管 MAC 使用私鑰使訊息接收者能夠驗證訊息在傳輸過程中沒有被變更,但簽章使用私鑰/公鑰對。

由於大多數公鑰簽署操作都是計算密集型的,因此對訊息雜湊進行簽署 (加密) 通常比對原始訊息進行簽署更有效。 傳送者建立訊息雜湊,對其進行簽署,然後傳送簽署和 (未加密的) 訊息。 接收者計算訊息的雜湊值,解密簽署,並將簽署的簽名與雜湊值進行比較。 如果相符,接收者可以相當確定該訊息確實來自傳送者並且在傳輸過程中沒有被變更。

簽署僅確保原始訊息未被變更,並且透過使用傳送者的公鑰,訊息雜湊由有權存取私鑰的人簽署。

您可以使用 AsymmetricKeyAlgorithmProvider 物件來列舉可用的簽署演算法,併產生或匯入密鑰組。 您可以在 CryptographicHash 類別上使用靜態方法來簽署訊息或驗證簽章。