/// <summary> /// Rotates or initializes the crypto keys for this <see cref="ClientConnection"/>. /// </summary> public bool RotateCipherKeys() { // Make sure at least a second has passed before next key rotation if ((DateTime.UtcNow.Ticks - m_lastCipherKeyUpdateTime).ToMilliseconds() >= 1000.0D) { try { // Since this function cannot be not called more than once per second there // is no real benefit to maintaining these memory streams at a member level using (BlockAllocatedMemoryStream response = new BlockAllocatedMemoryStream()) { byte[] bytes, bufferLen; // Create or update cipher keys and initialization vectors UpdateKeyIVs(); // Add current cipher index to response response.WriteByte((byte)m_cipherIndex); // Serialize new keys using (BlockAllocatedMemoryStream buffer = new BlockAllocatedMemoryStream()) { // Write even key bufferLen = BigEndian.GetBytes(m_keyIVs[EvenKey][KeyIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[EvenKey][KeyIndex], 0, m_keyIVs[EvenKey][KeyIndex].Length); // Write even initialization vector bufferLen = BigEndian.GetBytes(m_keyIVs[EvenKey][IVIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[EvenKey][IVIndex], 0, m_keyIVs[EvenKey][IVIndex].Length); // Write odd key bufferLen = BigEndian.GetBytes(m_keyIVs[OddKey][KeyIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[OddKey][KeyIndex], 0, m_keyIVs[OddKey][KeyIndex].Length); // Write odd initialization vector bufferLen = BigEndian.GetBytes(m_keyIVs[OddKey][IVIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[OddKey][IVIndex], 0, m_keyIVs[OddKey][IVIndex].Length); // Get bytes from serialized buffer bytes = buffer.ToArray(); } // Encrypt keys using private keys known only to current client and server if (m_authenticated && !string.IsNullOrWhiteSpace(m_sharedSecret)) { bytes = bytes.Encrypt(m_sharedSecret, CipherStrength.Aes256); } // Add serialized key response response.Write(bytes, 0, bytes.Length); // Send cipher key updates m_parent.SendClientResponse(m_clientID, ServerResponse.UpdateCipherKeys, ServerCommand.Subscribe, response.ToArray()); } // Send success message m_parent.SendClientResponse(m_clientID, ServerResponse.Succeeded, ServerCommand.RotateCipherKeys, "New cipher keys established."); m_parent.OnStatusMessage(MessageLevel.Info, $"{ConnectionID} cipher keys rotated."); return(true); } catch (Exception ex) { // Send failure message m_parent.SendClientResponse(m_clientID, ServerResponse.Failed, ServerCommand.RotateCipherKeys, "Failed to establish new cipher keys: " + ex.Message); m_parent.OnStatusMessage(MessageLevel.Warning, $"Failed to establish new cipher keys for {ConnectionID}: {ex.Message}"); return(false); } } m_parent.SendClientResponse(m_clientID, ServerResponse.Failed, ServerCommand.RotateCipherKeys, "Cipher key rotation skipped, keys were already rotated within last second."); m_parent.OnStatusMessage(MessageLevel.Warning, $"Cipher key rotation skipped for {ConnectionID}, keys were already rotated within last second."); return(false); }
/// <summary> /// Rotates or initializes the crypto keys for this <see cref="ClientConnection"/>. /// </summary> public bool RotateCipherKeys() { // Make sure at least a second has passed before next key rotation if ((DateTime.UtcNow.Ticks - m_lastCipherKeyUpdateTime).ToMilliseconds() >= 1000.0D) { try { MemoryStream response = new MemoryStream(); // Create or update cipher keys and initialization vectors UpdateKeyIVs(); // Add current cipher index to response response.WriteByte((byte)m_cipherIndex); // Serialize new keys MemoryStream buffer = new MemoryStream(); byte[] bytes, bufferLen; // Write even key bufferLen = EndianOrder.BigEndian.GetBytes(m_keyIVs[EvenKey][KeyIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[EvenKey][KeyIndex], 0, m_keyIVs[EvenKey][KeyIndex].Length); // Write even initialization vector bufferLen = EndianOrder.BigEndian.GetBytes(m_keyIVs[EvenKey][IVIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[EvenKey][IVIndex], 0, m_keyIVs[EvenKey][IVIndex].Length); // Write odd key bufferLen = EndianOrder.BigEndian.GetBytes(m_keyIVs[OddKey][KeyIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[OddKey][KeyIndex], 0, m_keyIVs[OddKey][KeyIndex].Length); // Write odd initialization vector bufferLen = EndianOrder.BigEndian.GetBytes(m_keyIVs[OddKey][IVIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[OddKey][IVIndex], 0, m_keyIVs[OddKey][IVIndex].Length); // Get bytes from serialized buffer bytes = buffer.ToArray(); // // Encrypt keys using private keys known only to current client and server // if (m_authenticated && !m_sharedSecret.IsNullOrWhiteSpace()) // bytes = bytes.Encrypt(m_sharedSecret, CipherStrength.Aes256); // Add serialized key response response.Write(bytes, 0, bytes.Length); // Send cipher key updates m_parent.SendClientResponse(m_clientID, ServerResponse.UpdateCipherKeys, ServerCommand.Subscribe, response.ToArray()); // Send success message m_parent.SendClientResponse(m_clientID, ServerResponse.Succeeded, ServerCommand.RotateCipherKeys, "New cipher keys established."); m_parent.OnStatusMessage(ConnectionID + " cipher keys rotated."); return(true); } catch (Exception ex) { // Send failure message m_parent.SendClientResponse(m_clientID, ServerResponse.Failed, ServerCommand.RotateCipherKeys, "Failed to establish new cipher keys: " + ex.Message); m_parent.OnStatusMessage("Failed to establish new cipher keys for {0}: {1}", ConnectionID, ex.Message); return(false); } } m_parent.SendClientResponse(m_clientID, ServerResponse.Failed, ServerCommand.RotateCipherKeys, "Cipher key rotation skipped, keys were already rotated within last second."); m_parent.OnStatusMessage("WARNING: Cipher key rotation skipped for {0}, keys were already rotated within last second.", ConnectionID); return(false); }