简体   繁体   English

C# 如何使用 Bouncy Castle 而不是 x509certificate2 在 Asp.net 5 中使用 S/Mime

[英]C# How to S/Mime in Asp.net 5 with Bouncy Castle instead of x509certificate2

I successfully used the below code to send an S/Mime e-mail on latest Windows Server, but it fails on 2012 Windows Server.我成功地使用以下代码在最新的 Windows 服务器上发送了 S/Mime 电子邮件,但在 2012 Windows 服务器上却失败了。 I think 2012 does not support newer AES encryption.我认为 2012 不支持较新的 AES 加密。

How would I rewrite the following code to replace System.Security.Cryptography.X509Certificates.X509Certificate2() with Bouncy Castle, also using MimeKit and Mailkit?我将如何重写以下代码以将System.Security.Cryptography.X509Certificates.X509Certificate2()替换为 Bouncy Castle,同时还使用 MimeKit 和 Mailkit? I tried using older DES3 for 2012, but it fails with CryptoThrowHelper+WindowsCryptographicException: The specified.network password is not correct.我尝试在 2012 年使用较旧的 DES3,但它因CryptoThrowHelper+WindowsCryptographicException: The specified.network password is not correct. Exactly the same code runs just fine on Windows 10 on my developer machine.完全相同的代码在我的开发人员机器上的 Windows 10 上运行得很好。 Ultimately I want this to run in a Linux container, plus I think Bouncy Castle is much more fun to type and say.最终我希望它在 Linux 容器中运行,而且我认为 Bouncy Castle 打字和说起来更有趣。 :) :)

var message = new MimeMessage(); // Using MimeKit, MailKit 
message.To.Add( new MailboxAddress("John Doe","jdoe@somewhere.com"));
message.From.Add( new MailboxAddress("Jane Doe","jndoe@somewhere.com"));
message.Headers.Add( "AS3-From", "PILM");
message.Headers.Add( "AS3-To", "SARS");
message.Date = DateTimeOffset.Now;
message.MessageId = "42";
message.Subject = "This is a subject";
message.Body = new TextPart("html") { Text = "This is a body" };

using (var context = new TemporarySecureMimeContext())
{   // TODO: Replace Microsoft Cryptography with BouncyCastle
    var cert = new System.Security.Cryptography
        .X509Certificates.X509Certificate2(
        @"c:\security\smime.p12", "VeryCoolPassword",
        System.Security.Cryptography.X509Certificates
            .X509KeyStorageFlags.EphemeralKeySet);

    var recip = new CmsRecipient(cert) {
        EncryptionAlgorithms = new EncryptionAlgorithm[] { 
            EncryptionAlgorithm.TripleDes }
    };
    var recips = new CmsRecipientCollection();
    recips.Add(recip);

    message.Body = ApplicationPkcs7Mime.Encrypt(
        context, recips, message.Body );
};

var client = new SmtpClient();
client.Connect("MySuperEmailServer", 465, true);
client.Authenticate("MySuperUserName", "VeryCoolPassword");
client.Send(message);
client.Disconnect(true);
client.Dispose();

There seems to be several parts to this question.这个问题似乎有几个部分。

First, you want to know how to load a S/MIME certificate using BouncyCastle.首先,您想知道如何使用 BouncyCastle 加载 S/MIME 证书。 Since, as Crypt32 pointed out, you aren't likely to need to load *.pfx (aka *.p12) files since you wouldn't have their private key, you'll likely need to load a *.cer (or *.crt) file:因为,正如 Crypt32 指出的那样,您不太可能需要加载 *.pfx(又名 *.p12)文件,因为您没有他们的私钥,您可能需要加载 *.cer(或 * .crt)文件:

using (var stream = File.OpenRead ("smime-recipient-certificate.cer")) {
    var parser = new X509CertificateParser ();

    var certificate = parser.ReadCertificate (stream);
}

MimeKit's CmsRecipient class will do this for you if you call the CmsRecipient.ctor that takes a fileName argument.如果您调用带有 fileName 参数的 CmsRecipient.ctor,MimeKit 的 CmsRecipient class 将为您执行此操作。

That said, it never hurts to know how to load it manually in case you maybe don't have it stored on disk somewhere (eg maybe a MemoryStream or something).也就是说,如果您可能没有将它存储在磁盘上的某个地方(例如,可能是 MemoryStream 或其他东西),知道如何手动加载它永远不会有坏处。

The CmsRecipient.ctor that takes an X509Certificate2 (that you are currently using) is also fine to use.采用 X509Certificate2(您当前正在使用)的 CmsRecipient.ctor 也可以使用。 MimeKit just converts the X509Certificate2 certificate into a BouncyCastle certificate internally. MimeKit 只是在内部将 X509Certificate2 证书转换为 BouncyCastle 证书。

That said, based on your conversation with Crypt32, it sounds like the issue you were having is with loading an X509Certificate2 from a.pfx file on Windows Server 2012?也就是说,根据您与 Crypt32 的对话,听起来您遇到的问题是从 Windows Server 2012 上的 a.pfx 文件加载 X509Certificate2? In which case, loading the certificate using BouncyCastle is probably the way to go.在这种情况下,使用 BouncyCastle 加载证书可能是通往 go 的途径。

If you need or want to know how to load a.pfx file using BouncyCastle, you can do that using the following logic:如果您需要或想知道如何使用 BouncyCastle 加载 .pfx 文件,您可以使用以下逻辑来实现:

// Note: BouncyCastle's X509Certificate class is named X509Certificate, not to be
// confused with System.Security.Cryptography.X509Certificates.X509Certificate.
X509Certificate LoadPfx (Stream stream, string password, out AsymmetricKeyParameter privateKey)
{
    var pkcs12 = new Pkcs12Store (stream, password.ToCharArray ());

    foreach (string alias in pkcs12.Aliases) {
        if (!pkcs12.IsKeyEntry (alias))
            continue;

        var chain = pkcs12.GetCertificateChain (alias);

        if (chain.Length == 0)
            continue;

        var keyEntry = pkcs12.GetKey (alias);

        if (!keyEntry.Key.IsPrivate)
            continue;

        privateKey = keyEntry.Key;

        return chain[0].Certificate;
    }

    throw Exception ("Did not find a certificate with a private key.");
}

Note: I would probably suggest changing this:注意:我可能会建议更改此设置:

message.MessageId = "42";

to this:对此:

message.MessageId = MimeUtils.GenerateMessageId();

This will generate a random/unique message-id value using the correct syntax (The Message-Id header isn't a number, it's a xyz@abc.com type value).这将使用正确的语法生成随机/唯一的消息 ID 值(消息 ID header 不是数字,它是 xyz@abc.com 类型值)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM