MAC, hash y firmasMACs, hashes, and signatures

En este artículo se describe cómo se pueden utilizar los códigos de autenticación de mensaje (MAC), los hash y las firmas en las aplicaciones de la Plataforma universal de Windows (UWP) para detectar mensajes manipulados.This article discusses how message authentication codes (MACs), hashes, and signatures can be used in Universal Windows Platform (UWP) apps to detect message tampering.

Códigos de autenticación de mensaje (MAC)Message authentication codes (MACs)

El cifrado ayuda a impedir que personas no autorizadas puedan leer un mensaje, pero no evita que una persona pueda manipular el mensaje.Encryption helps prevent an unauthorized individual from reading a message, but it does not prevent that individual from tampering with the message. La modificación de un mensaje, aunque produzca algo sin sentido, puede tener un impacto grave.An altered message, even if the alteration results in nothing but nonsense, can have real costs. Los códigos de autenticación de mensaje (MAC) ayudan a prevenir la manipulación de mensajes.A message authentication code (MAC) helps prevent message tampering. Por ejemplo, tenga en cuenta el siguiente caso:For example, consider the following scenario:

  • Roberto y Alicia comparten una clave secreta y se ponen de acuerdo para usar una función MAC.Bob and Alice share a secret key and agree on a MAC function to use.
  • Roberto crea un mensaje y suministra el mensaje y la clave secreta a la función MAC para obtener un valor MAC.Bob creates a message and inputs the message and the secret key into a MAC function to retrieve a MAC value.
  • Roberto envía el [ mensaje sin cifrar ] y el valor Mac a Alice a través de una red.Bob sends the [unencrypted] message and the MAC value to Alice over a network.
  • Alicia usa la clave secreta y el mensaje como entrada de la función MAC.Alice uses the secret key and the message as input to the MAC function. Compara el valor MAC generado con el valor MAC enviado por Roberto.She compares the generated MAC value to the MAC value sent by Bob. Si coinciden, significa que no se manipuló el mensaje durante el tránsito.If they are the same, the message was not changed in transit.

Eva, que interceptó la conversación de Roberto y Alicia, no puede manipular el mensaje.Note that Eve, a third party eavesdropping on the conversation between Bob and Alice, cannot effectively manipulate the message. Eva no tiene acceso a la clave privada y, por lo tanto, no puede crear un valor MAC que pueda hacer que el mensaje manipulado para Alicia parezca genuino.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.

Crear un código de autenticación de mensaje solo garantiza que no se manipuló el mensaje original y, mediante una clave secreta compartida, que alguien con acceso a esa clave privada firmó el hash de mensaje.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.

Puedes usar el MacAlgorithmProvider para enumerar los algoritmos de MAC disponibles y generar una clave simétrica.You can use the MacAlgorithmProvider to enumerate the available MAC algorithms and generate a symmetric key. Puedes usar métodos estáticos en la clase CryptographicEngine para realizar el cifrado necesario para crear el valor MAC.You can use static methods on the CryptographicEngine class to perform the necessary encryption that creates the MAC value.

Las firmas digitales son el equivalente de clave pública a los códigos de autenticación de mensaje (MAC) de clave privada.Digital signatures are the public key equivalent of private key message authentication codes (MACs). Aunque los MAC usan claves privadas para permitir que el destinatario de un mensaje compruebe que no se ha manipulado un mensaje durante la transmisión, las firmas usan un par de claves, la pública y la privada.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.

Este código de ejemplo muestra cómo usar la clase MacAlgorithmProvider para crear un código de autenticación de mensajes basado en hash (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.");
            }
        }
    }
}

Códigos hashHashes

Una función hash criptográfica toma un bloque de datos de una longitud arbitraria y devuelve una cadena de bits de tamaño fijo.A cryptographic hash function takes an arbitrarily long block of data and returns a fixed-size bit string. Las funciones hash se suelen usar al firmar datos.Hash functions are typically used when signing data. Como la mayoría de las operaciones de firma con clave pública requieren realizar cálculos intensivos, suele ser más eficiente firmar (cifrar) un hash de mensaje que firmar el mensaje original.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. El siguiente procedimiento representa un escenario frecuente (aunque simplificado):The following procedure represents a common, albeit simplified, scenario:

  • Roberto y Alicia comparten una clave secreta y se ponen de acuerdo para usar una función MAC.Bob and Alice share a secret key and agree on a MAC function to use.
  • Roberto crea un mensaje y suministra el mensaje y la clave secreta a la función MAC para obtener un valor MAC.Bob creates a message and inputs the message and the secret key into a MAC function to retrieve a MAC value.
  • Roberto envía el [ mensaje sin cifrar ] y el valor Mac a Alice a través de una red.Bob sends the [unencrypted] message and the MAC value to Alice over a network.
  • Alicia usa la clave secreta y el mensaje como entrada de la función MAC.Alice uses the secret key and the message as input to the MAC function. Compara el valor MAC generado con el valor MAC enviado por Roberto.She compares the generated MAC value to the MAC value sent by Bob. Si coinciden, significa que no se manipuló el mensaje durante el tránsito.If they are the same, the message was not changed in transit.

Ten en cuenta que Alicia envió un mensaje sin cifrar.Note that Alice sent an unencrypted message. Lo que cifró fue el hash.Only the hash was encrypted. Este procedimiento solo garantiza que no se manipuló el mensaje original y, mediante la clave pública de Alicia, que alguien con acceso a la clave privada de Alicia (probablemente Alicia) firmó el hash de mensaje.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.

Puedes usar la clase HashAlgorithmProvider para enumerar los algoritmos hash disponibles y crear un valor CryptographicHash.You can use the HashAlgorithmProvider class to enumerate the available hash algorithms and create a CryptographicHash value.

Las firmas digitales son el equivalente de clave pública a los códigos de autenticación de mensaje (MAC) de clave privada.Digital signatures are the public key equivalent of private key message authentication codes (MACs). A diferencia de los MAC, que usan claves privadas para permitir que el destinatario de un mensaje compruebe que el mensaje no se ha manipulado durante la transmisión, las firmas usan un par de claves, la pública y la privada.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.

El objeto CryptographicHash puede usarse para aplicar el algoritmo hash a distintos datos repetidamente sin tener que recrear el objeto para cada uso.The CryptographicHash object can be used to repeatedly hash different data without having to re-create the object for each use. El método Append agrega nuevos datos a un búfer para que se les aplique el algoritmo hash.The Append method adds new data to a buffer to be hashed. El método GetValueAndReset aplica el algoritmo hash a los datos y restablece el objeto para otro uso.The GetValueAndReset method hashes the data and resets the object for another use. Esto se muestra en el siguiente ejemplo.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);
}

Firmas digitalesDigital signatures

Las firmas digitales son el equivalente de clave pública a los códigos de autenticación de mensaje (MAC) de clave privada.Digital signatures are the public key equivalent of private key message authentication codes (MACs). A diferencia de los MAC, que usan claves privadas para permitir que el destinatario de un mensaje compruebe que el mensaje no se ha manipulado durante la transmisión, las firmas usan un par de claves, la pública y la privada.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.

Pero como la mayoría de las operaciones de firma con clave pública requieren realizar cálculos intensivos, suele ser más eficiente firmar (cifrar) un hash de mensaje que firmar el mensaje original.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. El remitente crea un hash de mensaje, lo firma y envía la firma y el mensaje (sin cifrar).The sender creates a message hash, signs it, and sends both the signature and the (unencrypted) message. El destinatario calcula un hash para el mensaje, descifra la firma y compara la firma descifrada con el valor de hash.The recipient calculates a hash over the message, decrypts the signature, and compares the decrypted signature to the hash value. Si coinciden, el destinatario puede estar razonablemente seguro de que el mensaje proviene realmente del remitente y no se manipuló durante la transmisión.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.

La firma solo garantiza que no se manipuló el mensaje original y, mediante la clave pública del remitente, que alguien con acceso a la clave privada firmó el hash de mensaje.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.

Puedes usar un objeto AsymmetricKeyAlgorithmProvider para enumerar los algoritmos de firma disponibles y generar o importar un par de claves.You can use an AsymmetricKeyAlgorithmProvider object to enumerate the available signature algorithms and generate or import a key pair. Puedes usar métodos estáticos en la clase CryptographicHash para firmar un mensaje o comprobar una firma.You can use static methods on the CryptographicHash class to sign a message or verify a signature.