次の方法で共有


MAC、ハッシュ、署名

この記事では、ユニバーサル 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 クラスで静的メソッドを使用して、メッセージに署名したり、署名を検証したりできます。