I wrote in a previous post that I was planning to have a poke around with ViewState, extending the stuff I've done on compression into encryption and signing etc...well there's good and bad news for this plan. It looks like (oddly) that the MAC and encryption stuff is actually handled in the LosWriter class; an internal class used by LosFormatter to actually do the object serialization...it uses the following code to do this (thanks once more to the indispensible Reflector) :
internal void CompleteTransforms(TextWriter output, bool enableMac, byte[] macKey)
{ int num1;
byte[] array1;
string text1;
char[] array2;
string text2;
num1 = 0;
if (this._recyclable)
{
this._byteBuffer = ((byte[]) LosWriter._byteBufferAllocator.GetBuffer());
if (this._freePos > 0)
{
num1 = Encoding.UTF8.GetBytes(this._charBuffer, 0, this._freePos, this._byteBuffer, 0);
}
if (enableMac)
{
array1 = MachineKey.GetEncodedData(this._byteBuffer, macKey, 0, &(num1));
text1 = Convert.ToBase64String(array1, 0, num1);
output.Write(text1);
return;
}
array2 = ((char[]) LosWriter._charBufferAllocatorBase64.GetBuffer());
num1 = Convert.ToBase64CharArray(this._byteBuffer, 0, num1, array2, 0);
output.Write(array2, 0, num1);
LosWriter._charBufferAllocatorBase64.ReuseBuffer(array2);
return;
}
this._byteBuffer = Encoding.UTF8.GetBytes(this._charBuffer, 0, this._freePos);
num1 = this._byteBuffer.Length;
if (enableMac)
{
this._byteBuffer = MachineKey.GetEncodedData(this._byteBuffer, macKey, 0, &(num1));
}
text2 = Convert.ToBase64String(this._byteBuffer);
output.Write(text2);
}
As you can probably see, this code handles the application of the MAC key and encryption to the serialized data. This is the code used by the 'MachineKey' to perform the encryption:
internal static byte[] EncryptOrDecryptData(bool fEncrypt, byte[] buf, byte[] modifier, int start, int length)
{ MemoryStream stream1;
ICryptoTransform transform1;
CryptoStream stream2;
byte[] array1;
byte[] array2;
MachineKey.EnsureConfig();
stream1 = new MemoryStream();
transform1 = MachineKey.GetCryptoTransform(fEncrypt);
stream2 = new CryptoStream(stream1, transform1, 1);
stream2.Write(buf, start, length);
if (fEncrypt && (modifier != null))
{
stream2.Write(modifier, 0, modifier.Length);
}
stream2.FlushFinalBlock();
array1 = stream1.ToArray();
stream2.Close();
MachineKey.ReturnCryptoTransform(fEncrypt, transform1);
if (!fEncrypt && (modifier != null))
{
array2 = new byte[((uint) (array1.Length - modifier.Length))];
Buffer.BlockCopy(array1, 0, array2, 0, array2.Length);
array1 = array2;
}
return array1;
}
Unfortunately, this means I'll either have to play about with reflection / dump the source from Refelector / completely reinvent how this works to go much further with my ViewState tinkering, god it'd have been nice if this stuff were done with a Factory originally...guess they didn't think anyone would be nuts enough to want to play with it...:-)
I'm eventually going to have to relent and actually write an article one of these days...problem for me is structuring the thing so it's readable to non-obsessive humans...
© 2025 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.