Freigeben über


Verfahrensweise: Signieren und Versehen einer Nachricht mit einem Umschlag

In diesem Beispiel wird eine CMS/PKCS #7-signierte und mit Umschlag versehene Nachricht unter Verwendung von System.Security.Cryptography.Pkcs erstellt. Zuerst wird die Nachricht von einem einzelnen Signierer signiert und anschließend für einen einzelnen Empfänger verschlüsselt. Die Nachricht wird dann mithilfe des privaten Schlüssels des Empfängers entschlüsselt, und die Signatur wird überprüft. Das Beispiel verwendet das SignedCms-Objekt, das es ermöglicht, eine Nachricht von einem oder mehreren Signieren signieren und gegensignieren zu lassen. Es verwendet außerdem das EnvelopedCms-Objekt, das es ermöglicht, Nachrichten für einen oder mehrere Empfänger zu verschlüsseln oder mit einem Umschlag zu versehen.

Beispiel

Beschreibung

In diesem Beispiel werden die folgenden Klassen verwendet:

Für die Ausführung auf einem einzelnen Computer ist für das Beispiel Folgendes erforderlich:

  • Ein Zertifikat mit öffentlichem Schlüssel mit dem Antragstellernamen "MessageSigner1" muss im Zertifikatspeicher "My" enthalten sein.

  • Ein weiteres Zertifikat mit dem Antragstellernamen "Recipient1" muss in den Zertifikatspeichern "AddressBook" und "My" enthalten sein.

  • Zugeordnete private Schlüssel müssen auf dem einzelnen Computer gespeichert sein.

Der Beispielcode agiert erst als Absender der Nachricht und übernimmt anschließend die Rolle des Nachrichtenempfängers. Das Beispiel verwendet in beiden Rollen dieselben Anmeldeinformationen des öffentlichen Schlüssels. Deshalb ist es für das Beispiel erforderlich, dass das Zertifikat mit öffentlichem Schlüssel für den Antragstellernamen "Recipient1" in zwei Speichern vorhanden ist. Als Absender durchsucht der Code den Zertifikatspeicher "AddressBook" nach dem Zertifikat des Empfängers und verschlüsselt damit die Nachricht. Als Empfänger durchsucht der Code den Zertifikatspeicher "My" nach dem Zertifikat und entschlüsselt mit dem zugeordneten privaten Schlüssel die Nachricht.

NoteHinweis:

Dieses Beispiel dient nur der Veranschaulichung. In Produktionsumgebungen kann ein anderes Modell verwendet werden, in dem Absender und Empfänger der Nachricht in verschiedenen Prozessen mit ihren eindeutigen Anmeldeinformationen des öffentlichen Schlüssels ausgeführt werden.

Richten Sie dieses Beispiel mithilfe des Dienstprogramms Makecert.exe ein; dies ist nur eine von vielen Möglichkeiten. Certificate Creation Tool (Makecert.exe) ist ein komfortables Dienstprogramm zum Testen von Zertifikaten. In einer Produktionsumgebung werden Zertifikate von einer Zertifizierungsstelle generiert.

Mithilfe der folgenden Makecert-Befehle werden die erforderlichen Zertifikate mit öffentlichem Schlüssel und die privaten Schlüssel generiert.

Makecert -n "CN=MessageSigner1" -ss My

Makecert -n "CN=Recipient1" -sky exchange -ss M

Diese Befehle legen die entsprechenden Zertifikate mit öffentlichem Schlüssel im Zertifikatspeicher "My" ab. Um das Zertifikat mit öffentlichem Schlüssel für den Antragstellernamen "Recipient1" im Zertifikatspeicher "AddressBook" abzulegen, exportieren Sie das Zertifikat mit öffentlichem Schlüssel und importieren es in den Speicher "AddressBook", indem Sie das in Verfahrensweise: Exportieren und Importieren eines Zertifikats mit öffentlichem Schlüssel geschilderte Verfahren verwenden.

// Copyright (c) Microsoft Corporation. All rights reserved.

#region Using directives

using System;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.Text;

#endregion

namespace SigningAndEnvelopingMessage
{
    class EnvelopedSignedCms
    {
        const String signerName = "MessageSigner1";
        const String recipientName = "Recipient1";

        static void Main(string[] args)
        {
            byte[] origMsg;

            Console.WriteLine("System.Security.Cryptography.Pkcs " +
                "Sample: Encrypted, signed, decrypted, and " +
                "verified message");
            //  Original message.
            const String msg = "Here are the sales figures for the " +
                "upcoming quarterly report to Wall Street.";

            Console.WriteLine("\nOriginal message (len {0}): {1}  ",
                              msg.Length, msg);

            //  Convert message to array of bytes for signing.
            Encoding unicode = Encoding.Unicode;
            byte[] msgBytes = unicode.GetBytes(msg);

            Console.WriteLine("\n\n------------------------------");
            Console.WriteLine("     SETUP OF CREDENTIALS     ");
            Console.WriteLine("------------------------------\n");

            //  The signer's private key, obtained by association with
            //  their signing certificate, is necessary to sign the 
            //  message.
            X509Certificate2 signerCert = GetSignerCert();

            //  The recipient's certificate is necessary to encrypt
            //  the message for that recipient.
            X509Certificate2 recipientCert = GetRecipientCert();

            Console.WriteLine("\n\n----------------------");
            Console.WriteLine("     SENDER SIDE      ");
            Console.WriteLine("----------------------\n");

            byte[] encodedSignedCms = SignMsg(msgBytes, signerCert);

            //  Encrypt the encoded SignedCms message.
            byte[] encodedEnvelopedCms = EncryptMsg(encodedSignedCms,
                recipientCert);

            Console.Write("\nMessage after encryption (len {0}):  ",
                encodedEnvelopedCms.Length);
            foreach (byte b in encodedEnvelopedCms)
            {
                Console.Write("{0:x}", b);
            }
            Console.WriteLine();


            Console.WriteLine("\n\n------------------------");
            Console.WriteLine("     RECIPIENT SIDE     ");
            Console.WriteLine("------------------------\n");

            encodedSignedCms = DecryptMsg(encodedEnvelopedCms);

            //  Get the original message back after verification so
            //  it can be displayed.
            if (VerifyMsg(encodedSignedCms, out origMsg))
            {
                Console.WriteLine("\nMessage verified");
            }
            else
            {
                Console.WriteLine("\nMessage failed to verify");
            }

            //  Convert Unicode bytes to the original message string.
            Console.WriteLine("\nDecrypted Authenticated Message: {0}",
                unicode.GetString(origMsg));

        }

        //  Open the My (or Personal) certificate store. Search for
        //  credentials with which to sign the message. The certificate
        //  must have the subject name "MessageSigner1".
        static public X509Certificate2 GetSignerCert()
        {
            //  Open the My certificate store.
            X509Store storeMy = new X509Store(StoreName.My,
                StoreLocation.CurrentUser);
            storeMy.Open(OpenFlags.ReadOnly);

            //  Display certificates to help troubleshoot the
            //  example's setup.
            Console.WriteLine("Found certs with the following subject " +
                "names in the {0} store:", storeMy.Name);
            foreach (X509Certificate2 cert in storeMy.Certificates)
            {
                Console.WriteLine("\t{0}", cert.SubjectName.Name);
            }

            //  Find the signer's certificate.
            X509Certificate2Collection certColl =
                storeMy.Certificates.Find(X509FindType.FindBySubjectName,
                signerName, false);
            Console.WriteLine(
                "Found {0} certificates in the {1} store with name {2}",
                certColl.Count, storeMy.Name, signerName);

            //  Check to see if the certificate suggested by the example
            //  requirements is not present.
            if (certColl.Count == 0)
            {
                Console.WriteLine(
                    "A suggested certificate to use for this example " +
                    "is not in the certificate store. Select " +
                    "an alternate certificate to use for " +
                    "signing the message.");
            }

            storeMy.Close();

            return certColl[0];
        }

        //  Open the AddressBook (called Other in Internet Explorer) 
        //  certificate store and search for a recipient
        //  certificate with which to encrypt the message. The certificate
        //  must have the subject name "Recipient1".
        static public X509Certificate2 GetRecipientCert()
        {
            //  Open the AddressBook local user X509 certificate store.
            X509Store storeAddressBook = new X509Store(StoreName.
                AddressBook, StoreLocation.CurrentUser);
            storeAddressBook.Open(OpenFlags.ReadOnly);

            //  Display certificates to help troubleshoot the 
            //  example's setup.
            Console.WriteLine(
                "Found certs with the following subject names in the " +
                "{0} store:",
                storeAddressBook.Name);
            foreach (X509Certificate2 cert in storeAddressBook.Certificates)
            {
                Console.WriteLine("\t{0}", cert.SubjectName.Name);
            }

            //  Get recipient certificate.
            //  For purposes of this sample, do not validate the
            //  certificate. Note that in a production environment,
            //  validating the certificate will probably be necessary.
            X509Certificate2Collection certColl = storeAddressBook.
                Certificates.Find(X509FindType.FindBySubjectName,
                recipientName, false);
            Console.WriteLine(
                "Found {0} certificates in the {1} store with name {2}",
                certColl.Count, storeAddressBook.Name, recipientName);

            //  Check to see if the certificate suggested by the example
            //  requirements is not present.
            if (certColl.Count == 0)
            {
                Console.WriteLine(
                    "A suggested certificate to use for this example " +
                    "is not in the certificate store. Select " +
                    "an alternate certificate to use for " +
                    "signing the message.");
            }

            storeAddressBook.Close();

            return certColl[0];
        }

        //  Sign the message by the using the private key of the signer.
        //  Note that signer's public key certificate is input here 
        //  because it is used to locate the corresponding private key.
        static public byte[] SignMsg(
            Byte[] msg,
            X509Certificate2 signerCert)
        {
            //  Place message in a ContentInfo object.
            //  This is required to build a SignedCms object.
            ContentInfo contentInfo = new ContentInfo(msg);

            //  Instantiate SignedCms object with the ContentInfo above.
            //  Has default SubjectIdentifierType IssuerAndSerialNumber.
            //  Has default Detached property value false, so message is
            //  included in the encoded SignedCms.
            SignedCms signedCms = new SignedCms(contentInfo);

            //  Formulate a CmsSigner object, which has all the needed
            //  characteristics of the signer.
            CmsSigner cmsSigner = new CmsSigner(signerCert);

            //  Sign the PKCS #7 message.
            Console.Write("Computing signature with signer subject " +
                "name {0} ... ", signerCert.SubjectName.Name);
            signedCms.ComputeSignature(cmsSigner);
            Console.WriteLine("Done.");

            //  Encode the PKCS #7 message.
            return signedCms.Encode();
        }

        //  Verify the encoded SignedCms message and return a Boolean
        //  value that specifies whether the verification was successful.
        //  Also return the original message that was signed, which is
        //  available as part of the SignedCms message after it
        //  is decoded.
        static public bool VerifyMsg(byte[] encodedSignedCms,
            out byte[] origMsg)
        {
            //  Prepare a SignedCms object in which to decode
            //  and verify.
            SignedCms signedCms = new SignedCms();

            signedCms.Decode(encodedSignedCms);

            //  Catch a verification exception in the event you want to
            //  advise the message recipient that security actions
            //  might be appropriate.
            try
            {
                //  Verify signature. Do not validate signer
                //  certificate for the purposes of this example.
                //  Note that in a production environment, validating
                //  the signer certificate chain will probably be
                //  necessary.
                Console.Write("Checking signature on message ... ");
                signedCms.CheckSignature(true);
                Console.WriteLine("Done.");
            }
            catch (System.Security.Cryptography.CryptographicException e)
            {
                Console.WriteLine("VerifyMsg caught exception:  {0}",
                    e.Message);
                Console.WriteLine("The message may have been modified " +
                    "in transit or storage. Authenticity of the " +
                    "message is not guaranteed.");
                origMsg = null;
                return false;
            }

            origMsg = signedCms.ContentInfo.Content;

            return true;
        }

        //  Encrypt the message with the public key of
        //  the recipient. This is done by enveloping the message by
        //  using a EnvelopedCms object.
        static public byte[] EncryptMsg(Byte[] msg,
            X509Certificate2 recipientCert)
        {
            //  Place message in a ContentInfo object.
            //  This is required to build an EnvelopedCms object.
            ContentInfo contentInfo = new ContentInfo(msg);

            //  Instantiate EnvelopedCms object with the ContentInfo
            //  above.
            //  Has default SubjectIdentifierType IssuerAndSerialNumber.
            //  Has default ContentEncryptionAlgorithm property value
            //  RSA_DES_EDE3_CBC.
            EnvelopedCms envelopedCms = new EnvelopedCms(contentInfo);

            //  Formulate a CmsRecipient object that
            //  represents information about the recipient
            //  to encrypt the message for.
            CmsRecipient recip1 = new CmsRecipient(
                SubjectIdentifierType.IssuerAndSerialNumber,
                recipientCert);

            Console.Write("Encrypting data for a single recipient of " +
                "subject name {0} ... ",
                recip1.Certificate.SubjectName.Name);

            //  Encrypt the message for the recipient.
            envelopedCms.Encrypt(recip1);
            Console.WriteLine("Done.");

            //  The encoded EnvelopedCms message contains the encrypted
            //  message and the information about each recipient that
            //  the message was enveloped for.
            return envelopedCms.Encode();
        }

        //  Decrypt the encoded EnvelopedCms message.
        static public Byte[] DecryptMsg(byte[] encodedEnvelopedCms)
        {
            //  Prepare object in which to decode and decrypt.
            EnvelopedCms envelopedCms = new EnvelopedCms();

            //  Decode the message.
            envelopedCms.Decode(encodedEnvelopedCms);

            //  Display the number of recipients the message is
            //  enveloped for; it should be 1 for this example.
            DisplayEnvelopedCms(envelopedCms, false);

            //  Decrypt the message for the single recipient.
            //  Note that the following call to the Decrypt method
            //  accomplishes the same result:
            //  envelopedCms.Decrypt();
            Console.Write("Decrypting Data ... ");
            envelopedCms.Decrypt(envelopedCms.RecipientInfos[0]);
            Console.WriteLine("Done.");

            return envelopedCms.Encode();
        }

        //  Display the ContentInfo property of a SignedCms object.
        private void DisplaySignedCmsContent(String desc,
            SignedCms signedCms)
        {
            Console.WriteLine(desc + " (length {0}):  ",
                signedCms.ContentInfo.Content.Length);
            foreach (byte b in signedCms.ContentInfo.Content)
            {
                Console.Write(b.ToString() + " ");
            }
            Console.WriteLine();
        }

        //  Display the ContentInfo property of an EnvelopedCms object.
        static private void DisplayEnvelopedCmsContent(String desc,
            EnvelopedCms envelopedCms)
        {
            Console.WriteLine(desc + " (length {0}):  ",
                envelopedCms.ContentInfo.Content.Length);
            foreach (byte b in envelopedCms.ContentInfo.Content)
            {
                Console.Write(b.ToString() + " ");
            }
            Console.WriteLine();
        }

        //  Display some properties of an EnvelopedCms object.
        static private void DisplayEnvelopedCms(EnvelopedCms e,
            Boolean displayContent)
        {
            Console.WriteLine("\nEnveloped PKCS #7 Message Information:");
            Console.WriteLine(
                "\tThe number of recipients for the Enveloped PKCS #7 " +
                "is:  {0}",
                e.RecipientInfos.Count);
            for (int i = 0; i < e.RecipientInfos.Count; i++)
            {
                Console.WriteLine(
                    "\tRecipient #{0} has type {1}.",
                    i + 1,
                    e.RecipientInfos[i].RecipientIdentifier.Type);
            }
            if (displayContent)
            {
                DisplayEnvelopedCmsContent("Enveloped PKCS #7 Content", e);
            }
            Console.WriteLine();
        }
    }
}

Siehe auch

Aufgaben

Verfahrensweise: Signieren von Nachrichten durch einen Signierer
Verfahrensweise: Signieren einer Nachricht durch mehrere Signierer
Verfahrensweise: Gegensignieren einer Nachricht
Verfahrensweise: Versehen einer Nachricht mit einem Umschlag für einen Empfänger
Verfahrensweise: Versehen einer Nachricht mit einem Umschlag für mehrere Empfänger

Footer image

Copyright © 2007 by Microsoft Corporation. Alle Rechte vorbehalten.