如何解密 PKCS7 消息
How to decrypt a PKCS7 message
我无法用 C# 解密一些 XML 文件。
我对密码学知之甚少,但据我所知,我有一个受密码保护的证书,其中包含私钥和 public 密钥。
通过将密码应用于证书,我获得了解密我收到的文件所需的私钥。
我要解密的邮件位于 PKCS7(CMS?)格式的文件中。我相信我需要解析文件、解密它们,然后取消签名。
我不知道该怎么做。我已经尝试了我发现很明显可以帮助我完成这项任务的工具,但我无法让它工作。
在这一点上,我真的很想知道;有什么我不明白的吗?还是我在工作中使用了错误的工具?
这是我在一堆代码中的一些尝试:
public string DecryptFailingExample()
{
var content = File.ReadAllBytes("encryptedFileWithDataThatIWant.xml.enc");
var cert = new X509Certificate2("certificateFile.pfx", "PasswordForFile");
//This code didn't work. rsa.Decrypt would throw: "The length of the data to decrypt is not valid for the size of this key."
//using RSA rsa = cert.GetRSAPrivateKey();
//var decryptedBytes = rsa.Decrypt(content, RSAEncryptionPadding.OaepSHA1); //I tried all possible paddings - Nothing worked
//So I tried this instead:
SignedCms signedCms = new SignedCms();
signedCms.Decode(content); //Crash: ASN1 corrupted data; The provided data is tagged with 'Universal' class value '13', but it should have been 'Universal' class value '16'.
var ecms = new EnvelopedCms();
//If I try to skip SignedCms and pass "content" directly to EnvelopedCms, I will get: "ASN1 bad tag value met."
ecms.Decode(signedCms.ContentInfo.Content); //Crash:
ecms.Decrypt(new X509Certificate2Collection(cert));
}
这是我要解密的邮件的样子:
-----BEGIN PKCS7-----
MIAGCSqGSIb3DQEHA6BAMIACAQAxggGEMIIBgAIBADBoMFExCzAJBgNVBAYTAkRF
MSQwIgYDVQQKExtFdXJvcGVhbiBFbmVyZ3kgRXhjaGFuZ2UgQUcxHDAaBgNVB4MT
etc
3nPyd3c9iGyKhWdQPPr/SRWB/l9bCjkla81MgTcj1rRGQyPJXpkyxpc9U4YYZnxt
eHkcJMVWDw9ErThok8nh/7bkE4KbWBaLZAac+9occ4deDrlu0wAAAAAAAAAAAAA=
-----END PKCS7-----
编辑:
这是另一个不起作用的最小示例。
//Step 1: Load PKCS7 message from disk
var content = File.ReadAllBytes("encryptedFileWithDataThatIWant.xml.enc");
//Step 2: Load .pfx certificate from disk
var cert = new X509Certificate2("certificateFile.pfx", "Password");
//Step 3: Create instance of EnvelopedCms
var ecms = new EnvelopedCms();
//Step 4: Add certificate for decoding
ecms.Certificates.Add(cert);
//Step 5: Decode the PKCS7 message
ecms.Decode(content); //Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'ASN1 bad tag value met.'
除了 .PFX 文件,我还有一个带有私有证书的 PEM 文件。它看起来像这样:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,915538553FEFBA6A98930E4BFFDA1E68
Pk0FHxXNHukA62FSmuzzE+gqHgeauZr6z+lqTcbf55cakrQzHQOQUnR0w5kCFPPg
etc
L7U2cWJpbNsRNmBcTyH1WWJ4hYoCqdl9G6Zey4y/EQbZl1DKXtmIiLZSneF0VU9u
-----END RSA PRIVATE KEY-----
我试过像这样导入密钥,但这似乎不起作用:
var pem = File.ReadAllBytes("pemFile.pem");
var pemChars = Encoding.UTF8.GetString(pem);
var rsa = RSA.Create();
rsa.ImportFromEncryptedPem(pemChars, "Password"); //System.ArgumentException: 'No supported key formats were found. Check that the input represents the contents of a PEM-encoded key file, not the path to such a file. (Parameter 'input')'
知道了!
感谢@MaartenBodewes 让我走上正轨。
我要解码的文件不是二进制文件,而是文本文件。以文本形式读取文件,然后转换为二进制文件,足以使其正常工作。
工作代码大致如下所示,并且可以针对我的具体情况进一步减少。实际上,它将处理 PKCS7 和 CMS 标签 + 二进制和文本文件。
public string Decrypt()
{
var ecms = Read("encryptedFileWithDataThatIWant.xml.enc");
var cert = new X509Certificate2("certificateFile.pfx", "Password");
ecms.Decrypt(new X509Certificate2Collection{cert});
return Encoding.UTF8.GetString(ecms.ContentInfo.Content);
}
private static EnvelopedCms Read(string fileName)
{
//Try read as binary
var maybeFirstException = TryRead(File.ReadAllBytes(fileName), out var ecms);
if (maybeFirstException is null)
{
return ecms;
}
//Otherwise read as text, convert to binary and try again
var text = File
.ReadAllText(fileName)
.Replace("-----BEGIN PKCS7-----", string.Empty)
.Replace("-----BEGIN CMS-----", string.Empty)
.Replace("-----END PKCS7-----", string.Empty)
.Replace("-----END CMS-----", string.Empty);
var binary = Convert.FromBase64String(text);
var maybeSecondException = TryRead(binary, out ecms);
if (maybeSecondException is null)
{
return ecms;
}
throw new AggregateException("Tried to decode file as both binary and text, but both attempts failed", new List<Exception>
{
maybeFirstException,
maybeSecondException
});
}
private static Exception TryRead(byte[] bytes, out EnvelopedCms ecms)
{
ecms = new EnvelopedCms();
try
{
ecms.Decode(bytes);
return null;
}
catch (CryptographicException e)
{
return e;
}
}
我无法用 C# 解密一些 XML 文件。
我对密码学知之甚少,但据我所知,我有一个受密码保护的证书,其中包含私钥和 public 密钥。
通过将密码应用于证书,我获得了解密我收到的文件所需的私钥。
我要解密的邮件位于 PKCS7(CMS?)格式的文件中。我相信我需要解析文件、解密它们,然后取消签名。
我不知道该怎么做。我已经尝试了我发现很明显可以帮助我完成这项任务的工具,但我无法让它工作。
在这一点上,我真的很想知道;有什么我不明白的吗?还是我在工作中使用了错误的工具?
这是我在一堆代码中的一些尝试:
public string DecryptFailingExample()
{
var content = File.ReadAllBytes("encryptedFileWithDataThatIWant.xml.enc");
var cert = new X509Certificate2("certificateFile.pfx", "PasswordForFile");
//This code didn't work. rsa.Decrypt would throw: "The length of the data to decrypt is not valid for the size of this key."
//using RSA rsa = cert.GetRSAPrivateKey();
//var decryptedBytes = rsa.Decrypt(content, RSAEncryptionPadding.OaepSHA1); //I tried all possible paddings - Nothing worked
//So I tried this instead:
SignedCms signedCms = new SignedCms();
signedCms.Decode(content); //Crash: ASN1 corrupted data; The provided data is tagged with 'Universal' class value '13', but it should have been 'Universal' class value '16'.
var ecms = new EnvelopedCms();
//If I try to skip SignedCms and pass "content" directly to EnvelopedCms, I will get: "ASN1 bad tag value met."
ecms.Decode(signedCms.ContentInfo.Content); //Crash:
ecms.Decrypt(new X509Certificate2Collection(cert));
}
这是我要解密的邮件的样子:
-----BEGIN PKCS7-----
MIAGCSqGSIb3DQEHA6BAMIACAQAxggGEMIIBgAIBADBoMFExCzAJBgNVBAYTAkRF MSQwIgYDVQQKExtFdXJvcGVhbiBFbmVyZ3kgRXhjaGFuZ2UgQUcxHDAaBgNVB4MT
etc
3nPyd3c9iGyKhWdQPPr/SRWB/l9bCjkla81MgTcj1rRGQyPJXpkyxpc9U4YYZnxt eHkcJMVWDw9ErThok8nh/7bkE4KbWBaLZAac+9occ4deDrlu0wAAAAAAAAAAAAA=
-----END PKCS7-----
编辑: 这是另一个不起作用的最小示例。
//Step 1: Load PKCS7 message from disk
var content = File.ReadAllBytes("encryptedFileWithDataThatIWant.xml.enc");
//Step 2: Load .pfx certificate from disk
var cert = new X509Certificate2("certificateFile.pfx", "Password");
//Step 3: Create instance of EnvelopedCms
var ecms = new EnvelopedCms();
//Step 4: Add certificate for decoding
ecms.Certificates.Add(cert);
//Step 5: Decode the PKCS7 message
ecms.Decode(content); //Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'ASN1 bad tag value met.'
除了 .PFX 文件,我还有一个带有私有证书的 PEM 文件。它看起来像这样:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,915538553FEFBA6A98930E4BFFDA1E68
Pk0FHxXNHukA62FSmuzzE+gqHgeauZr6z+lqTcbf55cakrQzHQOQUnR0w5kCFPPg
etc
L7U2cWJpbNsRNmBcTyH1WWJ4hYoCqdl9G6Zey4y/EQbZl1DKXtmIiLZSneF0VU9u
-----END RSA PRIVATE KEY-----
我试过像这样导入密钥,但这似乎不起作用:
var pem = File.ReadAllBytes("pemFile.pem");
var pemChars = Encoding.UTF8.GetString(pem);
var rsa = RSA.Create();
rsa.ImportFromEncryptedPem(pemChars, "Password"); //System.ArgumentException: 'No supported key formats were found. Check that the input represents the contents of a PEM-encoded key file, not the path to such a file. (Parameter 'input')'
知道了!
感谢@MaartenBodewes 让我走上正轨。 我要解码的文件不是二进制文件,而是文本文件。以文本形式读取文件,然后转换为二进制文件,足以使其正常工作。
工作代码大致如下所示,并且可以针对我的具体情况进一步减少。实际上,它将处理 PKCS7 和 CMS 标签 + 二进制和文本文件。
public string Decrypt()
{
var ecms = Read("encryptedFileWithDataThatIWant.xml.enc");
var cert = new X509Certificate2("certificateFile.pfx", "Password");
ecms.Decrypt(new X509Certificate2Collection{cert});
return Encoding.UTF8.GetString(ecms.ContentInfo.Content);
}
private static EnvelopedCms Read(string fileName)
{
//Try read as binary
var maybeFirstException = TryRead(File.ReadAllBytes(fileName), out var ecms);
if (maybeFirstException is null)
{
return ecms;
}
//Otherwise read as text, convert to binary and try again
var text = File
.ReadAllText(fileName)
.Replace("-----BEGIN PKCS7-----", string.Empty)
.Replace("-----BEGIN CMS-----", string.Empty)
.Replace("-----END PKCS7-----", string.Empty)
.Replace("-----END CMS-----", string.Empty);
var binary = Convert.FromBase64String(text);
var maybeSecondException = TryRead(binary, out ecms);
if (maybeSecondException is null)
{
return ecms;
}
throw new AggregateException("Tried to decode file as both binary and text, but both attempts failed", new List<Exception>
{
maybeFirstException,
maybeSecondException
});
}
private static Exception TryRead(byte[] bytes, out EnvelopedCms ecms)
{
ecms = new EnvelopedCms();
try
{
ecms.Decode(bytes);
return null;
}
catch (CryptographicException e)
{
return e;
}
}