Freigeben über


MACs, Hashes und Signaturen

In diesem Artikel wird erläutert, wie Nachrichtenauthentifizierungscodes (MACs), Hashes und Signaturen in Universelle Windows-Plattform-Apps (UWP) verwendet werden können, um Nachrichtenmanipulation zu erkennen.

Nachrichtenauthentifizierungscodes (MACs)

Die Verschlüsselung verhindert, dass eine nicht autorisierte Person eine Nachricht liest, aber sie verhindert nicht, dass die Person die Nachricht manipuliert. Eine geänderte Nachricht kann auch dann, wenn die Änderung zu nichts als Unsinn führt, echte Kosten haben. Ein Nachrichtenauthentifizierungscode (MAC) verhindert nachrichtenmanipulation. Betrachten Sie beispielsweise das folgende Szenario:

  • Bob und Alice teilen einen geheimen Schlüssel und stimmen einer MAC-Funktion zu, die verwendet werden soll.
  • Bob erstellt eine Nachricht und gibt die Nachricht und den geheimen Schlüssel in eine MAC-Funktion ein, um einen MAC-Wert abzurufen.
  • Bob sendet die Nachricht [unverschlüsselt] und den MAC-Wert an Alice über ein Netzwerk.
  • Alice verwendet den geheimen Schlüssel und die Nachricht als Eingabe für die MAC-Funktion. Sie vergleicht den generierten MAC-Wert mit dem VON Bob gesendeten MAC-Wert. Wenn sie identisch sind, wurde die Nachricht während der Übertragung nicht geändert.

Beachten Sie, dass Eve, ein Dritter, das Gespräch zwischen Bob und Alice abhört, die Nachricht nicht effektiv manipulieren kann. Eve hat keinen Zugriff auf den privaten Schlüssel und kann daher keinen MAC-Wert erstellen, der dazu führt, dass die manipulierte Nachricht für Alice legitim erscheint.

Durch das Erstellen eines Nachrichtenauthentifizierungscodes wird nur sichergestellt, dass die ursprüngliche Nachricht nicht geändert wurde, und mithilfe eines freigegebenen geheimen Schlüssels, dass der Nachrichtenhash von einer Person mit Zugriff auf diesen privaten Schlüssel signiert wurde.

Sie können den MacAlgorithmProvider verwenden, um die verfügbaren MAC-Algorithmen auflisten und einen symmetrischen Schlüssel zu generieren. Sie können statische Methoden für die CryptographicEngine-Klasse verwenden, um die erforderliche Verschlüsselung auszuführen, die den MAC-Wert erstellt.

Digitale Signaturen sind das öffentliche Schlüsseläquivalent von Authentifizierungscodes für private Schlüsselnachrichten (PRIVATE Key Message Authentication Codes, MACs). Obwohl MACs private Schlüssel verwenden, um einem Nachrichtenempfänger zu ermöglichen, zu überprüfen, ob eine Nachricht während der Übertragung nicht geändert wurde, verwenden Signaturen ein privates/öffentliches Schlüsselpaar.

Dieser Beispielcode zeigt, wie Sie mithilfe der MacAlgorithmProvider-Klasse einen Authentifizierungscode mit Hashnachrichten (Hashed Message Authentication Code, HMAC) erstellen.

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

Eine kryptografische Hashfunktion akzeptiert einen willkürlich langen Datenblock und gibt eine Bitzeichenfolge mit fester Größe zurück. Hashfunktionen werden in der Regel beim Signieren von Daten verwendet. Da die meisten Signaturenvorgänge für öffentliche Schlüssel rechenintensiv sind, ist es in der Regel effizienter, einen Nachrichtenhash zu signieren (verschlüsseln), als die ursprüngliche Nachricht zu signieren. Das folgende Verfahren stellt ein gängiges, wenn auch vereinfachtes Szenario dar:

  • Bob und Alice teilen einen geheimen Schlüssel und stimmen einer MAC-Funktion zu, die verwendet werden soll.
  • Bob erstellt eine Nachricht und gibt die Nachricht und den geheimen Schlüssel in eine MAC-Funktion ein, um einen MAC-Wert abzurufen.
  • Bob sendet die Nachricht [unverschlüsselt] und den MAC-Wert an Alice über ein Netzwerk.
  • Alice verwendet den geheimen Schlüssel und die Nachricht als Eingabe für die MAC-Funktion. Sie vergleicht den generierten MAC-Wert mit dem VON Bob gesendeten MAC-Wert. Wenn sie identisch sind, wurde die Nachricht während der Übertragung nicht geändert.

Beachten Sie, dass Alice eine unverschlüsselte Nachricht gesendet hat. Nur der Hash wurde verschlüsselt. Das Verfahren stellt nur sicher, dass die ursprüngliche Nachricht nicht geändert wurde und unter Verwendung des öffentlichen Schlüssels von Alice, dass der Nachrichtenhash von einer Person mit Zugriff auf den privaten Schlüssel von Alice signiert wurde, vermutlich Alice.

Mit der HashAlgorithmProvider-Klasse können Sie die verfügbaren Hashalgorithmen aufzählen und einen CryptographicHash-Wert erstellen.

Digitale Signaturen sind das öffentliche Schlüsseläquivalent von Authentifizierungscodes für private Schlüsselnachrichten (PRIVATE Key Message Authentication Codes, MACs). Während MACs private Schlüssel verwenden, um einem Nachrichtenempfänger zu ermöglichen, zu überprüfen, ob eine Nachricht während der Übertragung nicht geändert wurde, verwenden Signaturen ein privates/öffentliches Schlüsselpaar.

Das CryptographicHash-Objekt kann verwendet werden, um wiederholt unterschiedliche Daten zu hashen, ohne das Objekt für jede Verwendung erneut erstellen zu müssen. Mit der Append-Methode werden einem Puffer neue Daten hinzugefügt, die mit Hash versehen werden sollen. Die GetValueAndReset-Methode hasht die Daten und setzt das Objekt für eine andere Verwendung zurück. Dies wird im folgenden Beispiel gezeigt.

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

Digitale Signaturen

Digitale Signaturen sind das öffentliche Schlüsseläquivalent von Authentifizierungscodes für private Schlüsselnachrichten (PRIVATE Key Message Authentication Codes, MACs). Während MACs private Schlüssel verwenden, um einem Nachrichtenempfänger zu ermöglichen, zu überprüfen, ob eine Nachricht während der Übertragung nicht geändert wurde, verwenden Signaturen ein privates/öffentliches Schlüsselpaar.

Da die meisten Signaturenvorgänge für öffentliche Schlüssel rechenintensiv sind, ist es in der Regel effizienter, einen Nachrichtenhash zu signieren (verschlüsseln), als die ursprüngliche Nachricht zu signieren. Der Absender erstellt einen Nachrichtenhash, signiert ihn und sendet sowohl die Signatur als auch die (unverschlüsselte) Nachricht. Der Empfänger berechnet einen Hash über die Nachricht, entschlüsselt die Signatur und vergleicht die entschlüsselte Signatur mit dem Hashwert. Wenn sie übereinstimmen, kann der Empfänger relativ sicher sein, dass die Nachricht tatsächlich vom Absender stammt und während der Übertragung nicht geändert wurde.

Das Signieren stellt nur sicher, dass die ursprüngliche Nachricht nicht geändert wurde, und mithilfe des öffentlichen Schlüssels des Absenders, dass der Nachrichtenhash von einer Person mit Zugriff auf den privaten Schlüssel signiert wurde.

Sie können ein AsymmetricKeyAlgorithmProvider - Objekt verwenden, um die verfügbaren Signaturalgorithmen auflisten und ein Schlüsselpaar zu generieren oder zu importieren. Sie können statische Methoden für die CryptographicHash-Klasse verwenden, um eine Nachricht zu signieren oder eine Signatur zu überprüfen.