Share via


HOW TO:封套多位收件者的訊息

此範例會使用 System.Security.Cryptography.Pkcs 建立 CMS/PKCS #7 封套訊息。此訊息會為多位收件者加密。接著,系統會使用每一位收件者的私密金鑰將訊息解密。範例中使用了 EnvelopedCms 物件,它可以讓訊息為一或多個收件者加密 (或稱*「封套」*)。

範例

本範例使用下列類別:

若要在單一電腦上執行,下列範例的「通訊錄」憑證存放區和「我的」憑證存放區中都必須具有主體名稱為 "Recipient1" 和 "Recipient2" 的公開金鑰憑證。該電腦上也必須存放關聯的私密金鑰。此範例程式碼先扮演訊息傳送者,然後扮演訊息收件者。兩個角色都使用相同的公開金鑰認證。因此這個範例要求兩個存放區中都必須具有公開金鑰憑證。做為傳送者時,此範例會在「通訊錄」憑證存放區中搜尋收件者的憑證,並使用該憑證來加密訊息。做為收件者時,它會在「我的」憑證存放區中搜尋憑證,並使用關聯的私密金鑰將訊息解密。

Note注意:

此範例僅用於示範。實際執行環境中可能使用不同的模型,其中訊息的傳送者和收件者會使用其唯一公開金鑰認證,在不同的處理序中執行。

使用 Makecert.exe 公用程式設定此範例,這是完成此工作的方法之一。Certificate Creation Tool (Makecert.exe) 是測試憑證的方便公用程式。在實際執行環境中,憑證是由憑證授權單位所產生。

下面的 Makecert 命令會產生必要的公開金鑰憑證和私密金鑰。

Makecert -n "CN=Recipient1" -ss My

Makecert -n "CN=Recipient2" -ss My

這些命令會將適當的公開金鑰憑證置於「我的」憑證存放區內。此時,您必須匯出公開金鑰憑證,然後再依照HOW TO:匯出和匯入公開金鑰憑證中的程序,為每一位收件者將其匯入「通訊錄」憑證存放區。

// 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 EnvelopAMessageForMultipleRecipients
{
    class EnvelopedCmsMultipleRecipients
    {
        const String recipientName1 = "Recipient1";
        const String recipientName2 = "Recipient2";

        static void Main(string[] args)
        {
            Console.WriteLine("System.Security.Cryptography.Pkcs " +
                "Sample: Multiple-recipient " +
                "encrypted and decrypted message");

            //  Original message.
            const String msg = "To all department heads: The following " +
                "organizational changes will be announced next week:";

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

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

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

            //  The recipients' certificates are necessary to encrypt
            //  the message for those recipients.
            X509Certificate2Collection recipientCerts = GetRecipientCerts();

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

            byte[] encodedEnvelopedCms = EncryptMsg(msgBytes,
                recipientCerts);

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

            //  Decrypts the message for one of the recipients. 
            //  Return the decrypted message to display it.
            Byte[] decryptedMsg = DecryptMsg(encodedEnvelopedCms);

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

        //  Open the AddressBook (called Other in Internet Explorer) 
        //  certificate store and search for recipient
        //  certificates with which to encrypt the message. It must
        //  include two certificates: one with the subject name  
        //  "Recipient1", and one with the subject name "Recipient2".
        static public X509Certificate2Collection GetRecipientCerts()
        {
            //  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 certificates.
            //  For purposes of this sample, do not validate the
            //  certificates. Note that in a production environment,
            //  validating the certificates will probably be necessary.

            //  Get first recipient certificate.
            X509Certificate2Collection certColl = storeAddressBook.
                Certificates.Find(X509FindType.FindBySubjectName,
                recipientName1, false);
            Console.WriteLine(
                "Found {0} certificates in the {1} store with name {2}",
                certColl.Count, storeAddressBook.Name, recipientName1);
            X509Certificate2Collection recipientCerts =
                new X509Certificate2Collection();

            //  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.");
            }

            recipientCerts.Add(certColl[0]);

            //  Get second recipient certificate.
            certColl = storeAddressBook.
                Certificates.Find(X509FindType.FindBySubjectName,
                recipientName2, false);
            Console.WriteLine(
                "Found {0} certificates in the {1} store with name {2}",
                certColl.Count, storeAddressBook.Name, recipientName2);

            //  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.");
            }

            recipientCerts.Add(certColl[0]);

            storeAddressBook.Close();

            return recipientCerts;
        }

        //  Encrypt the message for each recipient by using the public
        //  key of that recipient. This is done by 
        //  enveloping the message by using an EnvelopedCms object.
        static public byte[] EncryptMsg(
            Byte[] msg,
            X509Certificate2Collection recipientCerts)
        {
            //  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 CmsRecipientCollection object that
            //  represents information about the set of recipients 
            //  to encrypt the message for.
            CmsRecipientCollection recips =
                new CmsRecipientCollection(
                SubjectIdentifierType.IssuerAndSerialNumber,
                recipientCerts);

            Console.WriteLine("\nEncrypting data for multiple " +
                "recipients with subject names: ");
            foreach (CmsRecipient recip in recips)
            {
                Console.WriteLine("\t" +
                    recip.Certificate.SubjectName.Name);
            }

            //  Encrypt the message for the collection of recipients.
            envelopedCms.Encrypt(recips);
            Console.WriteLine("Done.");

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

        //  Decrypt the encoded EnvelopedCms message for one of the
        //  recipients.
        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 2 for this example.
            DisplayEnvelopedCms(envelopedCms, false);

            //  Decrypt the message.
            //  The message is decrypted for the recipient that
            //  you find the first matching private key for.
            //  A line similar to the following, however, 
            //  decrypts the message for a specified recipient. In
            //  in this case, the first recipient.
            //  envelopedCms.Decrypt(envelopedCms.RecipientInfos[0]);
            Console.Write("Decrypting Data for one recipient ... ");
            envelopedCms.Decrypt();
            Console.WriteLine("Done.");

            //  The decrypted message occupies the ContentInfo property
            //  after the Decrypt method is invoked.
            return envelopedCms.ContentInfo.Content;
        }

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

請參閱

工作

HOW TO:由一位簽署者簽署訊息
HOW TO:由多位簽署者簽署一個訊息
HOW TO:副署訊息
HOW TO:封套單一收件者的訊息

概念

HOW TO:簽署和封套訊息

Footer image

Copyright © 2007 by Microsoft Corporation. All rights reserved.