MACs, hashvärden och signaturer

I den här artikeln beskrivs hur koder för meddelandeautentisering (MAC), hashar och signaturer kan användas i UWP-appar (Universal Windows Platform) för att identifiera manipulering av meddelanden.

Autentiseringskoder för meddelanden (MACs)

Kryptering hjälper till att förhindra att en obehörig person läser ett meddelande, men det hindrar inte den personen från att manipulera meddelandet. Ett ändrat budskap, även om ändringen inte resulterar i något annat än nonsens, kan ha verkliga kostnader. En kod för meddelandeautentisering (MAC) hjälper till att förhindra manipulering av meddelanden. Tänk till exempel på följande scenario:

  • Bob och Alice delar en hemlig nyckel och är överens om att en MAC-funktion ska användas.
  • Bob skapar ett meddelande och matar in meddelandet och den hemliga nyckeln i en MAC-funktion för att hämta ett MAC-värde.
  • Bob skickar meddelandet [okrypterat] och MAC-värdet till Alice via ett nätverk.
  • Alice använder den hemliga nyckeln och meddelandet som indata till MAC-funktionen. Hon jämför det genererade MAC-värdet med mac-värdet som skickas av Bob. Om de är desamma ändrades inte meddelandet under överföring.

Observera att Eve, en tredje part som tjuvlyssnar på konversationen mellan Bob och Alice, inte effektivt kan manipulera meddelandet. Eve har inte åtkomst till den privata nyckeln och kan därför inte skapa ett MAC-värde som gör att det manipulerade meddelandet verkar legitimt för Alice.

Om du skapar en kod för meddelandeautentisering ser du bara till att det ursprungliga meddelandet inte har ändrats och genom att använda en delad hemlig nyckel att meddelandehash har signerats av någon med åtkomst till den privata nyckeln.

Du kan använda MacAlgorithmProvider för att räkna upp tillgängliga MAC-algoritmer och generera en symmetrisk nyckel. Du kan använda statiska metoder i klassen CryptographicEngine för att utföra nödvändig kryptering som skapar MAC-värdet.

Digitala signaturer är den offentliga nyckelns motsvarighet till autentiseringskoder för privata nycklar (MACs). Även om macs använder privata nycklar för att göra det möjligt för en meddelandemottagare att verifiera att ett meddelande inte har ändrats under överföringen, använder signaturer ett privat/offentligt nyckelpar.

Den här exempelkoden visar hur du använder klassen MacAlgorithmProvider för att skapa en hashad kod för meddelandeautentisering (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.");
            }
        }
    }
}

Hashvärden

En kryptografisk hashfunktion tar ett godtyckligt långt datablock och returnerar en bitsträng med fast storlek. Hash-funktioner används vanligtvis vid signering av data. Eftersom de flesta offentliga nyckelsignaturåtgärder är beräkningsintensiva är det vanligtvis mer effektivt att signera (kryptera) en meddelandehash än att signera det ursprungliga meddelandet. Följande procedur representerar ett vanligt, om än förenklat, scenario:

  • Alice har ett offentligt/privat nyckelpar och vill skicka ett signerat meddelande till Bob.
  • Alice skapar ett meddelande och beräknar en hash av meddelandet med hjälp av en hash-funktion.
  • Alice signerar hashen med sin privata nyckel och skickar meddelandet [okrypterat] och signaturen till Bob via ett nätverk.
  • Bob beräknar en hash för det mottagna meddelandet med hjälp av samma hash-funktion. Han använder sedan Alice offentliga nyckel för att dekryptera signaturen och jämför den med den beräknade hashen. Om de är desamma ändrades inte meddelandet under överföring och kom från Alice.

Observera att Alice skickade ett okrypterat meddelande. Endast hashen krypterades. Proceduren säkerställer endast att det ursprungliga meddelandet inte har ändrats och, genom att använda Alice offentliga nyckel, att meddelandehash har signerats av någon med åtkomst till Alices privata nyckel, förmodligen Alice.

Du kan använda klassen HashAlgorithmProvider för att räkna upp tillgängliga hash-algoritmer och skapa ett CryptographicHash- värde.

Digitala signaturer är den offentliga nyckelns motsvarighet till autentiseringskoder för privata nycklar (MACs). Medan macs använder privata nycklar för att göra det möjligt för en meddelandemottagare att kontrollera att ett meddelande inte har ändrats under överföringen, använder signaturer ett privat/offentligt nyckelpar.

Det CryptographicHash--objektet kan användas för att upprepade gånger hash olika data utan att behöva återskapa objektet för varje användning. Metoden Lägg till lägger till nya data i en buffert som ska hashas. Metoden GetValueAndReset hashar data och återställer objektet för en annan användning. Detta visas i följande exempel.

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

Digitala signaturer

Digitala signaturer är den offentliga nyckelns motsvarighet till autentiseringskoder för privata nycklar (MACs). Medan macs använder privata nycklar för att göra det möjligt för en meddelandemottagare att kontrollera att ett meddelande inte har ändrats under överföringen, använder signaturer ett privat/offentligt nyckelpar.

Eftersom de flesta offentliga nyckelsignaturåtgärder är beräkningsintensiva är det dock vanligtvis mer effektivt att signera (kryptera) en meddelandehash än att signera det ursprungliga meddelandet. Avsändaren skapar en meddelandehash, signerar den och skickar både signaturen och meddelandet (okrypterat). Mottagaren beräknar en hash över meddelandet, dekrypterar signaturen och jämför den dekrypterade signaturen med hash-värdet. Om de matchar kan mottagaren vara ganska säker på att meddelandet faktiskt kom från avsändaren och inte ändrades under överföringen.

Signering säkerställer endast att det ursprungliga meddelandet inte har ändrats och genom att använda avsändarens offentliga nyckel, att meddelandehash har signerats av någon med åtkomst till den privata nyckeln.

Du kan använda ett AsymmetricKeyAlgorithmProvider-objekt för att räkna upp tillgängliga signaturalgoritmer och generera eller importera ett nyckelpar. Du kan använda statiska metoder i klassen CryptographicHash för att signera ett meddelande eller verifiera en signatur.