/// <summary> /// This will change the encryption keys used to create resume tickets, thus /// invalidating all existing tickets. /// </summary> public void InvalidateAllTickets() { lock (m_syncRoot) { var state = m_state.Clone(); state.ServerKeyName = Guid.NewGuid(); state.ServerHMACKey = SaltGenerator.Create(32); state.ServerEncryptionkey = SaltGenerator.Create(32); m_state = state; } }
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 bool TryResumeSession(Stream stream, byte[] certSignatures, out Guid userToken) { #if SQLCLR userToken = Guid.Empty; return(false); #else //Resume Session: // C => S // byte ResumeSession // byte TicketLength // byte[] Ticket // byte ClientChallengeLength // byte[] ClientChallenge // S <= C // byte HashMethod // byte ServerChallengeLength // byte[] ServerChallenge IDigest hash = new Sha384Digest(); byte[] serverChallenge = SaltGenerator.Create(16); stream.WriteByte((byte)HashMethod.Sha384); stream.WriteByte((byte)serverChallenge.Length); stream.Write(serverChallenge); stream.Flush(); // C => S // byte ClientResponseLength // byte[] ClientChallenge byte[] ticket = stream.ReadBytes(stream.ReadNextByte()); byte[] clientChallenge = stream.ReadBytes(stream.ReadNextByte()); byte[] clientResponse = stream.ReadBytes(stream.ReadByte()); // S => C // bool IsSuccessful // byte ServerResponseLength // byte[] ServerResponse if (TryLoadTicket(ticket, out byte[] secret, out userToken))
private bool TryResumeSession(ref Stream secureStream, Stream stream2, byte[] certSignatures) { #if SQLCLR return(false); #else if (m_resumeTicket != null && m_sessionSecret != null) { //Resume Session: // C => S // byte ResumeSession // byte TicketLength // byte[] Ticket // byte ClientChallengeLength // byte[] ClientChallenge byte[] clientChallenge = SaltGenerator.Create(16); stream2.WriteByte((byte)AuthenticationMode.ResumeSession); stream2.WriteByte((byte)m_resumeTicket.Length); stream2.Write(m_resumeTicket); stream2.WriteByte((byte)clientChallenge.Length); stream2.Write(clientChallenge); stream2.Flush(); // S <= C // byte HashMethod // byte ServerChallengeLength // byte[] ServerChallenge HashMethod hashMethod = (HashMethod)stream2.ReadNextByte(); IDigest hash = Scram.CreateDigest(hashMethod); byte[] serverChallenge = stream2.ReadBytes(stream2.ReadNextByte()); // C => S // byte ClientResponseLength // byte[] ClientChallenge byte[] clientResponse = hash.ComputeHash(serverChallenge, clientChallenge, m_sessionSecret, certSignatures); byte[] serverResponse = hash.ComputeHash(clientChallenge, serverChallenge, m_sessionSecret, certSignatures); stream2.WriteByte((byte)clientResponse.Length); stream2.Write(clientResponse); stream2.Flush(); // S => C // bool IsSuccessful // byte ServerResponseLength // byte[] ServerResponse if (stream2.ReadBoolean()) { byte[] serverResponseCheck = stream2.ReadBytes(stream2.ReadNextByte()); // C => S // bool IsSuccessful if (serverResponse.SecureEquals(serverResponseCheck)) { stream2.Write(true); stream2.Flush(); secureStream = stream2; return(true); } stream2.Write(false); stream2.Flush(); } m_resumeTicket = null; m_sessionSecret = null; } return(false); #endif }
private bool TryResumeSession(Stream stream, byte[] certSignatures, out Guid userToken) { #if SQLCLR userToken = Guid.Empty; return(false); #else //Resume Session: // C => S // byte ResumeSession // byte TicketLength // byte[] Ticket // byte ClientChallengeLength // byte[] ClientChallenge // S <= C // byte HashMethod // byte ServerChallengeLength // byte[] ServerChallenge IDigest hash = new Sha384Digest(); byte[] serverChallenge = SaltGenerator.Create(16); stream.WriteByte((byte)HashMethod.Sha384); stream.WriteByte((byte)serverChallenge.Length); stream.Write(serverChallenge); stream.Flush(); // C => S // byte ClientResponseLength // byte[] ClientChallenge byte[] ticket = stream.ReadBytes(stream.ReadNextByte()); byte[] clientChallenge = stream.ReadBytes(stream.ReadNextByte()); byte[] clientResponse = stream.ReadBytes(stream.ReadByte()); byte[] secret; // S => C // bool IsSuccessful // byte ServerResponseLength // byte[] ServerResponse if (TryLoadTicket(ticket, out secret, out userToken)) { byte[] clientResponseCheck = hash.ComputeHash(serverChallenge, clientChallenge, secret, certSignatures); if (clientResponse.SecureEquals(clientResponseCheck)) { byte[] serverResponse = hash.ComputeHash(clientChallenge, serverChallenge, secret, certSignatures); stream.Write(true); stream.WriteByte((byte)serverResponse.Length); stream.Write(serverResponse); stream.Flush(); if (stream.ReadBoolean()) { return(true); } return(false); } } stream.Write(false); userToken = default(Guid); return(false); #endif }