使用MIMEKIT使用数字证书对纯文本文件进行签名和加密

时间:2018-10-16 10:10:13

标签: c# encryption smime mimekit

对文件签名和加密非常新。在stackoverflow上找到MIMEKIT和代码。对代码的工作原理了解甚少或根本不了解,因此对其进行了更改。在程序包调用p7mViewer中打开创建的文件时,显示消息文件已损坏;签名信息可能会丢失。服务提供商无法解密使用以下代码生成的文件。

我需要使用SHA-256签名并使用DES-3进行加密。请参见下面的代码。

using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Windows.Forms;
using Org.BouncyCastle.Cms;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;
using MimeKit;
using System.Text;

namespace ConsoleApplicationSignWithBouncyCastle
{
class Program
{

    [STAThread]
    static void Main(string[] args)
    {

        try
        {
            // First load a Certificate, filename/path and certificate password
            Cert = ReadCertFromFile("c:/temp1/cert.pfx", "password");

            //  Select a binary file
            var dialog = new OpenFileDialog
            {
                Filter = "All files (*.*)|*.*",
                InitialDirectory = "./",
                Title = "Select a text file"
            };
            var filename = (dialog.ShowDialog() == DialogResult.OK) ? dialog.FileName : null;

            // Get the file
          byte[] fileContent = File.ReadAllBytes( filename);

            // Create the generator
            var dataGenerator = new CmsEnvelopedDataStreamGenerator();

            // Add receiver
            // Cert is the user's X.509 Certificate set bellow
             dataGenerator.AddKeyTransRecipient(Cert);

            // Make the output stream 
            int startFileName = filename.LastIndexOf(@"\") +1;
            string outFile = @"c:\temp1\"+ filename.Substring(startFileName, filename.LastIndexOf(".") - startFileName) + "_w_2.edi";
            var outStream = new FileStream(outFile, FileMode.Create);

            string Streamline = "";
            byte[] StreamBytes = null;
            byte[] newline = Encoding.ASCII.GetBytes(Environment.NewLine);

            Streamline = "MIME-Version: 1.0";
            StreamBytes = Encoding.ASCII.GetBytes(Streamline);
            outStream.Write(StreamBytes , 0,Streamline.Length  );
            outStream.Write(newline, 0, newline.Length );

            Streamline = "Date: " + DateTime.Now.ToString("ddd, dd MMM yyyy HH:mm:ss") + " +0000";
            StreamBytes = Encoding.ASCII.GetBytes(Streamline);
            outStream.Write(StreamBytes, 0, Streamline.Length);
            outStream.Write(newline, 0, newline.Length);

            Streamline = "X-Priority: 3 (Normal)";
            StreamBytes = Encoding.ASCII.GetBytes(Streamline);
            outStream.Write(StreamBytes, 0, Streamline.Length);
            outStream.Write(newline, 0, newline.Length);

            Streamline = "Message-ID: <10000003141>";
            StreamBytes = Encoding.ASCII.GetBytes(Streamline);
            outStream.Write(StreamBytes, 0, Streamline.Length);
            outStream.Write(newline, 0, newline.Length);

            Streamline = "Content-Disposition: attachment; filename="+@"""smime.p7m""";
            StreamBytes = Encoding.ASCII.GetBytes(Streamline);
            outStream.Write(StreamBytes, 0, Streamline.Length);
            outStream.Write(newline, 0, newline.Length);

            Streamline = "Content-Transfer-Encoding: binary";
            StreamBytes = Encoding.ASCII.GetBytes(Streamline);
            outStream.Write(StreamBytes, 0, Streamline.Length);
            outStream.Write(newline, 0, newline.Length);

            Streamline = "AS3-From: PILM";
            StreamBytes = Encoding.ASCII.GetBytes(Streamline);
            outStream.Write(StreamBytes, 0, Streamline.Length);
            outStream.Write(newline, 0, newline.Length);

            Streamline = "AS3-To: SARS";
            StreamBytes = Encoding.ASCII.GetBytes(Streamline);
            outStream.Write(StreamBytes, 0, Streamline.Length);
            outStream.Write(newline, 0, newline.Length);

            Streamline = "Subject: "+ filename.Substring(startFileName, filename.LastIndexOf(".") - startFileName) ;
            StreamBytes = Encoding.ASCII.GetBytes(Streamline);
            outStream.Write(StreamBytes, 0, Streamline.Length);
            outStream.Write(newline, 0, newline.Length);

            Streamline = "Content-Type: application/pkcs7-mime; smime-type="+@"""enveloped - data"""+ ";name="+@"""smime.p7m""";
            StreamBytes = Encoding.ASCII.GetBytes(Streamline);
            outStream.Write(StreamBytes, 0, Streamline.Length);
            outStream.Write(newline, 0, newline.Length);
            outStream.Write(newline, 0, newline.Length);

            // Sign the stream
            var cryptoStream = dataGenerator.Open(outStream, CmsEnvelopedGenerator.DesEde3Cbc  );
            // Store in our binary stream writer and write the signed content
            var binWriter = new BinaryWriter(cryptoStream);
            binWriter.Write(fileContent);



        }
        catch (Exception ex)
        {
            Console.WriteLine("So, you wanna make an exception huh! : " + ex.ToString());
            Console.ReadKey();
        }
    }

    public static Org.BouncyCastle.X509.X509Certificate Cert { get; set; }

    // This reads a certificate from a file.
    // Thanks to: http://blog.softwarecodehelp.com/2009/06/23/CodeForRetrievePublicKeyFromCertificateAndEncryptUsingCertificatePublicKeyForBothJavaC.aspx
    public static Org.BouncyCastle.X509.X509Certificate ReadCertFromFile(string strCertificatePath, string strCertificatePassword)
    {
        try
        {

            X509Certificate2 myCert =  new X509Certificate2(strCertificatePath, strCertificatePassword);
            var cert = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(myCert);

            return cert;
        }
        catch (Exception ex)
        {
            Console.WriteLine("So, you wanna make an exception huh! : " + ex.ToString());
            Console.ReadKey();
            return null;
        }
    }


}

}

1 个答案:

答案 0 :(得分:1)

如果您使用MimeKit而不是尝试手动生成自己的MIME,则可以执行以下操作:

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Windows.Forms;

using MimeKit;
using MimeKit.Cryptography;

namespace ConsoleApplicationSignWithBouncyCastle
{
    class Program
    {
        [STAThread]
        static void Main (string[] args)
        {
            //  Select a binary file
            var dialog = new OpenFileDialog {
                Filter = "All files (*.*)|*.*",
                InitialDirectory = "./",
                Title = "Select a text file"
            };
            var filename = (dialog.ShowDialog () == DialogResult.OK) ? dialog.FileName : null;
            var certificate2 = new X509Certificate2 ("c:/temp1/cert.pfx", "password");
            MimeEntity body;

            using (var content = new MemoryStream (File.ReadAllBytes (filename)))
                var part = new MimePart (MimeTypes.GetMimeType (filename)) {
                    ContentDisposition = new ContentDisposition (ContentDisposition.Attachment),
                    ContentTransferEncoding = ContentEncoding.Binary,
                    FileName = Path.GetFileName (filename),
                    Content = new MimeContent (content)
                };

                var recipient = new CmsRecipient (certificate2) {
                    EncryptionAlgorithms = new EncryptionAlgorithm[] { EncryptionAlgorithm.TripleDes }
                };
                var recipients = new CmsRecipientCollection ();
                recipients.Add (recipient);

                using (var ctx = new TemporarySecureMimeContext ())
                    body = ApplicationPkcs7Mime.Encrypt (ctx, recipients, part);
            }

            var message = new MimeMessage ();
            message.Headers.Add ("AS3-From", "PILM");
            message.Headers.Add ("AS3-To", "SARS");
            message.Subject = Path.GetFileNameWithoutExtension (filename);
            message.Date = DateTimeOffset.Now;
            message.MessageId = "10000003141";
            message.Body = body;

            var outFile = @"c:\temp1\" + Path.GetFileNameWithoutExtension (filename) + "_w_2.edi";
            message.WriteTo (outFile);
        }
    }
}

请注意,以上代码段比原始代码段要简单得多。白天和黑夜是不同的:)

如果您还想使用SHA-256签名,则可以这样做(差异很小):

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Windows.Forms;

using MimeKit;
using MimeKit.Cryptography;

namespace ConsoleApplicationSignWithBouncyCastle
{
    class Program
    {
        [STAThread]
        static void Main (string[] args)
        {
            //  Select a binary file
            var dialog = new OpenFileDialog {
                Filter = "All files (*.*)|*.*",
                InitialDirectory = "./",
                Title = "Select a text file"
            };
            var filename = (dialog.ShowDialog () == DialogResult.OK) ? dialog.FileName : null;
            var certificate2 = new X509Certificate2 ("c:/temp1/cert.pfx", "password");
            MimeEntity body;

            using (var content = new MemoryStream (File.ReadAllBytes (filename)))
                var part = new MimePart (MimeTypes.GetMimeType (filename)) {
                    ContentDisposition = new ContentDisposition (ContentDisposition.Attachment),
                    ContentTransferEncoding = ContentEncoding.Binary,
                    FileName = Path.GetFileName (filename),
                    Content = new MimeContent (content)
                };

                var recipient = new CmsRecipient (certificate2) {
                    EncryptionAlgorithms = new EncryptionAlgorithm[] { EncryptionAlgorithm.TripleDes }
                };
                var recipients = new CmsRecipientCollection ();
                recipients.Add (recipient);

                var signer = new CmsSigner (certificate2) {
                    DigestAlgorithm = DigestAlgorithm.Sha256
                };

                using (var ctx = new TemporarySecureMimeContext ()) {
                    using (var stream = File.OpenRead ("c:/temp1/cert.pfx"))
                        ctx.Import (stream, "password");
                    body = ApplicationPkcs7Mime.SignAndEncrypt (ctx, signer, recipients, part);
                }
            }

            var message = new MimeMessage ();
            message.Headers.Add ("AS3-From", "PILM");
            message.Headers.Add ("AS3-To", "SARS");
            message.Subject = Path.GetFileNameWithoutExtension (filename);
            message.Date = DateTimeOffset.Now;
            message.MessageId = "10000003141";
            message.Body = body;

            var outFile = @"c:\temp1\" + Path.GetFileNameWithoutExtension (filename) + "_w_2.edi";
            message.WriteTo (outFile);
        }
    }
}