Create a gist now

Instantly share code, notes, and snippets.

Demonstrates how to decode an .ASPXAUTH cookie as generated by the current version of Microsoft's implementation of .NET. You should be able to drop this into the `Global.asax.cs` file of an ASP.NET project and be able to share cookies with code running on Mono. A few notes: (1) This assumes a machine key section that uses SHA1 validation and AE…
public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs args)
{
var machineKeySection = (MachineKeySection) WebConfigurationManager.GetWebApplicationSection("system.web/machineKey");
var cookie = args.Context.Request.Cookies[".ASPXAUTH"];
if (cookie == null || !Regex.IsMatch(cookie.Value, "^([a-fA-F0-9]{2})+$"))
return;
var cookieBytes = ByteUtility.ToBytes(cookie.Value);
int signatureLength;
bool isValid = true;
using (var validationAlgorithm = new HMACSHA1(ByteUtility.ToBytes(machineKeySection.ValidationKey)))
{
signatureLength = validationAlgorithm.HashSize >> 3;
if (cookieBytes.Length - 1 < signatureLength)
return;
var signature = validationAlgorithm.ComputeHash(cookieBytes, 0, cookieBytes.Length - signatureLength);
for (int signatureIndex = 0; signatureIndex < signature.Length; signatureIndex++)
{
// If we break early, we'll be more vulnerable to timing attacks.
if (signature[signatureIndex] != cookieBytes[cookieBytes.Length - signatureLength + signatureIndex])
isValid = false;
}
}
byte[] decryptedBytes;
int initializationVectorLength;
using (var decryptionAlgorithm = Rijndael.Create())
{
initializationVectorLength = decryptionAlgorithm.IV.Length;
decryptionAlgorithm.Key = ByteUtility.ToBytes(machineKeySection.DecryptionKey);
using (var decryptor = decryptionAlgorithm.CreateDecryptor())
decryptedBytes = decryptor.TransformFinalBlock(cookieBytes, 0, cookieBytes.Length - signatureLength);
if (!isValid)
decryptedBytes = null;
}
if (decryptedBytes == null || decryptedBytes.Length < 51 + initializationVectorLength)
return;
FormsAuthenticationTicket ticket;
using (var stream = new MemoryStream(decryptedBytes, 8 + initializationVectorLength, decryptedBytes.Length - 28 - initializationVectorLength, false))
using (var reader = new BinaryReader(stream, Encoding.Unicode))
{
if (reader.ReadByte() != 0x01)
return;
int version = (int) reader.ReadByte();
var issueDate = new DateTime(reader.ReadInt64(), DateTimeKind.Utc);
if (reader.ReadByte() != 0xFE)
return;
var expirationDate = new DateTime(reader.ReadInt64(), DateTimeKind.Utc);
bool isPersistent = reader.ReadBoolean();
string name = ReadFormsAuthenticationTicketString(reader);
string userData = ReadFormsAuthenticationTicketString(reader);
string path = ReadFormsAuthenticationTicketString(reader);
if (reader.ReadByte() != 0xFF)
return;
ticket = new FormsAuthenticationTicket(version, name, issueDate, expirationDate, isPersistent, userData, path);
}
args.User = new GenericPrincipal(new FormsIdentity(ticket), new string[] { });
}
private static string ReadFormsAuthenticationTicketString(BinaryReader reader)
{
int stringLength = 0;
byte lengthByte;
int iterations = 0;
do
{
lengthByte = reader.ReadByte();
stringLength |= (lengthByte & 0x7F) << (iterations * 7);
iterations++;
} while ((lengthByte & (byte) 0x80) != 0);
return new string(reader.ReadChars(stringLength));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment