Decrypting PKCS7 message with C#

Proprietary encryption software

Im sick of Russian GHOST cryptography and CryptoPro poorly designed tools. Can we use Windows Crypto API to decrypt file with few lines of code? Yes! 

To read PKCS7 message we have to use EnvelopedCms class of System.Security namespace. It may contain either base64 or binary data.

static void Main(string[] args)
{
    EnvelopedCms envelopedCms = TryRead("h:\\file.zip.sig.enc");

    if (envelopedCms == null)
    {
        Console.WriteLine("Unable to read file");
        return;
    }

    if (!TryDecode(envelopedCms))
    {
        Console.WriteLine("Unable to decode, no appropriate certificate");
        return;
    }

    Export(envelopedCms, "h:\\file.zip");
}


TryRead

First we try to read file as binary, if it fails as base64 text.

private static EnvelopedCms TryRead(string fileName)
{
    EnvelopedCms envelopedCms = TryRead(File.ReadAllBytes(fileName));

    if (envelopedCms != null)
    {
        return envelopedCms;
    }

    string text = File.ReadAllText(fileName);
    text = text.Replace("-----BEGIN CMS-----", "").Replace("-----END CMS-----", "");
    byte[] fromBase64String = Convert.FromBase64String(text);

    return TryRead(fromBase64String);
}

private static EnvelopedCms TryRead(byte[] bytes)
{
    try
    {
        EnvelopedCms ecms = new EnvelopedCms();
        ecms.Decode(bytes);

        return ecms;
    }
    catch (CryptographicException e)
    {
        return null;
    }
}

TryDecode

There is a recipient certificate serial number in EnvelopedCms.RecipientInfos[x].RecipientIdentifier.Value
We need to iterate over all recipients and search for appropriate certificate in local store.

private static bool TryDecode(EnvelopedCms envelopedCms)
{
    X509Certificate2Collection extraStore = new X509Certificate2Collection();
    IList<X509Certificate2> activeCertificates = GetActiveCertificates();

    foreach (RecipientInfo envelopedCmsRecipientInfo in envelopedCms.RecipientInfos)
    {
        X509IssuerSerial recipientIdentifierValue = (X509IssuerSerial)envelopedCmsRecipientInfo.RecipientIdentifier.Value;

        X509Certificate2 certificate2 = activeCertificates.FirstOrDefault(c => c.SerialNumber == recipientIdentifierValue.SerialNumber);

        if (certificate2 != null)
        {
            extraStore.Add(certificate2);
            break;
        }
    }

    envelopedCms.Decrypt(extraStore);
    return true;
}

Export

envelopedCms.ContentInfo.Content will contain decrypted message either as binary or as base64 text

private static void Export(EnvelopedCms envelopedCms, string fileName)
{
    ContentInfo contentInfo = envelopedCms.ContentInfo;
    byte[] contentBytes = contentInfo.Content;

    string s = Encoding.UTF8.GetString(contentBytes);

    if (s.StartsWith("-----BEGIN CMS-----"))
    {
        s = s.Replace("-----BEGIN CMS-----", "").Replace("-----END CMS-----", "");
        contentBytes = Convert.FromBase64String(s);
    }

    File.WriteAllBytes(fileName, contentBytes);
}

 

That’s it!

We were able to decode message without deep dive into cryptography and without extra software.

Great!

Comments are closed