Decrypting XML with private digital certificate password

0

I need to decrypt this XML:

<?xml version="1.0" encoding="UTF-8"?>
<xenc:EncryptedData
        xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
        Type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod
        Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:X509Data>
        <ds:X509Certificate></ds:X509Certificate>
    </ds:X509Data>
    <xenc:EncryptedKey
            xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
        <xenc:EncryptionMethod
                Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
        <xenc:CipherData>
            <xenc:CipherValue></xenc:CipherValue>
        </xenc:CipherData>
    </xenc:EncryptedKey>
</ds:KeyInfo>
<xenc:CipherData>
    <xenc:CipherValue></xenc:CipherValue>
</xenc:CipherData>

This is my project that I'm running:

using System;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;

class Program
{
static void Main(string[] args)
{

    // Create an XmlDocument object.
    XmlDocument xmlDoc = new XmlDocument();

    string arquivoXML = "C:\Teste-Desc\1-23042015-0703-ACE58971ACE59070.xml";
    string thumbPrintCertificado = "BA71F3AA888E0197D945D2A0CDE21C7E694CE432";


    // Load an XML file into the XmlDocument object. 
    try
    {
        xmlDoc.PreserveWhitespace = true;
        xmlDoc.Load(arquivoXML);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }

    // Create a new TripleDES key. 
    TripleDESCryptoServiceProvider tDESkey = new TripleDESCryptoServiceProvider();
    X509Certificate2 cert = BuscaConfiguracaoCertificado(thumbPrintCertificado);
    RSACryptoServiceProvider rsaKey = (RSACryptoServiceProvider)cert.PrivateKey;

    try
    {            
        Decrypt(xmlDoc, rsaKey);


        // Display the encrypted XML to the console.
        Console.WriteLine();
        Console.WriteLine("Decrypted XML:");
        Console.WriteLine();
        Console.WriteLine(xmlDoc.OuterXml);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
    finally
    {
        // Clear the TripleDES key.
        tDESkey.Clear();
    }

}

public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, TripleDESCryptoServiceProvider Alg)
{

    //////////////////////////////////////////////// 
    // Find the specified element in the XmlDocument 
    // object and create a new XmlElemnt object. 
    ////////////////////////////////////////////////

    XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;

    // Throw an XmlException if the element was not found. 
    if (elementToEncrypt == null)
    {
        throw new XmlException("The specified element was not found");

    }

    ////////////////////////////////////////////////// 
    // Create a new instance of the EncryptedXml class  
    // and use it to encrypt the XmlElement with the  
    // symmetric key. 
    //////////////////////////////////////////////////

    EncryptedXml eXml = new EncryptedXml();

    byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, Alg, false);

    //////////////////////////////////////////////// 
    // Construct an EncryptedData object and populate 
    // it with the desired encryption information. 
    ////////////////////////////////////////////////


    EncryptedData edElement = new EncryptedData();

    edElement.Type = EncryptedXml.XmlEncElementUrl;


    // Create an EncryptionMethod element so that the  
    // receiver knows which algorithm to use for decryption. 
    // Determine what kind of algorithm is being used and 
    // supply the appropriate URL to the EncryptionMethod element.

    edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncTripleDESUrl);

    // Add the encrypted element data to the  
    // EncryptedData object.
    edElement.CipherData.CipherValue = encryptedElement;

    //////////////////////////////////////////////////// 
    // Replace the element from the original XmlDocument 
    // object with the EncryptedData element. 
    ////////////////////////////////////////////////////

    EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);

}

public static void Decrypt(XmlDocument Doc, RSA Alg)
{
    // Check the arguments.
    if (Doc == null)
        throw new ArgumentNullException("Doc");
    if (Alg == null)
        throw new ArgumentNullException("Alg");

    // Create a new EncryptedXml object.
    EncryptedXml exml = new EncryptedXml(Doc);

    // Add a key-name mapping.
    // This method can only decrypt documents
    // that present the specified key name.
    exml.AddKeyNameMapping("rsaKey", Alg);

    // Decrypt the element.
    exml.DecryptDocument();

}

public static X509Certificate2 BuscaConfiguracaoCertificado(string sDigitalThumbPrint)
{
    X509Certificate2 x509Cert = null;

    X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
    X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
    X509Certificate2Collection collection1 = null;
    collection1 = (X509Certificate2Collection)collection.Find(X509FindType.FindByThumbprint, sDigitalThumbPrint, false);

    for (int i = 0; i < collection1.Count; i++)
    {
        x509Cert = collection1[i];
    }

    return x509Cert;
}

}

But when it arrives at the point:

exml.DecryptDocument();

Generates the following exception: Unable to retrieve decryption key.

Second TJMG manual should use the client's Digital Certificate private key ...

I do not know what to do anymore, I gratify if anyone can help me ...

    
asked by anonymous 28.04.2015 / 03:03

1 answer

1
  

Partial response

I do not have an answer to your question, but reading the cited documentation I can see what you're doing it wrong (which is a first step to fix). I do not know how to use this type of encryption in C # (by the way, in no language) however, so I'll just explain what is happening in order to guide you in the search for a solution:

  • Your document is encrypted using AES 256, CBC mode, symmetric encryption type :
  •     <xenc:EncryptionMethod
                Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
    
  • The encryption key (which, being symmetric, serves both to encrypt and to decrypt) is contained in the document itself:

    <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        ...
        <xenc:EncryptedKey
        xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
            ...
            <xenc:CipherData>
                <xenc:CipherValue></xenc:CipherValue>
            </xenc:CipherData>
        </xenc:EncryptedKey>
    </ds:KeyInfo>
    

    ... but not in flat format (of course, so anyone could decipher!): it was encrypted using another key - a key-encrypting key key - KEK).

    <xenc:EncryptionMethod
            Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
    

    As you pointed out, it has been encrypted with the public key of the client certificate (RSA 1.5), thus requiring the corresponding private key to decrypt.

  • The Java code shown as a reference is performing these operations correctly. Commenting:

    // Obtém uma instância da cifra RSA 1.5 (para a KEK)
    cipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);
    
    // Referencia o elemento que contém o item criptografado
    Element ee = (Element) doc.getElementsByTagName("xenc:EncryptedData").item(0);
    
    // Obtém uma instância da cifra AES 256 (para os dados de fato)
    // Estou assumindo que o modo CBC é o modo padrão, quando um não é especificado
    cipher = XMLCipher.getInstance(XMLCipher.AES_256);
    
    // Inicializa
    cipher.init(XMLCipher.DECRYPT_MODE, null);
    
    // Atribui a chave cifradora de chaves
    cipher.setKEK(rsaKey);
    
    // Faz todas as operações necessárias, nos elementos corretos
    // - Decifra a chave AES usando a chave RSA fornecida
    // - Decifra os dados usando a chave AES decifrada
    return cipher.doFinal(doc, ee);
    

    It is therefore necessary to perform these same operations in C #. I believe (but I can not confirm from experience) that this "How to " implements all the necessary steps:

        CspParameters cspParams = new CspParameters();
        cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
    
        // Get the RSA key from the key container.  This key will decrypt 
        // a symmetric key that was imbedded in the XML document.
        RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
    
        try
        {
            // Decrypt the elements.
            Decrypt(xmlDoc, rsaKey, "rsaKey");
    
            // Save the XML document.
            xmlDoc.Save("test.xml");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        finally
        {
            // Clear the RSA key.
            rsaKey.Clear();
        }
    

    ( Decrypt is the same as you're already doing)

    I can not guarantee that this will solve your problem (like finding this key in the key store , this is something I have no idea how it works), but it is already a step in the right direction. / p>     

    05.05.2015 / 15:30