この記事では、ユニバーサル Windows プラットフォーム (UWP) アプリでメッセージ認証コード (MAC)、ハッシュ、署名を使用してメッセージの改ざんを検出する方法について説明します。
メッセージ認証コード (MAC)
暗号化は、承認されていない個人がメッセージを読むのを防ぐのに役立ちますが、その個人がメッセージを改ざんするのを防ぐことはありません。 変更されたメッセージは、変更によってナンセンス以外の何も発生しない場合でも、実際のコストが発生する可能性があります。 メッセージ認証コード (MAC) は、メッセージの改ざんを防ぐのに役立ちます。 たとえば、次のシナリオを考えてみましょう。
- Bob と Alice は秘密鍵を共有し、使用する MAC 関数に同意します。
- Bob はメッセージを作成し、MAC 関数にメッセージと秘密鍵を入力して MAC 値を取得します。
- Bob は、[暗号化されていない] メッセージと MAC 値をネットワーク経由で Alice に送信します。
- Alice は、MAC 関数への入力として秘密鍵とメッセージを使用します。 生成された MAC 値と Bob から送信された MAC 値を比較します。 同じ場合、メッセージは転送中に変更されませんでした。
Bob と Alice の間の会話を傍受しているサード パーティのイブは、メッセージを効果的に操作できないことに注意してください。 Eve には秘密キーへのアクセス権がないため、改ざんされたメッセージが Alice に正当に表示される MAC 値を作成することはできません。
メッセージ認証コードを作成すると、元のメッセージが変更されず、共有秘密キーを使用して、その秘密キーにアクセスできるユーザーによってメッセージ ハッシュが署名されたことのみが保証されます。
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.");
}
}
}
}
ハッシュ
暗号化ハッシュ関数は、任意に長いデータ ブロックを受け取り、固定サイズのビット文字列を返します。 ハッシュ関数は、通常、データの署名時に使用されます。 ほとんどの公開キー署名操作は計算負荷が高いため、通常、元のメッセージに署名するよりもメッセージ ハッシュに署名 (暗号化) する方が効率的です。 次の手順は、簡略化された一般的なシナリオを表しています。
- Alice には公開キーと秘密キーのペアがあり、Bob に署名済みメッセージを送信したいと考えています。
- Alice はメッセージを作成し、ハッシュ関数を使用してメッセージのハッシュを計算します。
- Alice は秘密キーを使用してハッシュに署名し、[暗号化されていない] メッセージと署名をネットワーク経由で Bob に送信します。
- Bob は、同じハッシュ関数を使用して、受信したメッセージのハッシュを計算します。 その後、Alice の公開キーを使用して署名の暗号化を解除し、計算されたハッシュと比較します。 同じ場合、メッセージは転送中に変更されず、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 クラスで静的メソッドを使用して、メッセージに署名したり、署名を検証したりできます。