none
Decrypt XML file error: Padding is invalid and cannot be removed RRS feed

  • Question

  • I encrypt an XML file and save it to the original file.
    I then open the file and try to decrypt it, and get the error "Padding is invalid and cannot be removed".
    I think this is because during encryption, I execute

    key = New RijndaelManaged()

    And, during decryption, I also execute

    key = New RijndaelManaged()
    How can I save the key from the encryption ?

    Thank you.

    This is the code to encrypt and save the XML file:

    Imports System.Xml
    Imports System.Security.Cryptography
    Imports System.Security.Cryptography.Xml
    
    Dim key As RijndaelManaged = Nothing
    ' Create a new Rijndael key.
    key = New RijndaelManaged()
    ' Load an XML document.
    Dim xmlDoc As New XmlDocument()
    xmlDoc.PreserveWhitespace = True
    xmlDoc.Load("myXMLFile.XML")
    Encrypt(xmlDoc, "myElement1", key)
    Encrypt(xmlDoc, "myElement2", key)
    xmlDoc.Save("myXMLFile.XML")
    This is the code to decrypt the XML file:
    Imports System.Xml
    Imports System.Security.Cryptography
    Imports System.Security.Cryptography.Xml
    
    Dim key As RijndaelManaged = Nothing
    key = New RijndaelManaged()
    Dim xmlDoc As New XmlDocument()
    xmlDoc.PreserveWhitespace = True
    xmlDoc.Load("myXMLFile.XML")
    Decrypt(xmlDoc, key)
    Tuesday, March 7, 2017 3:46 PM

Answers

  • aujong,

    As a follow-up, here's an example that you can try:

    Option Strict On Option Explicit On Option Infer Off Public Class Form1 Private Sub Form1_Load(sender As System.Object, _ e As System.EventArgs) _ Handles MyBase.Load Dim myList As New List(Of MyExampleClass) MyExampleClass.AddNew(myList, "Mickey", "Mouse") MyExampleClass.AddNew(myList, "Donald", "Duck") Dim desktop As String = _ Environment.GetFolderPath(Environment.SpecialFolder.Desktop) Dim filePath As String = IO.Path.Combine(desktop, "EncryptedXML.xml") MyExampleClass.ExportToXML(myList, filePath, "Your Secret Key Here") Stop End Sub End Class Public Class MyExampleClass Private _firstName As String Private _lastName As String Private Sub New(ByVal fName As String, _ ByVal lName As String) If Not String.IsNullOrWhiteSpace(fName) AndAlso _ Not String.IsNullOrWhiteSpace(lName) Then _firstName = fName.Trim _lastName = lName.Trim End If End Sub Public ReadOnly Property FirstName As String Get Return _firstName End Get End Property Public ReadOnly Property LastName As String Get Return _lastName End Get End Property Public Shared Sub _ AddNew(ByRef list As List(Of MyExampleClass), _ ByVal firstName As String, _ ByVal lastName As String) If list IsNot Nothing Then Dim instance As New MyExampleClass(firstName, lastName) If instance IsNot Nothing Then list.Add(instance) End If End If End Sub Public Shared Sub _ ExportToXML(ByVal list As List(Of MyExampleClass), _ ByVal filePath As String, _ ByVal key As String) If list IsNot Nothing AndAlso list.Count > 0 Then If Not String.IsNullOrWhiteSpace(key) Then Dim fi As New IO.FileInfo(filePath) If fi.Exists Then fi.Delete() End If Using s3d As New Simple3Des(key) Dim xDoc As XElement = _ <Data> <%= From mec As MyExampleClass In list Select _ <Info> <%= New XAttribute("Field1", s3d.EncryptData(mec.FirstName)) %> <%= New XAttribute("Field2", s3d.EncryptData(mec.LastName)) %> </Info> %> </Data> xDoc.Save(fi.FullName) End Using End If End If End Sub ' Based on: https://msdn.microsoft.com/en-us/library/ms172831.aspx Private NotInheritable Class Simple3Des Implements IDisposable Private TripleDes As New Security.Cryptography.TripleDESCryptoServiceProvider Sub New(ByVal key As String) ' Initialize the crypto provider. TripleDes.Key = TruncateHash(key, TripleDes.KeySize \ 8) TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8) End Sub Public Function EncryptData(ByVal plaintext As String) _ As String ' Convert the plaintext string to a byte array. Dim plaintextBytes() As Byte = _ System.Text.Encoding.Unicode.GetBytes(plaintext) ' Create the stream. Dim ms As New System.IO.MemoryStream ' Create the encoder to write to the stream. Dim encStream As New Security.Cryptography.CryptoStream(ms, _ TripleDes.CreateEncryptor(), _ System.Security.Cryptography.CryptoStreamMode.Write) ' Use the crypto stream to write the byte array to the stream. encStream.Write(plaintextBytes, 0, plaintextBytes.Length) encStream.FlushFinalBlock() ' Convert the encrypted stream to a printable string. Return Convert.ToBase64String(ms.ToArray) End Function Public Function DecryptData(ByVal encryptedtext As String) _ As String ' Convert the encrypted text string to a byte array. Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext) ' Create the stream. Dim ms As New System.IO.MemoryStream ' Create the decoder to write to the stream. Dim decStream As New Security.Cryptography.CryptoStream(ms, _ TripleDes.CreateDecryptor(), _ System.Security.Cryptography.CryptoStreamMode.Write) ' Use the crypto stream to write the byte array to the stream. decStream.Write(encryptedBytes, 0, encryptedBytes.Length) decStream.FlushFinalBlock() ' Convert the plaintext stream to a string. Return System.Text.Encoding.Unicode.GetString(ms.ToArray) End Function Private Function TruncateHash(ByVal key As String, _ ByVal length As Integer) _ As Byte() Dim sha1 As New Security.Cryptography.SHA1CryptoServiceProvider ' Hash the key. Dim keyBytes() As Byte = _ System.Text.Encoding.Unicode.GetBytes(key) Dim hash() As Byte = sha1.ComputeHash(keyBytes) ' Truncate or pad the hash. ReDim Preserve hash(length - 1) Return hash End Function Public Sub Dispose() Implements IDisposable.Dispose If TripleDes IsNot Nothing Then TripleDes.Dispose() TripleDes = Nothing End If End Sub End Class End Class


    I set the XML up to use attributes but you can just as easily use elements. The result is shown here:

    <?xml version="1.0" encoding="utf-8"?>
    <Data>
      <Info Field1="f/gEzZx6Y6ZGmK7ShEG4Fg==" Field2="e/RXnYwoyAjulMmLC0bn3w==" />
      <Info Field1="M9Mc9l8MLksYomFLq9xNVw==" Field2="BpzLI9VGsMmTTmN1R/0nMQ==" />
    </Data>


    "One who has no vices also has no virtues..."

    • Marked as answer by aujong Tuesday, March 7, 2017 7:15 PM
    Tuesday, March 7, 2017 4:23 PM

All replies

  • aujong,

    You might want to reconsider how you're encrypting it and instead of AES, opt for text encryption. XML is just text after all.

    So when writing the XML file, for each 'element' of the XML have this function return the encrypted version:

    Based on: https://msdn.microsoft.com/en-us/library/ms172831.aspx
    
    Public NotInheritable Class Simple3Des
        Implements IDisposable
    
        Private TripleDes As New Security.Cryptography.TripleDESCryptoServiceProvider
    
        Sub New(ByVal key As String)
            ' Initialize the crypto provider.
            TripleDes.Key = TruncateHash(key, TripleDes.KeySize \ 8)
            TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8)
        End Sub
    
        Public Function EncryptData(ByVal plaintext As String) _
            As String
    
            ' Convert the plaintext string to a byte array. 
            Dim plaintextBytes() As Byte = _
                System.Text.Encoding.Unicode.GetBytes(plaintext)
    
            ' Create the stream. 
            Dim ms As New System.IO.MemoryStream
            ' Create the encoder to write to the stream. 
            Dim encStream As New Security.Cryptography.CryptoStream(ms, _
                TripleDes.CreateEncryptor(), _
                System.Security.Cryptography.CryptoStreamMode.Write)
    
            ' Use the crypto stream to write the byte array to the stream.
            encStream.Write(plaintextBytes, 0, plaintextBytes.Length)
            encStream.FlushFinalBlock()
    
            ' Convert the encrypted stream to a printable string. 
            Return Convert.ToBase64String(ms.ToArray)
        End Function
    
        Public Function DecryptData(ByVal encryptedtext As String) _
            As String
    
            ' Convert the encrypted text string to a byte array. 
            Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext)
    
            ' Create the stream. 
            Dim ms As New System.IO.MemoryStream
            ' Create the decoder to write to the stream. 
            Dim decStream As New Security.Cryptography.CryptoStream(ms, _
                TripleDes.CreateDecryptor(), _
                System.Security.Cryptography.CryptoStreamMode.Write)
    
            ' Use the crypto stream to write the byte array to the stream.
            decStream.Write(encryptedBytes, 0, encryptedBytes.Length)
            decStream.FlushFinalBlock()
    
            ' Convert the plaintext stream to a string. 
            Return System.Text.Encoding.Unicode.GetString(ms.ToArray)
        End Function
    
        Private Function TruncateHash(ByVal key As String, _
                                      ByVal length As Integer) _
                                      As Byte()
    
            Dim sha1 As New Security.Cryptography.SHA1CryptoServiceProvider
    
            ' Hash the key. 
            Dim keyBytes() As Byte = _
                System.Text.Encoding.Unicode.GetBytes(key)
            Dim hash() As Byte = sha1.ComputeHash(keyBytes)
    
            ' Truncate or pad the hash. 
            ReDim Preserve hash(length - 1)
            Return hash
        End Function
    
        Public Sub Dispose() Implements IDisposable.Dispose
            If TripleDes IsNot Nothing Then
                TripleDes.Dispose()
                TripleDes = Nothing
            End If
        End Sub
    End Class
    
    

    On the way in (reading it), just do the opposite.

    So long as your encryption key is the same both times, it works without a problem.


    "One who has no vices also has no virtues..."

    Tuesday, March 7, 2017 3:55 PM
  • Clearly, you should look at what the RijndaelManaged class does: https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged.rijndaelmanaged(v=vs.110).aspx

    modify your code to generate the key and IV before creating the encryptor, then the decryptor...


    Tuesday, March 7, 2017 3:58 PM
  • aujong,

    As a follow-up, here's an example that you can try:

    Option Strict On Option Explicit On Option Infer Off Public Class Form1 Private Sub Form1_Load(sender As System.Object, _ e As System.EventArgs) _ Handles MyBase.Load Dim myList As New List(Of MyExampleClass) MyExampleClass.AddNew(myList, "Mickey", "Mouse") MyExampleClass.AddNew(myList, "Donald", "Duck") Dim desktop As String = _ Environment.GetFolderPath(Environment.SpecialFolder.Desktop) Dim filePath As String = IO.Path.Combine(desktop, "EncryptedXML.xml") MyExampleClass.ExportToXML(myList, filePath, "Your Secret Key Here") Stop End Sub End Class Public Class MyExampleClass Private _firstName As String Private _lastName As String Private Sub New(ByVal fName As String, _ ByVal lName As String) If Not String.IsNullOrWhiteSpace(fName) AndAlso _ Not String.IsNullOrWhiteSpace(lName) Then _firstName = fName.Trim _lastName = lName.Trim End If End Sub Public ReadOnly Property FirstName As String Get Return _firstName End Get End Property Public ReadOnly Property LastName As String Get Return _lastName End Get End Property Public Shared Sub _ AddNew(ByRef list As List(Of MyExampleClass), _ ByVal firstName As String, _ ByVal lastName As String) If list IsNot Nothing Then Dim instance As New MyExampleClass(firstName, lastName) If instance IsNot Nothing Then list.Add(instance) End If End If End Sub Public Shared Sub _ ExportToXML(ByVal list As List(Of MyExampleClass), _ ByVal filePath As String, _ ByVal key As String) If list IsNot Nothing AndAlso list.Count > 0 Then If Not String.IsNullOrWhiteSpace(key) Then Dim fi As New IO.FileInfo(filePath) If fi.Exists Then fi.Delete() End If Using s3d As New Simple3Des(key) Dim xDoc As XElement = _ <Data> <%= From mec As MyExampleClass In list Select _ <Info> <%= New XAttribute("Field1", s3d.EncryptData(mec.FirstName)) %> <%= New XAttribute("Field2", s3d.EncryptData(mec.LastName)) %> </Info> %> </Data> xDoc.Save(fi.FullName) End Using End If End If End Sub ' Based on: https://msdn.microsoft.com/en-us/library/ms172831.aspx Private NotInheritable Class Simple3Des Implements IDisposable Private TripleDes As New Security.Cryptography.TripleDESCryptoServiceProvider Sub New(ByVal key As String) ' Initialize the crypto provider. TripleDes.Key = TruncateHash(key, TripleDes.KeySize \ 8) TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8) End Sub Public Function EncryptData(ByVal plaintext As String) _ As String ' Convert the plaintext string to a byte array. Dim plaintextBytes() As Byte = _ System.Text.Encoding.Unicode.GetBytes(plaintext) ' Create the stream. Dim ms As New System.IO.MemoryStream ' Create the encoder to write to the stream. Dim encStream As New Security.Cryptography.CryptoStream(ms, _ TripleDes.CreateEncryptor(), _ System.Security.Cryptography.CryptoStreamMode.Write) ' Use the crypto stream to write the byte array to the stream. encStream.Write(plaintextBytes, 0, plaintextBytes.Length) encStream.FlushFinalBlock() ' Convert the encrypted stream to a printable string. Return Convert.ToBase64String(ms.ToArray) End Function Public Function DecryptData(ByVal encryptedtext As String) _ As String ' Convert the encrypted text string to a byte array. Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext) ' Create the stream. Dim ms As New System.IO.MemoryStream ' Create the decoder to write to the stream. Dim decStream As New Security.Cryptography.CryptoStream(ms, _ TripleDes.CreateDecryptor(), _ System.Security.Cryptography.CryptoStreamMode.Write) ' Use the crypto stream to write the byte array to the stream. decStream.Write(encryptedBytes, 0, encryptedBytes.Length) decStream.FlushFinalBlock() ' Convert the plaintext stream to a string. Return System.Text.Encoding.Unicode.GetString(ms.ToArray) End Function Private Function TruncateHash(ByVal key As String, _ ByVal length As Integer) _ As Byte() Dim sha1 As New Security.Cryptography.SHA1CryptoServiceProvider ' Hash the key. Dim keyBytes() As Byte = _ System.Text.Encoding.Unicode.GetBytes(key) Dim hash() As Byte = sha1.ComputeHash(keyBytes) ' Truncate or pad the hash. ReDim Preserve hash(length - 1) Return hash End Function Public Sub Dispose() Implements IDisposable.Dispose If TripleDes IsNot Nothing Then TripleDes.Dispose() TripleDes = Nothing End If End Sub End Class End Class


    I set the XML up to use attributes but you can just as easily use elements. The result is shown here:

    <?xml version="1.0" encoding="utf-8"?>
    <Data>
      <Info Field1="f/gEzZx6Y6ZGmK7ShEG4Fg==" Field2="e/RXnYwoyAjulMmLC0bn3w==" />
      <Info Field1="M9Mc9l8MLksYomFLq9xNVw==" Field2="BpzLI9VGsMmTTmN1R/0nMQ==" />
    </Data>


    "One who has no vices also has no virtues..."

    • Marked as answer by aujong Tuesday, March 7, 2017 7:15 PM
    Tuesday, March 7, 2017 4:23 PM
  • Thank you for your help !
    Tuesday, March 7, 2017 7:15 PM
  • Thank you for your help !

    You're welcome. I'm glad that it helped. :)


    "One who has no vices also has no virtues..."

    Tuesday, March 7, 2017 7:24 PM