Reputation: 1433
I am trying to encrypt an XML element in an XML document.
I came across THIS MSDN DOC which shows an approach of how to do this.
If I use the code "as is" in this doc, it works. However, this demo code does not fit my scenario, where I need to save the encrypted XML file and then at another time load it and then decrypt it. So, I have amended the demo code to do this, but now I get the error:
Padding is invalid and cannot be removed.
I have seen in other posts on SO that users having got a similar error have set the Padding
property of the RijndaelManaged
class. I tried this using all of PKCS7
, Zeros
and None
, but I still get the error. I should mention that I applied the same Padding
value to the key for both the encrypt and decrypt methods.
What am I doing wrong, or is there an alternative approach?
Below is my amended code (for a console app). Please assign file paths to the two constants at the top.
PLAINTEXT XML FILE:
<?xml version="1.0" encoding="utf-8" ?><root><creditcard>
<number>19834209</number>
<expiry>02/02/2002</expiry></creditcard></root>
AMENDED CODE:
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Xml;
namespace TestXMLEncryption
{
class Program
{
private const string STR_EncryptedXmlFile = "Path of Encrypted.xml";
private const string STR_PlainTextXmlFile = "Path of PlainText.xml";
static void Main(string[] args)
{
PlainTextXmlToEncryptedXml();
EncryptedXmlToPlainTextXml();
}
private static void EncryptedXmlToPlainTextXml()
{
using (var key = new RijndaelManaged())
{
try
{
key.Padding = PaddingMode.PKCS7;
// Load an XML document.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(STR_EncryptedXmlFile);
Decrypt(xmlDoc, key);
Console.WriteLine("The element was decrypted");
Console.WriteLine(xmlDoc.InnerXml);
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine($"ERROR: {e.Message}");
Console.ReadLine();
}
finally
{
// Clear the key.
if (key != null)
{
key.Clear();
}
}
}
}
private static void PlainTextXmlToEncryptedXml()
{
using (var key = new RijndaelManaged())
{
try
{
key.Padding = PaddingMode.PKCS7;
// Load an XML document.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(STR_PlainTextXmlFile);
// Encrypt the "creditcard" element.
Encrypt(xmlDoc, "creditcard", key);
Console.WriteLine("The element was encrypted");
xmlDoc.Save(STR_EncryptedXmlFile);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
// Clear the key.
if (key != null)
{
key.Clear();
}
}
}
}
public static void Decrypt(XmlDocument Doc, SymmetricAlgorithm Alg)
{
// Find the EncryptedData element in the XmlDocument.
XmlElement encryptedElement = Doc.GetElementsByTagName("EncryptedData")[0] as XmlElement;
// If the EncryptedData element was not found, throw an exception.
if (encryptedElement == null)
{
throw new XmlException("The EncryptedData element was not found.");
}
// Create an EncryptedData object and populate it.
EncryptedData edElement = new EncryptedData();
edElement.LoadXml(encryptedElement);
// Create a new EncryptedXml object.
EncryptedXml exml = new EncryptedXml();
// Decrypt the element using the symmetric key.
byte[] rgbOutput = exml.DecryptData(edElement, Alg);
// Replace the encryptedData element with the plaintext XML element.
exml.ReplaceData(encryptedElement, rgbOutput);
}
public static void Encrypt(XmlDocument Doc, string ElementName, SymmetricAlgorithm Key)
{
////////////////////////////////////////////////
// Find the specified element in the XmlDocument
// object and create a new XmlElemnt object.
////////////////////////////////////////////////
XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementName)[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, Key, 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.
string encryptionMethod = null;
if (Key is TripleDES)
{
encryptionMethod = EncryptedXml.XmlEncTripleDESUrl;
}
else if (Key is DES)
{
encryptionMethod = EncryptedXml.XmlEncDESUrl;
}
else if (Key is Rijndael)
{
switch (Key.KeySize)
{
case 128:
encryptionMethod = EncryptedXml.XmlEncAES128Url;
break;
case 192:
encryptionMethod = EncryptedXml.XmlEncAES192Url;
break;
case 256:
encryptionMethod = EncryptedXml.XmlEncAES256Url;
break;
}
}
else if (Key is Aes)
{
switch (Key.KeySize)
{
case 128:
encryptionMethod = EncryptedXml.XmlEncAES128Url;
break;
case 192:
encryptionMethod = EncryptedXml.XmlEncAES192Url;
break;
case 256:
encryptionMethod = EncryptedXml.XmlEncAES256Url;
break;
}
}
else
{
// Throw an exception if the transform is not in the previous categories
throw new CryptographicException("The specified algorithm is not supported for XML Encryption.");
}
edElement.EncryptionMethod = new EncryptionMethod(encryptionMethod);
// 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);
}
}
}
Upvotes: 0
Views: 382
Reputation: 33098
You are making up a new key in both your Encrypt and your Decrypt routines, because you created the RijndaelManaged object and didn’t set (or read) the Key property.
The sample code didn’t need to, because it used the same object for encryption and decryption, so it had the same random key for both operations.
Upvotes: 0