简体   繁体   中英

How to decrypt a PKCS7 message

I'm failing at decrypting some XML files in C#.

I know very little of cryptography, but from what I understand, I have a password protected certificate, containing both a private and a public key.

By applying the password to the certificate, I get the private key needed to decrypt files that I receive.

The messages I want to decrypt resides in a PKCS7 (CMS?) formatted file. I believe I need to parse the files, decrypt them, and then un-sign them.

I have little idea on how to do this. I have tried the tooling that I found was obvious candidates to help me get this task done, but I can't get it to work.

At this point, I really want to know; Is there something I'm not understanding? Or am I using the wrong tools for the job?

Here's some of my attempts in one bunch of code:

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));
}

This is what my message looks like, that I want to decrypt:

-----BEGIN PKCS7-----

MIAGCSqGSIb3DQEHA6BAMIACAQAxggGEMIIBgAIBADBoMFExCzAJBgNVBAYTAkRF MSQwIgYDVQQKExtFdXJvcGVhbiBFbmVyZ3kgRXhjaGFuZ2UgQUcxHDAaBgNVB4MT

etc

3nPyd3c9iGyKhWdQPPr/SRWB/l9bCjkla81MgTcj1rRGQyPJXpkyxpc9U4YYZnxt eHkcJMVWDw9ErThok8nh/7bkE4KbWBaLZAac+9occ4deDrlu0wAAAAAAAAAAAAA=

-----END PKCS7-----

EDIT: Here's another minimal example that doesn't work.

//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.'

Apart from the .PFX file, I also do have a PEM file with the private certificate. It looks like this:

-----BEGIN RSA PRIVATE KEY-----

Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,915538553FEFBA6A98930E4BFFDA1E68

Pk0FHxXNHukA62FSmuzzE+gqHgeauZr6z+lqTcbf55cakrQzHQOQUnR0w5kCFPPg

etc

L7U2cWJpbNsRNmBcTyH1WWJ4hYoCqdl9G6Zey4y/EQbZl1DKXtmIiLZSneF0VU9u

-----END RSA PRIVATE KEY-----

I tried importing the key like this, but that doesn't seem to work:

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')'

GOT IT!

Thanks to @MaartenBodewes for putting me on the right track. The file I wanted to decode was not in binary, but in text. Reading the file as text, and then converting to binary, was enough for it to work.

The working code looks approximately like this, and could be reduced even further for my specific case. As it is, it will handle PKCS7 and CMS tags + binary and text files.

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;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM