2

我必须与一些商业伙伴交换加密和签名的电子邮件。需要特定的算法,例如:

  • 对于签名,RSASSA-PSS 作为签名算法,
  • 用于加密,RSAES-OAEP 用于密钥加密,AES-128 CBC 用于内容加密

我在使用 Mailkit 进行设置时遇到了麻烦,实际上在它背后是 MailKit 和 BouncyCastle。这是我到目前为止的位置:

用于解密和签名验证

解密正文是可以的,我在 Windows 商店中设置我的私钥后,使用 WindowsSecureMimeContext 进行解密

验证签名不行

case MultipartSigned signedBody:
    try
    {
        using (var ctx = new WindowsSecureMimeContext(StoreLocation.LocalMachine))
        {
            var verifiedData = signedBody.Verify(ctx);
            return verifiedData.All(o => o.Verify());
        }
    }
    catch (Exception e)
    {
        throw new Exception("Error during signature verification.", e);
    }

发件人的证书由通用 CA 签名,因此我再次使用 WindowsSecureMimeContext,但 verifyData.All(o => o.Verify()) 抛出 DigitalSignatureVerifyException(“无法验证数字签名:未知错误”-1073700864 “。”)

用于签名和加密

嗯,这看起来很难...

对于签名,似乎我需要一个 BouncyCastle 的 PssSigner,我可以通过覆盖 DkimSigner 来获得它,尤其是 DigestSigner 属性

class TestSigner : DkimSigner
{
    protected TestSigner(string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) 
        : base(domain, selector, algorithm)
    {
    }

    public TestSigner(AsymmetricKeyParameter key, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) 
        : base(key, domain, selector, algorithm)
    {
    }

    public TestSigner(string fileName, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256)
        : base(fileName, domain, selector, algorithm)
    {
    }

    public TestSigner(Stream stream, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256)
        : base(stream, domain, selector, algorithm)
    {
    }

    public override ISigner DigestSigner => SignerUtilities.GetSigner(PkcsObjectIdentifiers.IdRsassaPss);
}

但是我不知道在哪里使用它。也许在使用 MimeMessage.Sign() 时,但是我对方法签名中所需的参数有点迷失了

对于加密,我可以在 BouncyCastle 的库中找到 RsaesOaepParameters,但我不知道如何使用它。

邮件专家的任何帮助将不胜感激!

4

1 回答 1

1

ADkimSigner用于生成 DKIM 签名,这不是您想要做的。DKIM 签名与 S/MIME无关。

使用 RSASSA-PSS 进行 S/MIME 签名

目前,WindowsSecureMimeContextSystem.Security用作后端)不支持 RSASSA-PSS,因此您需要使用 Bouncy Castle 后端。

要使用 Bouncy Castle 后端,您需要使用BouncyCastleSecureMimeContext派生类之一(或创建您自己的派生类)。作为玩弄事物的临时解决方案,我可能会建议使用TemporarySecureMimeContext,但对于长期使用,我建议查看DefaultSecureMimeContext - 尽管您可能仍然希望对其进行子类化以使其正常工作。

现在您正在使用 Bouncy Castle S/MIME 上下文,为了指定您想要使用 RSASSA-PSS 填充,您需要使用带有CmsSigner参数的 API,例如MultipartSigned.Create()ApplicationPkcs7Mime。标志()

这是一个示例代码片段:

var signer = new CmsSigner ("certificate.pfx", "password");

// Specify that we want to use RSASSA-PSS
signer.RsaSignaturePaddingScheme = RsaSignaturePaddingScheme.Pss;

// Sign the message body
var signed = MultipartSigned.Create (ctx, signer, message.Body);

// replace the message body with the signed body
message.Body = signed;

使用 AES-128 CBC(或任何其他特定算法)和 RSAES-OAEP 的 S/MIME 加密

首先,要使用 S/MIME 进行加密,您需要使用ApplicationPkcs7Mime.Encrypt()方法之一。 [2]

采用 a 的 Encrypt() 方法MailboxAddress将通过根据提供的电子邮件地址进行证书查找来自动为您创建CmsRecipientCmsRecipientCollection(或者,如果这些邮箱中的任何一个实际上是SecureMailboxAddress,则使用指纹,这很有用如果该用户在您的数据库中拥有超过 1 个证书,或者您想更加确定 MimeKit 选择了正确的证书)。

当您向 MimeKit 提供 es 列表时,MimeKit 将为您做的另一件事MailboxAddress是,它将查找存储在数据库中为所述用户提供的支持的加密算法。

对于WindowsSecureMimeContext,这涉及查看 S/MIME Capabilities X509 证书扩展属性和解码支持的加密算法。然而,根据我的经验,Windows 证书存储中的 X509 证书上很多时候不存在此扩展,因此 MimeKit 必须假设仅支持 3DES CBC。

对于DefaultSecureMimeContext,如果您已经验证了该收件人的任何 S/MIME 签名消息,那么该用户的证书(链)和宣传的加密算法将存储在 MimeKit 的自定义 SQL 数据库中(当您使用 S/MIME 签名消息时,这是相当常见的客户端在 S/MIME 签名数据中包含 S/MIME Capabilities 属性的做法)。

现在您了解了它是如何工作的,如果您想强制使用 AES-128 CBC,那么执行此操作的方法是自己手动构建CmsRecipientCollection

当然,这涉及CmsRecipient为每个收件人创建一个新的。要创建此类,您真正需要的是该收件人的 X509 证书。

var recipient = new CmsRecipient (certificate);

既然你想强制使用 AES-128 CBC,现在你只需要覆盖这个接收者支持的加密算法:

recipient.EncryptionAlgorithms = new EncryptionAlgorithm[] {
    EncryptionAlgorithm.Aes128
};

(默认情况下,EncryptionAlgorithms属性将设置为证书的 S/MIME 功能扩展属性(按优先顺序)中列出的算法,如果存在,否则它将只包含 3DES CBC)。

如果您还想强制 RSAES-OAEP,您需要设置:

recipient.RsaEncryptionPadding = RsaEncryptionPadding.OaepSha1;

将每个添加CmsRecipient到您的CmsRecipientCollection,然后将其传递给您的首选Encrypt()方法,然后哇,它将使用 AES-128 CBC 进行加密。

笔记:

  1. MultipartSigned.Create()将生成一个multipart/signedMIME 部分,同时ApplicationPkcs7Mime.Sign()将创建一个application/pkcs7-mimeMIME 部分。无论您想使用哪一种都由您决定,请记住,您的选择可能会影响与您的收件人正在使用的任何客户端的兼容性(我认为大多数客户端都支持这两种形式,但您可能需要检查以确保)。
  2. 如果您已经SecureMimeContext使用 MimeKit 注册了您的自定义类(如 README 中的简要描述),那么您可以随意使用各种不采用加密上下文参数的 Encrypt/Decrypt/Sign/Verify/etc 方法,因为 MimeKit 将实例化您的默认上下文。否则,您将需要向他们传递上下文。
于 2017-12-23T03:04:17.820 回答