/// <summary> /// Encodes <see cref="value"/> to the provided <see cref="stream"/>. /// </summary> /// <param name="stream">where to write the data</param> /// <param name="prevValue">the previous value if required by <see cref="UsesPreviousValue"/>. Otherwise null.</param> /// <param name="value">the value to encode</param> /// <returns>the number of bytes necessary to encode this key/value.</returns> public unsafe virtual int Encode(byte *stream, T prevValue, T value) { BinaryStreamPointerWrapper bs = new BinaryStreamPointerWrapper(stream, MaxCompressionSize); Encode(bs, prevValue, value); return((int)bs.Position); }
/// <summary> /// Decodes <see cref="value"/> from the provided <see cref="stream"/>. /// </summary> /// <param name="stream">where to read the data</param> /// <param name="prevValue">the previous value if required by <see cref="UsesPreviousValue"/>. Otherwise null.</param> /// <param name="value">the place to store the decoded value</param> /// <param name="isEndOfStream">outputs true if the end of the stream symbol is detected. Not all encoding methods have an end of stream symbol and therefore will always return false.</param> /// <returns>the number of bytes necessary to decode the next key/value.</returns> public unsafe virtual int Decode(byte *stream, T prevValue, T value, out bool isEndOfStream) { BinaryStreamPointerWrapper bs = new BinaryStreamPointerWrapper(stream, MaxCompressionSize); Decode(bs, prevValue, value, out isEndOfStream); return((int)bs.Position); }
public void Test7Bit4() { byte[] data = new byte[4096 * 5]; fixed(byte *lp = data) { using (BinaryStreamPointerWrapper bs = new BinaryStreamPointerWrapper(lp, data.Length)) { DebugStopwatch sw = new DebugStopwatch(); double time = sw.TimeEventMedian(() => { for (int repeat = 0; repeat < 1000; repeat++) { bs.Position = 0; for (int x = 0; x < 1000; x++) { bs.Write7Bit(128u * 128u * 128u); bs.Write7Bit(128u * 128u * 128u); bs.Write7Bit(128u * 128u * 128u); bs.Write7Bit(128u * 128u * 128u); } } }); Console.WriteLine(4 * 1000 * 1000 / time / 1000 / 1000); } } }
/// <summary> /// Encodes <see cref="key"/> and <see cref="value"/> to the provided <see cref="stream"/>. /// </summary> /// <param name="stream">where to write the data</param> /// <param name="prevKey">the previous key if required by <see cref="UsesPreviousKey"/>. Otherwise null.</param> /// <param name="prevValue">the previous value if required by <see cref="UsesPreviousValue"/>. Otherwise null.</param> /// <param name="key">the key to encode</param> /// <param name="value">the value to encode</param> /// <returns>the number of bytes necessary to encode this key/value.</returns> public unsafe virtual int Encode(byte *stream, TKey prevKey, TValue prevValue, TKey key, TValue value) { var bs = new BinaryStreamPointerWrapper(stream, MaxCompressionSize); Encode(bs, prevKey, prevValue, key, value); return((int)bs.Position); }
public void TestWriteLong() { byte[] data = new byte[4096 * 8]; fixed(byte *lp = data) { using (var bs = new BinaryStreamPointerWrapper(lp, data.Length)) { DebugStopwatch sw = new DebugStopwatch(); var time = sw.TimeEventMedian(() => { for (int repeat = 0; repeat < 1000; repeat++) { bs.Position = 0; for (int x = 0; x < 1000; x++) { bs.Write((long)x); bs.Write((long)x); bs.Write((long)x); bs.Write((long)x); } } }); Console.WriteLine((4 * 1000 * 1000) / time / 1000 / 1000); } } }
private unsafe void CreateResumeTicket(Guid userToken, out byte[] ticket, out byte[] sessionSecret) { #if SQLCLR ticket = null; sessionSecret = null; #else State state = m_state; //Ticket Structure: // byte TicketVersion = 1 // Guid ServerKeyName // DateTime AuthenticationTime // byte[16] IV // byte[] Encrypted Session Data 32+16 // byte[32] HMAC (Sha2-256) const int encryptedLength = 32 + 16; const int ticketSize = 1 + 16 + 8 + 16 + encryptedLength + 32; byte[] initializationVector = SaltGenerator.Create(16); sessionSecret = SaltGenerator.Create(32); byte[] userTokenBytes = userToken.ToRfcBytes(); byte[] dataToEncrypt = new byte[encryptedLength]; sessionSecret.CopyTo(dataToEncrypt, 0); userTokenBytes.CopyTo(dataToEncrypt, sessionSecret.Length); ticket = new byte[ticketSize]; using (Aes aes = Cipher.CreateAes()) { aes.Key = state.ServerEncryptionkey; aes.IV = initializationVector; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.None; ICryptoTransform decrypt = aes.CreateEncryptor(); byte[] encryptedData = decrypt.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length); fixed(byte *lp = ticket) { BinaryStreamPointerWrapper stream = new BinaryStreamPointerWrapper(lp, ticket.Length); stream.Write((byte)1); stream.Write(state.ServerKeyName); stream.Write(DateTime.UtcNow.RoundDownToNearestMinute()); stream.Write(initializationVector); stream.Write(encryptedData); //Encrypted data, 32 byte session key, n byte user token stream.Write(HMAC <Sha256Digest> .Compute(state.ServerHMACKey, ticket, 0, ticket.Length - 32)); } } #endif }
private static unsafe byte[] CreateSessionData(byte[] sessionSecret, SrpUserCredential user) { byte[] initializationVector = SaltGenerator.Create(16); int len = sessionSecret.Length; int blockLen = (len + 15) & ~15; //Add 15, then round down. (Effectively rounds up to the nearest 128 bit boundary). byte[] dataToEncrypt = new byte[blockLen]; sessionSecret.CopyTo(dataToEncrypt, 0); //fill the remainder of the block with random bits if (len != blockLen) { SaltGenerator.Create(blockLen - len).CopyTo(dataToEncrypt, len); } byte[] ticket = new byte[1 + 16 + 8 + 16 + 2 + blockLen + 32]; using (Aes aes = Cipher.CreateAes()) { aes.Key = user.ServerEncryptionkey; aes.IV = initializationVector; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.None; ICryptoTransform decrypt = aes.CreateEncryptor(); byte[] encryptedData = decrypt.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length); fixed(byte *lp = ticket) { using (BinaryStreamPointerWrapper stream = new BinaryStreamPointerWrapper(lp, ticket.Length)) { stream.Write((byte)1); stream.Write((short)len); stream.Write(user.ServerKeyName); stream.Write(DateTime.UtcNow); stream.Write(initializationVector); stream.Write(encryptedData); stream.Write(HMAC <Sha256Digest> .Compute(user.ServerHMACKey, ticket, 0, ticket.Length - 32)); } } } return(ticket); }
/// <summary> /// Attempts to load the session resume ticket. /// </summary> /// <param name="ticket">The serialized data for the key</param> /// <param name="user">The user's credentials so the proper encryption key can be used</param> /// <param name="sessionSecret">the session secret decoded if successful. null otherwise</param> /// <returns> /// True if the ticket is authentic /// </returns> unsafe static bool TryLoadTicket(byte[] ticket, SrpUserCredential user, out byte[] sessionSecret) { sessionSecret = null; //Ticket Structure: // byte TicketVersion = 1 // int16 Username Length // int16 Session Key Length // Guid ServerKeyName // DateTime AuthenticationTime // byte[16] IV // byte[] Username // byte[] Encrypted Session Data (Round [Session Key Length] up to a 128 bit number to get the length of the encrypted data) // byte[32] HMAC (Sha2-256) if (ticket == null || ticket.Length < 1 + 16 + 8 + 16 + 2 + 32) return(false); fixed(byte *lp = ticket) { var stream = new BinaryStreamPointerWrapper(lp, ticket.Length); if (stream.ReadUInt8() != 1) { return(false); } int sessionKeyLength = stream.ReadUInt16(); if (sessionKeyLength < 0 || sessionKeyLength > 1024) //Max session key is 8192 SRP. { return(false); } int encryptedDataLength = (sessionKeyLength + 15) & ~15; //Add 15, then round down. (Effecitvely rounds up to the nearest 128 bit boundary). if (ticket.Length != 1 + 2 + 16 + 8 + 16 + encryptedDataLength + 32) { return(false); } if (!user.ServerKeyName.SecureEquals(stream.ReadGuid())) { return(false); } long maxTicketAge = DateTime.UtcNow.Ticks + TimeSpan.TicksPerMinute * 10; //Allows for time syncing issues that might move the server's time back by a few minutes. long minTicketAge = maxTicketAge - TimeSpan.TicksPerDay; long issueTime = stream.ReadInt64(); if (issueTime < minTicketAge || issueTime > maxTicketAge) { return(false); } byte[] initializationVector = stream.ReadBytes(16); //Verify the signature if everything else looks good. //This is last because it is the most computationally complex. //This limits denial of service attackes. byte[] hmac = HMAC <Sha256Digest> .Compute(user.ServerHMACKey, ticket, 0, ticket.Length - 32); if (!hmac.SecureEquals(ticket, ticket.Length - 32, 32)) { return(false); } byte[] encryptedData = stream.ReadBytes(encryptedDataLength); var aes = new RijndaelManaged(); aes.Key = user.ServerEncryptionkey; aes.IV = initializationVector; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.None; var decrypt = aes.CreateDecryptor(); sessionSecret = decrypt.TransformFinalBlock(encryptedData, 0, encryptedData.Length); return(true); } }
/// <summary> /// Writes the key to the stream /// </summary> /// <param name="stream"></param> public virtual unsafe void Write(byte *stream) { var writer = new BinaryStreamPointerWrapper(stream, Size); Write(writer); }
/// <summary> /// Reads the key from the stream /// </summary> /// <param name="stream"></param> public virtual unsafe void Read(byte *stream) { var reader = new BinaryStreamPointerWrapper(stream, Size); Read(reader); }
private unsafe bool TryLoadTicket(byte[] ticket, out byte[] sessionSecret, out Guid userToken) { #if SQLCLR sessionSecret = null; userToken = Guid.Empty; return(false); #else State state = m_state; const int encryptedLength = 32 + 16; const int ticketSize = 1 + 16 + 8 + 16 + encryptedLength + 32; userToken = default(Guid); sessionSecret = null; //Ticket Structure: // byte TicketVersion = 1 // Guid ServerKeyName // DateTime AuthenticationTime // byte[16] IV // byte[] Encrypted Session Data 32+16 // byte[32] HMAC (Sha2-256) if (ticket == null || ticket.Length != ticketSize) return(false); fixed(byte *lp = ticket) { var stream = new BinaryStreamPointerWrapper(lp, ticket.Length); if (stream.ReadUInt8() != 1) { return(false); } if (!state.ServerKeyName.SecureEquals(stream.ReadGuid())) { return(false); } long currentTime = DateTime.UtcNow.Ticks; long issueTime = stream.ReadInt64(); if (issueTime <= currentTime) { //Issue time is before current time. if (currentTime - issueTime > TimeSpan.TicksPerMinute * TicketExpireTimeMinutes) { return(false); } } else { //For some reason, the issue time is after the current time. //This could be due to a clock sync on the server after the ticket was issued. //Allow up to 1 minute of clock skew if (issueTime - currentTime > TimeSpan.TicksPerMinute) { return(false); } } byte[] initializationVector = stream.ReadBytes(16); //Verify the signature if everything else looks good. //This is last because it is the most computationally complex. //This limits denial of service attackes. byte[] hmac = HMAC <Sha256Digest> .Compute(state.ServerHMACKey, ticket, 0, ticket.Length - 32); if (!hmac.SecureEquals(ticket, ticket.Length - 32, 32)) { return(false); } byte[] encryptedData = stream.ReadBytes(encryptedLength); var aes = new RijndaelManaged(); aes.Key = state.ServerEncryptionkey; aes.IV = initializationVector; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.None; var decrypt = aes.CreateDecryptor(); encryptedData = decrypt.TransformFinalBlock(encryptedData, 0, encryptedData.Length); sessionSecret = new byte[32]; Array.Copy(encryptedData, 0, sessionSecret, 0, 32); userToken = encryptedData.ToRfcGuid(32); return(true); } #endif }