Search code examples
c#serializationencryptiondatacontractserializer

Is it possible to deserialize an encrypted file via DataContractSerializer?


I'm serializing an object via DataContractSerializer without any problems.

But if I now try to serialize this object into a encrypted file I get an exception when deserializing.

Here is my code:

        public static bool SerializeDataContract<t>(Stream fileStream, t o, bool bCrypt = false)
    {
        DataContractSerializer serializer = new DataContractSerializer(typeof(t));
        if(bCrypt)
        {
            TripleDESCryptoServiceProvider crypt = new TripleDESCryptoServiceProvider();
            crypt.IV = CRYPT_INIT_VECTOR;
            crypt.Key = CRYPT_KEY;
            crypt.Padding = PaddingMode.Zeros;

            using(CryptoStream cryptoStream = new CryptoStream(fileStream, crypt.CreateEncryptor(), CryptoStreamMode.Write))
            {
                serializer.WriteObject(cryptoStream, o);
                cryptoStream.Close();
            }
        }
        else
            serializer.WriteObject(fileStream, o);
        return true;
    }
    public static bool DeserializeDataContract<t>(Stream fileStream, out t o, bool bCrypt = false)
    {
        o = default(t);

        try
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(t));
            if(bCrypt)
            {
                TripleDESCryptoServiceProvider crypt = new TripleDESCryptoServiceProvider();
                crypt.IV = CRYPT_INIT_VECTOR;
                crypt.Key = CRYPT_KEY;
                crypt.Padding = PaddingMode.Zeros;

                using(CryptoStream cryptoStream = new CryptoStream(fileStream, crypt.CreateDecryptor(), CryptoStreamMode.Read))
                {
                    //TraceXML(cryptoStream);

                    o = (t)serializer.ReadObject(cryptoStream);
                    cryptoStream.Close();
                }
            }
            else
            {
                o = (t)serializer.ReadObject(fileStream);
            }
        }
        catch(Exception ex)
        {
            return false;
        }

        return true;
    }

If I call the two functions with bCrypt=false, everything works as expected. But if I call the functions with bCrypt=true, I get an exception when deserializing.

Exception is (tranlated from german to english): SerializationException: The data at the root level is invalid.

If I trace the data that is read after decryption, the data seems ok to me, that is it looks just like serialization without encryption.

Do you know, where the bug is in my code?

Or is it just not possible to use encryption with DataContractSerializer?


Solution

  • The problem is that the encrypted data is padded with zeroes so that the length of the original data isn't obvious.

    Here's one way to remove them so that deserializing works:

    using(var cryptoStream = 
          new CryptoStream(fileStream, crypt.CreateDecryptor(), CryptoStreamMode.Read))
    {               
        using(var reader = new StreamReader(cryptoStream))
        {
            var s = reader.ReadToEnd().TrimEnd(new char[]{'\0'});
    
            using(var stream = new MemoryStream(Encoding.ASCII.GetBytes(s)))
            {
                o = (t)serializer.ReadObject(stream);
            }
        }
    }