将 RSASSA-PSS 和 RSAES-OAEP 与 MailKit 结合使用
Using RSASSA-PSS and RSAES-OAEP with MailKit
我必须与一些业务合作伙伴交换加密和签名的电子邮件。需要具体的算法,比如:
- 签名,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 ("Failed to verify digital signature: Unknown error "-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,但我不知道如何使用它。
非常感谢邮件专家的任何帮助!
A DkimSigner
用于生成 DKIM 签名,这不是您想做的。 DKIM 签名与 S/MIME.
没有任何关系
S/MIME 使用 RSASSA-PSS 签名
目前,WindowsSecureMimeContext(使用 System.Security
作为后端)不支持 RSASSA-PSS,因此您需要使用 Bouncy Castle 后端。
要使用 Bouncy Castle 后端,您将需要使用 BouncyCastleSecureMimeContext derivatives (or create your own). As a temporary solution for playing around with things, I might suggest using the TemporarySecureMimeContext, but for long-term use, I would suggest looking at the DefaultSecureMimeContext 之一 - 尽管您可能仍需要子class 以使其正常工作。
现在您正在使用 Bouncy Castle S/MIME 上下文,为了指定您想要使用 RSASSA-PSS 填充,您需要使用采用 CmsSigner parameter such as MultipartSigned.Create() or ApplicationPkcs7Mime.Sign() 的 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;
S/MIME 使用 AES-128 CBC(或任何其他特定算法)和 RSAES-OAEP 进行加密
首先,要使用 S/MIME 进行加密,您需要使用 ApplicationPkcs7Mime.Encrypt() 方法之一。[2]
采用 MailboxAddress
的 Encrypt() 方法将自动创建 CmsRecipients and CmsRecipientCollection for you by doing certificate lookups based on the email address provided (or, if any of those mailboxes are actually a SecureMailboxAddress, the Fingerprint 代替,如果该用户在您的数据库中有超过 1 个证书或者您想成为特别确保 MimeKit 会选择正确的那个)。
当您向它提供 MailboxAddress
es 列表时,MimeKit 会为您做的另一件事是,它会为该用户查找存储在数据库中的受支持的加密算法。
对于 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
。要创建此 class,您真正需要的只是该收件人的 X509 证书。
var recipient = new CmsRecipient (certificate);
由于您想强制使用 AES-128 CBC,现在您只需覆盖此收件人支持的加密算法即可:
recipient.EncryptionAlgorithms = new EncryptionAlgorithm[] {
EncryptionAlgorithm.Aes128
};
(默认情况下,EncryptionAlgorithms 属性 将设置为证书的 S/MIME Capabilities Extension 属性(按优先顺序)中列出的算法,如果存在,否则它'将仅包含 3DES CBC)。
如果您还想强制执行 RSAES-OAEP,则需要设置:
recipient.RsaEncryptionPadding = RsaEncryptionPadding.OaepSha1;
将每个 CmsRecipient
添加到您的 CmsRecipientCollection
,然后将其传递给您首选的 Encrypt()
方法,哇哦,它将使用 AES-128 CBC 进行加密。
备注:
MultipartSigned.Create()
将生成 multipart/signed
MIME 部分,而 ApplicationPkcs7Mime.Sign()
将创建 application/pkcs7-mime
MIME 部分。无论您想使用哪种形式都由您决定,请记住,您的选择可能会影响与您的收件人使用的任何客户端的兼容性(我认为大多数客户端都支持这两种形式,但您可能需要检查以确保)。
- 如果您已经使用 MimeKit 注册了您的自定义
SecureMimeContext
class(如 README 中的简要描述),那么您可以随意使用各种 Encrypt/Decrypt/Sign/Verify/etc 方法不要采用加密上下文参数,因为 MimeKit 将为您实例化默认上下文。否则,您将需要向他们传递上下文。
我必须与一些业务合作伙伴交换加密和签名的电子邮件。需要具体的算法,比如:
- 签名,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 ("Failed to verify digital signature: Unknown error "-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,但我不知道如何使用它。
非常感谢邮件专家的任何帮助!
A DkimSigner
用于生成 DKIM 签名,这不是您想做的。 DKIM 签名与 S/MIME.
S/MIME 使用 RSASSA-PSS 签名
目前,WindowsSecureMimeContext(使用 System.Security
作为后端)不支持 RSASSA-PSS,因此您需要使用 Bouncy Castle 后端。
要使用 Bouncy Castle 后端,您将需要使用 BouncyCastleSecureMimeContext derivatives (or create your own). As a temporary solution for playing around with things, I might suggest using the TemporarySecureMimeContext, but for long-term use, I would suggest looking at the DefaultSecureMimeContext 之一 - 尽管您可能仍需要子class 以使其正常工作。
现在您正在使用 Bouncy Castle S/MIME 上下文,为了指定您想要使用 RSASSA-PSS 填充,您需要使用采用 CmsSigner parameter such as MultipartSigned.Create() or ApplicationPkcs7Mime.Sign() 的 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;
S/MIME 使用 AES-128 CBC(或任何其他特定算法)和 RSAES-OAEP 进行加密
首先,要使用 S/MIME 进行加密,您需要使用 ApplicationPkcs7Mime.Encrypt() 方法之一。[2]
采用 MailboxAddress
的 Encrypt() 方法将自动创建 CmsRecipients and CmsRecipientCollection for you by doing certificate lookups based on the email address provided (or, if any of those mailboxes are actually a SecureMailboxAddress, the Fingerprint 代替,如果该用户在您的数据库中有超过 1 个证书或者您想成为特别确保 MimeKit 会选择正确的那个)。
当您向它提供 MailboxAddress
es 列表时,MimeKit 会为您做的另一件事是,它会为该用户查找存储在数据库中的受支持的加密算法。
对于 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
。要创建此 class,您真正需要的只是该收件人的 X509 证书。
var recipient = new CmsRecipient (certificate);
由于您想强制使用 AES-128 CBC,现在您只需覆盖此收件人支持的加密算法即可:
recipient.EncryptionAlgorithms = new EncryptionAlgorithm[] {
EncryptionAlgorithm.Aes128
};
(默认情况下,EncryptionAlgorithms 属性 将设置为证书的 S/MIME Capabilities Extension 属性(按优先顺序)中列出的算法,如果存在,否则它'将仅包含 3DES CBC)。
如果您还想强制执行 RSAES-OAEP,则需要设置:
recipient.RsaEncryptionPadding = RsaEncryptionPadding.OaepSha1;
将每个 CmsRecipient
添加到您的 CmsRecipientCollection
,然后将其传递给您首选的 Encrypt()
方法,哇哦,它将使用 AES-128 CBC 进行加密。
备注:
MultipartSigned.Create()
将生成multipart/signed
MIME 部分,而ApplicationPkcs7Mime.Sign()
将创建application/pkcs7-mime
MIME 部分。无论您想使用哪种形式都由您决定,请记住,您的选择可能会影响与您的收件人使用的任何客户端的兼容性(我认为大多数客户端都支持这两种形式,但您可能需要检查以确保)。- 如果您已经使用 MimeKit 注册了您的自定义
SecureMimeContext
class(如 README 中的简要描述),那么您可以随意使用各种 Encrypt/Decrypt/Sign/Verify/etc 方法不要采用加密上下文参数,因为 MimeKit 将为您实例化默认上下文。否则,您将需要向他们传递上下文。