c# - 使用 mimekit 解密带有附件的电子邮件
问题描述
我们有一个场景来解密带有附件的电子邮件。我们正在使用mimekit
相同的库。我们还mimekit
用于电子邮件加密,它可以正常工作。
在我们的例子中,加密的电子邮件只有一个附件,没有这样的电子邮件正文。有一个 AzureLogic App
从 Oiifce365 邮箱(使用内置连接器)获取加密电子邮件,然后将详细信息发送到Azure Function App
运行解密逻辑的一个。解密证书存储在Azure Key Vault
.
下面是我们尝试过的代码,它显示异常说
无法将“Org.BouncyCastle.Asn1.DerApplicationSpecific”类型的对象转换为“Org.BouncyCastle.Asn1.Asn1SequenceParser”类型。
[FunctionName("DecryptSMIME")]
public static async Task<IActionResult> Decrypt([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log)
{
try
{
var temporarySecurityMimeContext = new TemporarySecureMimeContext();
// get decryption Cert pfx
var keyVaultClient = ServiceProvider.GetRequiredService<IKeyVaultClient>();
var decryptionCertBundle = keyVaultClient.GetSecretAsync("https://my-key-vault.vault.azure.net/secrets/Decryption-Certificate-Base64/d7a84b415a494c1ebaseae88cff50028").Result;
var decryptionCertBytes = Convert.FromBase64String(decryptionCertBundle.Value);
log.LogInformation($"Decoded length of decryption certificate: '{decryptionCertBytes.Length}'");
// get decryption Cert password
var decryptionCertPasswordBundle = keyVaultClient.GetSecretAsync("https://my-key-vault.vault.azure.net/secrets/Decryption-Certificate-Pass/34judc9f575f467a96d9483dfc8kf467").Result;
var decryptionCertPassword = decryptionCertPasswordBundle.Value;
using var stream = new MemoryStream(decryptionCertBytes);
temporarySecurityMimeContext.Import(stream, decryptionCertPassword);
log.LogInformation("Imported The Decryption certificate as MemoryStream");
using var encryptedContentStream = await GetMailAttachmentStreamAsync(req.Body, log) ;
log.LogInformation("Loading pkcs7-mime entity.");
ApplicationPkcs7Mime encryptedContent = (ApplicationPkcs7Mime)await MimeEntity.LoadAsync(ParserOptions.Default, ContentType.Parse(ParserOptions.Default, "application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m"), encryptedContentStream);
log.LogInformation("Decrypting pkcs7-mime entity.");
MimeEntity decryptedContent = encryptedContent.Decrypt();
return new OkObjectResult("OK");
}
catch (Exception ex)
{
log.LogError(ex, "Failed to decrypt the secure mime part in the request body.");
throw;
}
}
private static async Task<MemoryStream> GetMailAttachmentStreamAsync(Stream attachmentObjectStream, ILogger log)
{
var memoryStream = new MemoryStream();
await attachmentObjectStream.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
log.LogInformation($"Attachment Stream Processed. {memoryStream.Length} Bytes");
return memoryStream;
}
证书加载成功。电子邮件流还显示一些数据。但是,在运行解密时,它总是显示错误。任何帮助都会有所帮助。
解决方案
下面是您的代码,并进行了一些修复(即摆脱了MethodAsync(...).Result
不好的做法之类的代码)。
我还冒昧地添加了一条大评论,要求提供更多信息。
[FunctionName("DecryptSMIME")]
public static async Task<IActionResult> Decrypt([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log)
{
try
{
using var temporarySecurityMimeContext = new TemporarySecureMimeContext();
// get decryption Cert pfx
var keyVaultClient = ServiceProvider.GetRequiredService<IKeyVaultClient>();
var decryptionCertBundle = await keyVaultClient.GetSecretAsync("https://my-key-vault.vault.azure.net/secrets/Decryption-Certificate-Base64/d7a84b415a494c1ebaseae88cff50028");
var decryptionCertBytes = Convert.FromBase64String(decryptionCertBundle.Value);
log.LogInformation($"Decoded length of decryption certificate: '{decryptionCertBytes.Length}'");
// get decryption Cert password
var decryptionCertPasswordBundle = await keyVaultClient.GetSecretAsync("https://my-key-vault.vault.azure.net/secrets/Decryption-Certificate-Pass/34judc9f575f467a96d9483dfc8kf467");
var decryptionCertPassword = decryptionCertPasswordBundle.Value;
using var stream = new MemoryStream(decryptionCertBytes);
temporarySecurityMimeContext.Import(stream, decryptionCertPassword);
log.LogInformation("Imported The Decryption certificate as MemoryStream");
using var encryptedContentStream = await GetMailAttachmentStreamAsync(req.Body, log) ;
log.LogInformation("Loading pkcs7-mime entity.");
// Ideally, you would not use the MimeEntity.LoadAsync() method that takes a
// forged ContentType parameter. This is a huge hack and *may* be the cause
// of your problem. In other words, the content that MimeKit is trying to
// decrypt may be in the wrong format. To know for certain, I would need to
// know what the HttpRequest headers and Body look like.
//
// I would probably recommend that your code that sends this request be
// modified to send the entire raw MIME (i.e. including headers) of the
// application/pkcs7-mime part as the HTTP request body instead so that you
// would not need to forge the Content-Type header.
ApplicationPkcs7Mime encryptedContent = (ApplicationPkcs7Mime)await MimeEntity.LoadAsync(ParserOptions.Default, ContentType.Parse(ParserOptions.Default, "application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m"), encryptedContentStream);
log.LogInformation("Decrypting pkcs7-mime entity.");
MimeEntity decryptedContent = encryptedContent.Decrypt();
return new OkObjectResult("OK");
}
catch (Exception ex)
{
log.LogError(ex, "Failed to decrypt the secure mime part in the request body.");
throw;
}
}
private static async Task<MemoryStream> GetMailAttachmentStreamAsync(Stream attachmentObjectStream, ILogger log)
{
var memoryStream = new MemoryStream();
await attachmentObjectStream.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
log.LogInformation($"Attachment Stream Processed. {memoryStream.Length} Bytes");
return memoryStream;
}
推荐阅读
- python-3.x - Python 无法输出 unicode 文字
- react-native - 如何在 DrawerNavigator 中从 API 显示菜单列表
- automation - 使用和不使用 commands.js 或阻塞时的不同结果
- python - 如何从Python中的字典中替换部分变量列名
- java - 如何将一种方法与另一种方法组合使用
- docker - 如何使用 Hyper V 内部开关设置 docker 机器?
- c - “指向函数的指针”语法在 C 中如何工作?
- node.js - 如何在另一条路线内调用一条路线的功能?
- php - ODBC Driver 17 for SQL Server 附近的语法不正确。''
- c# - 通过属性字典中的键访问值