ygoe ygoe - 27 days ago 15
C# Question

.NET AES decryption breaks first few bytes

I'm using

AesCryptoServiceProvider
to encrypt and decrypt an XML document on disk. There's an example in the MSDN reference that was helpful. I generate the AES key from the SHA-256 hash of a given password. The first half of it is assigned as IV, since I don't know of any better thing to use here. As far as I know, both key and IV must be the same for encrypting and decrypting.

When I decrypt my file, this is what the beginning of it looks like:

I���H璧�-����[�="1.0" encoding="utf-8"?>


The rest of the document is perfectly fine. There's not even some random padding after the content as I would have expected maybe.

What is causing this random garbage at the beginning of the file?

Here's more of the reading code:

using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider())
{
using (SHA256CryptoServiceProvider sha = new SHA256CryptoServiceProvider())
{
this.cryptoKey = sha.ComputeHash(Encoding.Unicode.GetBytes(password));
}
aes.Key = this.cryptoKey;
Array.Copy(this.cryptoKey, aes.IV, 16);

ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
using (CryptoStream cs = new CryptoStream(fs, decryptor, CryptoStreamMode.Read))
using (StreamReader sr = new StreamReader(cs))
{
string data = sr.ReadToEnd();
xdoc.LoadXml(data);

//xdoc.Load(sr);
}
}


And that's the encryption code:

XmlWriterSettings xws = new XmlWriterSettings();
xws.Encoding = Encoding.UTF8;
xws.Indent = true;
xws.IndentChars = "\t";
xws.OmitXmlDeclaration = false;

using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider())
{
aes.Key = this.cryptoKey;
Array.Copy(this.cryptoKey, aes.IV, 16);

ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
using (CryptoStream cs = new CryptoStream(fs, encryptor, CryptoStreamMode.Write))
using (StreamWriter sw = new StreamWriter(cs, Encoding.UTF8))
{
XmlWriter writer = XmlWriter.Create(sw, xws);
xdoc.Save(writer);
writer.Close();
}
}

Answer

To begin with, don't generate the key material from an ad-hoc algorithm (and yes, when it comes to key derivation, SHA256 is an ad-hoc algorithm). Follow industry standards and use a trusted Password-Based Key Derivation Function. Current standard is PBKDF-2, see also RFC2898. .Net managed crypto implementation is the Rfc2898DeriveBytes class.

Second, you must show us the encryption code. Looks to me like the sample you used appends the IV used at the beginning of the encrypted stream. Which makes perfect sense, given that the IV should not be derived from the password. The key and IV should be derived from password+random, and the 'random' must be sent as part of the file.