MAC、ハッシュ、および署名MACs, hashes, and signatures

この記事では、ユニバーサル Windows プラットフォーム (UWP) アプリでメッセージ認証コード (MAC)、ハッシュ、署名を使ってメッセージの改ざんを検出する方法について説明します。This article discusses how message authentication codes (MACs), hashes, and signatures can be used in Universal Windows Platform (UWP) apps to detect message tampering.

メッセージ認証コード (MAC)Message authentication codes (MACs)

暗号化は、承認されていない個人によるメッセージの読み取りを防止できますが、その個人によるメッセージの改ざんを防止することはできません。Encryption helps prevent an unauthorized individual from reading a message, but it does not prevent that individual from tampering with the message. メッセージが改ざんされたことにより、そのメッセージが無意味な内容にすぎない場合であっても、実際にコストが発生する場合があります。An altered message, even if the alteration results in nothing but nonsense, can have real costs. メッセージ認証コード (MAC) は、メッセージの改ざんを防止します。A message authentication code (MAC) helps prevent message tampering. たとえば、次のシナリオについて考えてみます。For example, consider the following scenario:

  • ボブとアリスは秘密鍵を共有し、MAC 関数を使うことに同意しています。Bob and Alice share a secret key and agree on a MAC function to use.
  • ボブはメッセージを作成し、そのメッセージと秘密鍵を MAC 関数に入力して MAC 値を取得します。Bob creates a message and inputs the message and the secret key into a MAC function to retrieve a MAC value.
  • Bob の送信、[暗号化されていない]メッセージと、MAC、ネットワーク経由で alice 値します。Bob sends the [unencrypted] message and the MAC value to Alice over a network.
  • アリスは秘密鍵とメッセージを使って MAC 関数に入力します。Alice uses the secret key and the message as input to the MAC function. アリスは、生成された MAC 値とボブから受け取った MAC 値を比較します。She compares the generated MAC value to the MAC value sent by Bob. 両者が同じものである場合、メッセージは転送中に変更されていません。If they are the same, the message was not changed in transit.

ボブとアリスの通信を傍受する第三者のイブは、メッセージを効果的に操作できません。Note that Eve, a third party eavesdropping on the conversation between Bob and Alice, cannot effectively manipulate the message. イブは秘密キーにアクセスできないため、アリスに対して改ざんされたメッセージが本物であるかのように見せる MAC 値を作成することができません。Eve does not have access to the private key and cannot, therefore, create a MAC value which would make the tampered message appear legitimate to Alice.

メッセージ認証コードの作成によって保証されるのは、元のメッセージが改ざんされていないことと、共有の秘密鍵を使ったことから、その秘密鍵にアクセスできる人物によってメッセージ ハッシュへの署名が行われたことのみです。Creating a message authentication code ensures only that the original message was not altered and, by using a shared secret key, that the message hash was signed by someone with access to that private key.

MacAlgorithmProvider を使って、利用可能な MAC アルゴリズムを列挙して対称キーを生成することができます。You can use the MacAlgorithmProvider to enumerate the available MAC algorithms and generate a symmetric key. CryptographicEngine クラスで静的メソッドを使って、MAC 値を作成する必要な暗号化を実行することができます。You can use static methods on the CryptographicEngine class to perform the necessary encryption that creates the MAC value.

デジタル署名は、秘密キーによるメッセージ認証コード (MAC) と等価の公開キーのコードです。Digital signatures are the public key equivalent of private key message authentication codes (MACs). MAC ではメッセージが転送中に改ざんされなかったことをメッセージの受信者が確認するのに秘密キーを使いますが、署名では秘密キーと公開キーのペアを使います。Although MACs use private keys to enable a message recipient to verify that a message has not been altered during transmission, signatures use a private/public key pair.

次のコード例は、MacAlgorithmProvider クラスを使ってハッシュ メッセージ認証コード (HMAC) を作成する方法を示しています。This example code shows how to use the MacAlgorithmProvider class to create a hashed message authentication code (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.");
            }
        }
    }
}

HashesHashes

暗号化ハッシュ関数は任意の長さのデータ ブロックを受け取り、固定ビット サイズの文字列を返します。A cryptographic hash function takes an arbitrarily long block of data and returns a fixed-size bit string. 通常、ハッシュ関数はデータへの署名時に使われます。Hash functions are typically used when signing data. 多くの公開キー署名操作は負荷が高いため、通常は元のメッセージに署名 (暗号化) するよりもメッセージのハッシュに署名する方が効率的です。Because most public key signature operations are computationally intensive, it is typically more efficient to sign (encrypt) a message hash than it is to sign the original message. 次の手順では、一般的なシナリオを簡略化して説明します。The following procedure represents a common, albeit simplified, scenario:

  • ボブとアリスは秘密鍵を共有し、MAC 関数を使うことに同意しています。Bob and Alice share a secret key and agree on a MAC function to use.
  • ボブはメッセージを作成し、そのメッセージと秘密鍵を MAC 関数に入力して MAC 値を取得します。Bob creates a message and inputs the message and the secret key into a MAC function to retrieve a MAC value.
  • Bob の送信、[暗号化されていない]メッセージと、MAC、ネットワーク経由で alice 値します。Bob sends the [unencrypted] message and the MAC value to Alice over a network.
  • アリスは秘密鍵とメッセージを使って MAC 関数に入力します。Alice uses the secret key and the message as input to the MAC function. アリスは、生成された MAC 値とボブから受け取った MAC 値を比較します。She compares the generated MAC value to the MAC value sent by Bob. 両者が同じものである場合、メッセージは転送中に変更されていません。If they are the same, the message was not changed in transit.

アリスは暗号化されていないメッセージを送信したことに注目してください。Note that Alice sent an unencrypted message. ハッシュが暗号化されただけです。Only the hash was encrypted. この手順によって保証されるのは、元のメッセージが改変されていないことと、アリスの公開キーが使われていることから、アリスの秘密キーにアクセスできるだれか、おそらくアリス本人によってメッセージのハッシュが署名されたことだけです。The procedure ensures only that the original message was not altered and, by using Alice's public key, that the message hash was signed by someone with access to Alice's private key, presumably Alice.

HashAlgorithmProvider クラスを使って利用できるハッシュ アルゴリズムを列挙し、CryptographicHash 値を作成することができます。You can use the HashAlgorithmProvider class to enumerate the available hash algorithms and create a CryptographicHash value.

デジタル署名は、秘密キーによるメッセージ認証コード (MAC) と等価の公開キーのコードです。Digital signatures are the public key equivalent of private key message authentication codes (MACs). MAC ではメッセージが転送中に改変されなかったことをメッセージの受信者が確認するのに秘密キーを使いますが、署名では秘密キーと公開キーのペアを使います。Whereas MACs use private keys to enable a message recipient to verify that a message has not been altered during transmission, signatures use a private/public key pair.

CryptographicHash オブジェクトを使うと、その都度オブジェクトを作らなくても、異なるデータを繰り返しハッシュできます。The CryptographicHash object can be used to repeatedly hash different data without having to re-create the object for each use. Append メソッドは、ハッシュ対象のバッファーに、新しいデータを追加します。The Append method adds new data to a buffer to be hashed. GetValueAndReset メソッドは、データをハッシュし、次の使用のためにオブジェクトをリセットします。The GetValueAndReset method hashes the data and resets the object for another use. この例を次に示します。This is shown by the following example.

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);
}

デジタル署名Digital signatures

デジタル署名は、秘密キーによるメッセージ認証コード (MAC) と等価の公開キーのコードです。Digital signatures are the public key equivalent of private key message authentication codes (MACs). MAC ではメッセージが転送中に改変されなかったことをメッセージの受信者が確認するのに秘密キーを使いますが、署名では秘密キーと公開キーのペアを使います。Whereas MACs use private keys to enable a message recipient to verify that a message has not been altered during transmission, signatures use a private/public key pair.

多くの公開キー署名操作は負荷が高いため、通常は元のメッセージに署名 (暗号化) するよりもメッセージのハッシュに署名する方が効率的です。Because most public key signature operations are computationally intensive, however, it is typically more efficient to sign (encrypt) a message hash than it is to sign the original message. 送信者はメッセージのハッシュを作成してそれに署名し、署名と (暗号化されていない) メッセージの両方を送ります。The sender creates a message hash, signs it, and sends both the signature and the (unencrypted) message. 受信者はメッセージのハッシュを計算し、署名の暗号化を解除し、暗号化を解除した署名を計算したハッシュ値と比較します。The recipient calculates a hash over the message, decrypts the signature, and compares the decrypted signature to the hash value. これらが一致する場合、メッセージが本当に送信者からのものであり、転送中に改変されていないことを受信者は確信できます。If they match, the recipient can be fairly certain that the message did, in fact, come from the sender and was not altered during transmission.

署名によって保証されるのは、元のメッセージが改変されていないことと、送信者の公開キーが使われていることから、秘密キーにアクセスできる人によってメッセージのハッシュが署名されたことだけです。Signing ensures only that the original message was not altered and, by using the sender's public key, that the message hash was signed by someone with access to the private key.

AsymmetricKeyAlgorithmProvider オブジェクトを使って、利用できる署名アルゴリズムを列挙したり、キー ペアを生成またはインポートしたりできます。You can use an AsymmetricKeyAlgorithmProvider object to enumerate the available signature algorithms and generate or import a key pair. CryptographicHash クラスの静的メソッドを使って、メッセージに署名したり、署名を検証したりできます。You can use static methods on the CryptographicHash class to sign a message or verify a signature.