C# 将RSASSA-PSS和RSAES-OAEP与MailKit一起使用

C# 将RSASSA-PSS和RSAES-OAEP与MailKit一起使用,c#,cryptography,mimekit,C#,Cryptography,Mimekit,我必须与一些业务合作伙伴交换加密和签名的电子邮件。需要特定的算法,例如: 对于签名,RSASSA-PSS作为签名算法 对于加密,RSAES-OAEP用于密钥加密,AES-128 CBC用于内容加密 我在设置Mailkit时遇到了麻烦,实际上是在Mailkit和BouncyCastle的背后。 到目前为止,我的情况如下: 用于解密和签名验证 在windows应用商店中设置私钥后,可以使用WindowsSecureMimeContext对正文进行解密 验证签名不正确 case Multipart

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

  • 对于签名,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,但使用的是verifiedData。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);
}
但是我不知道在哪里使用它。也许在使用mimessage.Sign()时,我对方法签名中所需的参数有点迷茫

对于加密,我可以在BouncyCastle的库中找到一个rsaesAppParameters,因为我不知道如何使用它


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

A
DkimSigner
用于生成您不想做的DKIM签名。DKIM签名与S/MIME无关

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

当前(使用
System.Security
作为后端)不支持RSASSA-PSS,因此您需要使用Bouncy Castle后端

要使用Bouncy Castle后端,您需要使用其中一个衍生工具(或创建自己的衍生工具)。作为摆弄事物的临时解决方案,我可能建议使用,但对于长期使用,我建议查看-尽管您可能仍然希望将其子类化以使其工作

现在您正在使用Bouncy Castle S/MIME上下文,为了指定要使用RSASSA-PSS填充,您需要使用接受参数(如或)的API

下面是一个示例代码片段:

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进行加密,您需要使用以下方法之一。[2]

采用
MailboxAddress
的Encrypt()方法将根据提供的电子邮件地址进行证书查找,从而自动为您创建s和(或者,如果这些邮箱中的任何一个实际上是,则使用,如果该用户在您的数据库中有多个证书,或者您希望额外确保MimeKit选择了正确的证书,则这将非常有用)

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

对于
WindowsSecureMimeContext
,这涉及查看S/MIME功能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
};
(默认情况下,该属性将设置为证书的s/MIME功能扩展属性中列出的算法(按优先顺序),如果存在,否则它将只包含3DES CBC)

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

recipient.RsaEncryptionPadding = RsaEncryptionPadding.OaepSha1;
将每个
CmsRecipient
添加到您的
CmsRecipient集合
中,然后将其传递到您首选的
Encrypt()
方法,然后使用AES-128 CBC对其进行加密

注:

  • MultipartSigned.Create()
    将在
    ApplicationPkcs7Mime.Sign()时生成一个
    multipart/signed
    MIME部分
    将创建一个
    应用程序/pkcs7 mime
    mime部分。您想使用哪一个取决于您的决定,请记住,您的选择可能会影响与收件人正在使用的任何客户端的兼容性(我认为大多数客户端都支持这两种表单,但您可能需要检查以确保)
  • 如果您已向MimeKit注册了自定义的
    SecureMimeContext
    类(如自述文件中所述),然后您可以随意使用各种加密/解密/签名/验证/etc方法,这些方法不接受加密上下文参数,因为MimeKit将为您实例化默认上下文。否则,您需要向它们传递上下文

  • 您的验证异常看起来可能来自System.Security(您使用的是WindowsSec吗