EncryptedXml DecryptDocument method throws "Bad Data" exception
Asked Answered
G

2

6

I wrote a code block for Encrypt/Decrypt Streams. The code is working in my local machine. But when I publish my code on web The Decryption functions throws "Bad Data" exception Here is the my Encrypton and Decryption functions

private static MemoryStream EncryptStream(XmlDocument xmlDoc, XmlElement elementToEncrypt, string password)
{
    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = password;
    RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
    RijndaelManaged sessionKey = null;
    try
    {

        if (xmlDoc == null)
            throw new ArgumentNullException("xmlDoc");
        if (rsaKey == null)
            throw new ArgumentNullException("rsaKey");
        if (elementToEncrypt == null)
            throw new ArgumentNullException("elementToEncrypt");

        sessionKey = new RijndaelManaged();
        sessionKey.KeySize = 256;

        EncryptedXml eXml = new EncryptedXml();
        byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);

        EncryptedData edElement = new EncryptedData();
        edElement.Type = EncryptedXml.XmlEncElementUrl;
        edElement.Id = EncryptionElementID;
        edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);

        EncryptedKey ek = new EncryptedKey();
        byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, rsaKey, false);
        ek.CipherData = new CipherData(encryptedKey);
        ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);

        edElement.KeyInfo = new KeyInfo();

        KeyInfoName kin = new KeyInfoName();
        kin.Value = KeyName;

        ek.KeyInfo.AddClause(kin);
        edElement.CipherData.CipherValue = encryptedElement;
        edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));

        EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);

        if (sessionKey != null)
        {
            sessionKey.Clear();
        }
        rsaKey.Clear();
        MemoryStream stream = new MemoryStream();
        xmlDoc.Save(stream);
        stream.Position = 0;
        Encoding encodeing = System.Text.UnicodeEncoding.Default;
        return stream;
    }
    catch (Exception e)
    {
        if (sessionKey != null)
        {
            sessionKey.Clear();
        }
        rsaKey.Clear();
        throw (e);
    }
}

private static MemoryStream DecryptStream(XmlDocument xmlDoc, string password)
{
    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = password;
    RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
    EncryptedXml exml = null;
    try
    {
        if (xmlDoc == null)
            throw new ArgumentNullException("xmlDoc");
        if (rsaKey == null)
            throw new ArgumentNullException("rsaKey");

        exml = new EncryptedXml(xmlDoc);
        exml.AddKeyNameMapping(KeyName, rsaKey);

        exml.DecryptDocument();
        rsaKey.Clear();

        MemoryStream outStream = new MemoryStream();
        xmlDoc.Save(outStream);
        outStream.Position = 0;
        return outStream;
    }
    catch (Exception e)
    {
        rsaKey.Clear();
        throw (e);
    }
}

the exception is thrown on "exml.DecryptDocument();" line.

Do you have any idea about problem and the solution?

Edit:

in MSDN page, there is remark which is as follows

To use XML Encryption with X.509 certificates, you must have the Microsoft Enhanced Cryptographic Provider installed and the X.509 certificate must use the Enhanced Provider. If you do not have the Microsoft Enhanced Cryptographic Provider installed or the X.509 certificate does not use the Enhanced Provider, a CryptographicException with an "Unknown Error" will be thrown when you decrypt an XML document.

Do you have any idea about "Microsoft Enhanced Cryptographic Provider" and "X.509 certificate"? And Can my problem be related to this those?

Gorgias answered 11/3, 2013 at 13:17 Comment(8)
what is the value of your KeyName in web ?Caldarium
I tried the same in my machine also i couldn't simulate. pls share the KeyName valueCaldarium
I tried out with this key too, but no hope i couldn't simulate. I'm very much doubted on the xml content. Perhaps publish xml content will help me to simulate and help uCaldarium
How do you try to simulate the code? did you encrypta document then try to decrypt witm my code?Gorgias
Can you show us your Encrypt method?Scleroderma
sure, but you should wait for it :)Gorgias
I added the encryption code before decryption code.Gorgias
Hint: don't use "throw e;". Use "throw;"Sybaris
E
4

The reason the Decryption functions throws "Bad Data" exception when trying to Decrypt on another PC is that the CspParameters is linked to the session on the PC where the Encryption was run.

The cspParams object will need to be embedded and encrypted in the XML to enable Decryption on another PC. Luckily there is EncryptionProperty we can use for this.

private static MemoryStream EncryptStream(XmlDocument xmlDoc, XmlElement elementToEncrypt, string password)
{
    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = password;
    RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
    RijndaelManaged sessionKey = null;
    try
    {
        if (xmlDoc == null)
            throw new ArgumentNullException("xmlDoc");
        if (rsaKey == null)
            throw new ArgumentNullException("rsaKey");
        if (elementToEncrypt == null)
            throw new ArgumentNullException("elementToEncrypt");

        sessionKey = new RijndaelManaged();
        sessionKey.KeySize = 256;

        EncryptedXml eXml = new EncryptedXml();
        byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);

        EncryptedData edElement = new EncryptedData();
        edElement.Type = EncryptedXml.XmlEncElementUrl;
        edElement.Id = EncryptionElementID;
        edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);

        EncryptedKey ek = new EncryptedKey();
        byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, rsaKey, false);
        ek.CipherData = new CipherData(encryptedKey);
        ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);

        // Save some more information about the key using the EncryptionProperty element.

        // Create a new "EncryptionProperty" XmlElement object. 
        var property = new XmlDocument().CreateElement("EncryptionProperty", EncryptedXml.XmlEncNamespaceUrl);

        // Set the value of the EncryptionProperty" XmlElement object.
        property.InnerText = RijndaelManagedEncryption.EncryptRijndael(Convert.ToBase64String(rsaKey.ExportCspBlob(true)),
                        "Your Salt string here");

        // Create the EncryptionProperty object using the XmlElement object. 
        var encProperty = new EncryptionProperty(property);

        // Add the EncryptionProperty object to the EncryptedKey object.
        ek.AddProperty(encProperty);

        edElement.KeyInfo = new KeyInfo();

        KeyInfoName kin = new KeyInfoName();
        kin.Value = KeyName;

        ek.KeyInfo.AddClause(kin);
        edElement.CipherData.CipherValue = encryptedElement;
        edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));

        EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);

        if (sessionKey != null)
        {
            sessionKey.Clear();
        }
        rsaKey.Clear();
        MemoryStream stream = new MemoryStream();
        xmlDoc.Save(stream);
        stream.Position = 0;
        Encoding encodeing = System.Text.UnicodeEncoding.Default;
        return stream;
    }
    catch (Exception)
    {
        if (sessionKey != null)
        {
            sessionKey.Clear();
        }
        rsaKey.Clear();
        throw;
    }
}

private static MemoryStream DecryptStream(XmlDocument xmlDoc, string password)
{
    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = password;
    RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);

    var keyInfo = xmlDoc.GetElementsByTagName("EncryptionProperty")[0].InnerText;
        rsaKey.ImportCspBlob(
            Convert.FromBase64String(RijndaelManagedEncryption.DecryptRijndael(keyInfo,
                "Your Salt string here")));
    EncryptedXml exml = null;
    try
    {
        if (xmlDoc == null)
            throw new ArgumentNullException("xmlDoc");
        if (rsaKey == null)
            throw new ArgumentNullException("rsaKey");

        exml = new EncryptedXml(xmlDoc);
        exml.AddKeyNameMapping(KeyName, rsaKey);

        exml.DecryptDocument();
        rsaKey.Clear();

        MemoryStream outStream = new MemoryStream();
        xmlDoc.Save(outStream);
        outStream.Position = 0;
        return outStream;
    }
    catch (Exception)
    {
        rsaKey.Clear();
        throw;
    }
}

Have a look here for the RijndaelManagedEncryption class.

Ellmyer answered 14/10, 2014 at 16:20 Comment(2)
Thank you for your answer. It really helped me a lot.Thither
Always a pleasure and happy it helped.Ellmyer
D
1

Do not reinvent cryptography protocols. You will get it wrong. Case in point, mishandling the RSA key stored in the CSPs and expect them to magically appear on any machine.

To encrypt data in transfer, use SSL/TLS. .Net offers it out-of-the-box with SslStream. For WCF see How to: Configure an IIS-hosted WCF service with SSL.

Discontinue answered 11/3, 2013 at 14:12 Comment(1)
Thanks for your reply, I will implement your recommendation but still I need to implement additional encryption in addition to the ssl. So I have to solve that problem. Do you have any recommendation for my problem ?Gorgias

© 2022 - 2024 — McMap. All rights reserved.