EnvelopedCms 如何正确识别要解密的证书而不请求密码?
EnvelopedCms how to properly identify certificate to decrypt and not request a password?
我正在解密电子邮件中的 SMIME.P7M 附件。我目前有以下
EnvelopedCms envDate = new EnvelopedCms(new ContentInfo(data));
envDate.Decode(data);
RecipientInfoCollection recips = envDate.RecipientInfos;
RecipientInfo recipin = recips[0];
X509Certificate2 x509_2 = LoadCertificate2(StoreLocation.CurrentUser, (SubjectIdentifier)recipin.RecipientIdentifier);
加载证书如下所示
public static X509Certificate2 LoadCertificate2(StoreLocation storeLocation, SubjectIdentifier identifier)
{
X509Store store = new X509Store(storeLocation);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = store.Certificates;
X509Certificate2 x509 = null;
X509IssuerSerial issuerSerial;
if (identifier.Type == SubjectIdentifierType.IssuerAndSerialNumber)
{
issuerSerial = (X509IssuerSerial)identifier.Value;
}
foreach (X509Certificate2 c in certCollection)
{
Console.WriteLine("{0}Valid Date: {1}{0}", Environment.NewLine, c.NotBefore);
if (c.SerialNumber == issuerSerial.SerialNumber && c.Issuer == issuerSerial.IssuerName)
{
x509 = c;
break;
}
}
if (x509 == null)
Console.WriteLine("A x509 certificate for was not found");
store.Close();
return x509;
}
以上代码只获取第一个收件人RecipientInfo recipin = recips[0];然而,获取适当证书以遍历每个收件人并检查 SubjectIdentifier 存储的最有效方法是什么?
一旦获得正确的证书,我就使用这个
X509Certificate2Collection col = new X509Certificate2Collection(x509_2);
envDate.Decrypt(col);
decData = envDate.ContentInfo.Content;
这会提示输入与证书私钥关联的 PIN,我如何在调用 decrypt 之前添加 PIN 以便没有提示?
.NET Framework 中的 EnvelopedCms class 没有任何方法可以让您轻松地以编程方式应用 PIN(或其他解锁机制);特别是如果证书存在于 CurrentUser\My 或 LocalMachine\My 存储中(因为这些存储在 extraStore 集合中的任何证书之前被搜索)。
在 .NET Framework 4.7+ 上,如果证书不在 CurrentUser\My 或 LocalMachine\My 存储区中,您可以通过非常迂回的方式为 CNG 可访问密钥完成此操作:
CngKey key = ExerciseLeftToTheReader();
key.SetProperty(new CngProperty("SmartCardPin", pin, CngPropertyOptions.None));
X509Certificate2 cert = DifferentExerciseLeftToTheReader();
// You need to use tmpCert because this won't do good things if the certificate
// already knows about/how-to-find its associated private key
using (key)
using (X509Certificate2 tmpCert = new X509Certificate2(cert.RawData))
{
// Need to NOT read the HasPrivateKey property until after the property set. Debugger beware.
NativeMethods.CertSetCertificateContextProperty(
tmpCert.Handle,
CERT_NCRYPT_KEY_HANDLE_PROP_ID,
CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG,
key.Handle);
envelopedCms.Decrypt(new X509Certificate2Collection(tmpCert));
}
(当然,您需要为 CertSetCertificateContextProperty 定义 P/Invoke)
在 .NET Core 3.0 中,这变得更容易(预览版 2 当前可使用此功能)...尽管它确实让您承担了确定您是哪个 RecipientInfo 以及哪个密钥与之相关的负担:
RecipientInfo recipientInfo = FigureOutWhichOneYouCanMatch();
CngKey key = ExerciseLeftToTheReader();
key.SetProperty(new CngProperty("SmartCardPin", pin, CngPropertyOptions.None));
using (key)
using (RSA rsa = new RSACng(key))
{
envelopedCms.Decrypt(recipientInfo, rsa);
}
我正在解密电子邮件中的 SMIME.P7M 附件。我目前有以下
EnvelopedCms envDate = new EnvelopedCms(new ContentInfo(data));
envDate.Decode(data);
RecipientInfoCollection recips = envDate.RecipientInfos;
RecipientInfo recipin = recips[0];
X509Certificate2 x509_2 = LoadCertificate2(StoreLocation.CurrentUser, (SubjectIdentifier)recipin.RecipientIdentifier);
加载证书如下所示
public static X509Certificate2 LoadCertificate2(StoreLocation storeLocation, SubjectIdentifier identifier)
{
X509Store store = new X509Store(storeLocation);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = store.Certificates;
X509Certificate2 x509 = null;
X509IssuerSerial issuerSerial;
if (identifier.Type == SubjectIdentifierType.IssuerAndSerialNumber)
{
issuerSerial = (X509IssuerSerial)identifier.Value;
}
foreach (X509Certificate2 c in certCollection)
{
Console.WriteLine("{0}Valid Date: {1}{0}", Environment.NewLine, c.NotBefore);
if (c.SerialNumber == issuerSerial.SerialNumber && c.Issuer == issuerSerial.IssuerName)
{
x509 = c;
break;
}
}
if (x509 == null)
Console.WriteLine("A x509 certificate for was not found");
store.Close();
return x509;
}
以上代码只获取第一个收件人RecipientInfo recipin = recips[0];然而,获取适当证书以遍历每个收件人并检查 SubjectIdentifier 存储的最有效方法是什么?
一旦获得正确的证书,我就使用这个
X509Certificate2Collection col = new X509Certificate2Collection(x509_2);
envDate.Decrypt(col);
decData = envDate.ContentInfo.Content;
这会提示输入与证书私钥关联的 PIN,我如何在调用 decrypt 之前添加 PIN 以便没有提示?
.NET Framework 中的 EnvelopedCms class 没有任何方法可以让您轻松地以编程方式应用 PIN(或其他解锁机制);特别是如果证书存在于 CurrentUser\My 或 LocalMachine\My 存储中(因为这些存储在 extraStore 集合中的任何证书之前被搜索)。
在 .NET Framework 4.7+ 上,如果证书不在 CurrentUser\My 或 LocalMachine\My 存储区中,您可以通过非常迂回的方式为 CNG 可访问密钥完成此操作:
CngKey key = ExerciseLeftToTheReader();
key.SetProperty(new CngProperty("SmartCardPin", pin, CngPropertyOptions.None));
X509Certificate2 cert = DifferentExerciseLeftToTheReader();
// You need to use tmpCert because this won't do good things if the certificate
// already knows about/how-to-find its associated private key
using (key)
using (X509Certificate2 tmpCert = new X509Certificate2(cert.RawData))
{
// Need to NOT read the HasPrivateKey property until after the property set. Debugger beware.
NativeMethods.CertSetCertificateContextProperty(
tmpCert.Handle,
CERT_NCRYPT_KEY_HANDLE_PROP_ID,
CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG,
key.Handle);
envelopedCms.Decrypt(new X509Certificate2Collection(tmpCert));
}
(当然,您需要为 CertSetCertificateContextProperty 定义 P/Invoke)
在 .NET Core 3.0 中,这变得更容易(预览版 2 当前可使用此功能)...尽管它确实让您承担了确定您是哪个 RecipientInfo 以及哪个密钥与之相关的负担:
RecipientInfo recipientInfo = FigureOutWhichOneYouCanMatch();
CngKey key = ExerciseLeftToTheReader();
key.SetProperty(new CngProperty("SmartCardPin", pin, CngPropertyOptions.None));
using (key)
using (RSA rsa = new RSACng(key))
{
envelopedCms.Decrypt(recipientInfo, rsa);
}