本文討論如何在 WinUI 應用程式中使用訊息認證碼(MAC)、雜湊值與簽名來偵測訊息竄改。
訊息認證碼(MAC)
加密有助於防止未經授權的人閱讀訊息,但無法阻止該人篡改訊息。 即使改變訊息後變得毫無意義,它仍然可能帶來實際的代價。 訊息認證碼(MAC)有助於防止訊息被竄改。 例如,請考慮下列案例:
- Bob 和 Alice 共用一把秘密金鑰,並同意使用一個 MAC 函式。
- Bob 建立訊息,並將訊息與秘密金鑰輸入 MAC 函式以取得 MAC 值。
- Bob 會透過網路將[未加密]訊息和 MAC 值傳送給 Alice。
- Alice 使用秘密金鑰和訊息作為 MAC 函式的輸入。 她將產生的 MAC 值與 Bob 傳送的 MAC 值做比較。 如果是相同的,訊息在傳輸過程中沒有被更改。
請注意,偷聽鮑伯與愛麗絲對話的第三方伊芙無法有效操控訊息。 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.");
}
}
}
}
Hashes
密碼學雜湊函數會接收任意長度的資料區塊,並回傳一個固定大小的位元字串。 雜湊函數通常用於簽署資料時。 由於大多數公鑰簽章操作計算量大,通常對訊息雜湊值進行簽署(加密)效率高於簽署原始訊息。 以下程序代表一個常見但較簡化的情境:
- Alice 有一對公私金鑰,想把簽名訊息傳送給 Bob。
- Alice 建立訊息並利用雜湊函數計算訊息的雜湊值。
- Alice 用她的私鑰簽署雜湊值,並透過網路將[未加密]訊息和簽名傳送給 Bob。
- Bob 會用相同的雜湊函數計算收到訊息的雜湊值。 接著他使用 Alice 的公開金鑰解密簽名,並與計算出的雜湊值進行比較。 如果是相同的,訊息在傳輸過程中沒有被更改,而是來自愛麗絲。
請注意,Alice 發送了一則未加密的訊息。 只有雜湊值被加密了。 此程序僅確保原始訊息未被更改,且透過使用 Alice 的公開金鑰,訊息雜湊值由擁有 Alice 私鑰存取權的人簽署,推測為 Alice。
你可以使用 HashAlgorithmProvider 類別來枚舉可用的雜湊演算法,並建立 CryptographicHash 值。
數位簽章是公鑰中私鑰訊息驗證碼(MAC)的等價物。 MAC 使用私鑰讓訊息接收者確認訊息在傳輸過程中未被更改,而簽章則使用私鑰/公鑰對。
CryptographicHash 物件可用於反覆雜湊不同資料,而無需每次都重新建立物件。 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 類別中使用靜態方法來簽署訊息或驗證簽名。