MACy, hashe a podpisy

Tento článek popisuje, jak se dají v aplikacích WinUI používat ověřovací kódy zpráv (MAC), hodnoty hash a podpisy k detekci manipulace se zprávami.

Kódy ověřování zpráv (MAC)

Šifrování pomáhá zabránit neoprávněnému jednotlivci ve čtení zprávy, ale nezabrání tomu, aby s zprávou manipulovat. Změněná zpráva, i když změna vede k ničemu jinému než nesmyslu, může mít skutečné náklady. Ověřovací kód zprávy (MAC) pomáhá zabránit manipulaci se zprávami. Představte si například následující scénář:

  • Bob a Alice sdílejí tajný klíč a souhlasí s funkcí MAC, která se má použít.
  • Bob vytvoří zprávu a zadá zprávu a tajný klíč do funkce MAC, která načte hodnotu MAC.
  • Bob odešle [nešifrovanou] zprávu a hodnotu MAC Alice přes síť.
  • Alice používá tajný klíč a zprávu jako vstup do funkce MAC. Porovná vygenerovanou hodnotu MAC s hodnotou MAC poslanou Bobem. Pokud jsou stejné, zpráva se při přenosu nezměnila.

Všimněte si, že Eve, třetí strana odposlouchávající konverzaci mezi Bobem a Alicí, není schopna efektivně manipulovat se zprávou. Eve nemá přístup k privátnímu klíči a proto nemůže vytvořit hodnotu MAC, která by zfalšovaná zpráva vypadala jako legitimní pro Alice.

Vytvoření ověřovacího kódu zprávy zajišťuje pouze to, že původní zpráva nebyla změněna a pomocí sdíleného tajného klíče byla hodnota hash zprávy podepsána někým, kdo má k soukromého klíči přístup.

K vytvoření výčtu dostupných algoritmů MAC a vygenerování symetrického klíče můžete použít MacAlgorithmProvider . Statické metody ve třídě CryptographicEngine můžete použít k provedení potřebného šifrování, které vytvoří hodnotu MAC.

Digitální podpisy jsou ekvivalentem kódů pro autentizaci zpráv s veřejným klíčem, zatímco MAC používají privátní klíč. Přestože MACy používají soukromé klíče k tomu, aby příjemce zprávy mohl ověřit, že zpráva nebyla během přenosu změněna, podpisy používají dvojici soukromého a veřejného klíče.

Tento ukázkový kód ukazuje, jak pomocí Třídy MacAlgorithmProvider vytvořit ověřovací kód hashované zprávy (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.");
            }
        }
    }
}

Hashes

Kryptografická funkce hash přebírá libovolný dlouhý blok dat a vrací bitový řetězec s pevnou velikostí. Funkce hash se obvykle používají při podepisování dat. Vzhledem k tomu, že většina operací podpisu veřejného klíče je výpočetně náročná, je obvykle efektivnější podepsat (šifrovat) hodnotu hash zprávy, než je podepsat původní zprávu. Následující postup představuje společný, i když zjednodušený scénář:

  • Alice má pár veřejného a privátního klíče a chce poslat podepsanou zprávu Bobovi.
  • Alice vytvoří zprávu a vypočítá hodnotu hash zprávy pomocí funkce hash.
  • Alice podepíše hodnotu hash pomocí svého privátního klíče a odešle [nešifrovanou] zprávu a podpis Bobovi přes síť.
  • Bob vypočítá hodnotu hash přijaté zprávy pomocí stejné hashovací funkce. Pak použije veřejný klíč Alice k dešifrování podpisu a porovná ho s vypočítanou hodnotou hash. Pokud jsou stejné, zpráva se při přenosu nezměnila a pochází z Alice.

Všimněte si, že Alice odeslala nešifrovanou zprávu. Zašifrovala se pouze hodnota hash. Tento postup zajišťuje pouze to, že původní zpráva nebyla změněna a pomocí veřejného klíče Alice byla hodnota hash zprávy podepsána někým, kdo má přístup k privátnímu klíči Alice, pravděpodobně Alice.

HashAlgorithmProvider třídy můžete použít k vytvoření výčtu dostupných hash algoritmů a vytvoření hodnoty CryptographicHash.

Digitální podpisy jsou obdobou kódů pro ověřování zpráv (MAC), které využívají veřejný klíč místo privátního klíče. Zatímco MACy používají privátní klíče, které příjemci umožní ověřit, že zpráva nebyla během přenosu změněna, podpisy používají dvojici soukromého a veřejného klíče.

KryptografickýHash objekt lze použít k opakovanému hashování různých dat, aniž by bylo nutné znovu vytvořit objekt pro každé použití. Metoda Append přidá nová data do vyrovnávací paměti, která má být hashována. GetValueAndReset metoda hashuje data a resetuje objekt pro jiné použití. To je znázorněno v následujícím příkladu.

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

Digitální podpisy

Digitální podpisy jsou ekvivalentem veřejného klíče ověřovacích kódů zpráv privátního klíče (MAC). Zatímco MACy používají soukromé klíče k tomu, aby příjemce zprávy mohl ověřit, že zpráva nebyla během přenosu změněna, podpisy používají pár soukromého a veřejného klíče.

Vzhledem k tomu, že většina operací podpisu veřejného klíče je výpočetně náročná, je ale obvykle efektivnější podepsat (zašifrovat) hodnotu hash zprávy, než podepsat původní zprávu. Odesílatel vytvoří hodnotu hash zprávy, podepíše ji a odešle podpis i zprávu (nešifrovanou). Příjemce vypočítá hodnotu hash zprávy, dešifruje podpis a porovná dešifrovaný podpis s hodnotou hash. Pokud se shodují, příjemce si může být jistý, že zpráva ve skutečnosti pochází od odesílatele a během přenosu nebyla změněna.

Podepisování zajišťuje pouze to, že původní zpráva nebyla změněna, a pomocí veřejného klíče odesílatele, že hodnota hash zprávy byla podepsána někým, kdo má přístup k privátnímu klíči.

Pomocí objektu AsymmetricKeyAlgorithmProvider můžete vytvořit výčet dostupných algoritmů podpisu a vygenerovat nebo importovat pár klíčů. Statické metody ve třídě CryptographicHash můžete použít k podepsání zprávy nebo ověření podpisu.