private void HandleSpecificPacket(KexDHInit packet) { m_Logger.LogDebug("Received KexDHInit"); if ((m_PendingExchangeContext == null) || (m_PendingExchangeContext.KexAlgorithm == null)) { throw new SSHServerException(DisconnectReason.SSH_DISCONNECT_PROTOCOL_ERROR, "Server did not receive SSH_MSG_KEX_INIT as expected."); } // 1. C generates a random number x (1 < x < q) and computes e = g ^ x mod p. C sends e to S. // 2. S receives e. It computes K = e^y mod p byte[] sharedSecret = m_PendingExchangeContext.KexAlgorithm.DecryptKeyExchange(packet.ClientValue); // 2. S generates a random number y (0 < y < q) and computes f = g ^ y mod p. byte[] serverKeyExchange = m_PendingExchangeContext.KexAlgorithm.CreateKeyExchange(); byte[] hostKey = m_PendingExchangeContext.HostKeyAlgorithm.CreateKeyAndCertificatesData(); // H = hash(V_C || V_S || I_C || I_S || K_S || e || f || K) byte[] exchangeHash = ComputeExchangeHash( m_PendingExchangeContext.KexAlgorithm, hostKey, packet.ClientValue, serverKeyExchange, sharedSecret); if (m_SessionId == null) { m_SessionId = exchangeHash; } // https://tools.ietf.org/html/rfc4253#section-7.2 // Initial IV client to server: HASH(K || H || "A" || session_id) // (Here K is encoded as mpint and "A" as byte and session_id as raw // data. "A" means the single character A, ASCII 65). byte[] clientCipherIV = ComputeEncryptionKey( m_PendingExchangeContext.KexAlgorithm, exchangeHash, m_PendingExchangeContext.CipherClientToServer.BlockSize, sharedSecret, 'A'); // Initial IV server to client: HASH(K || H || "B" || session_id) byte[] serverCipherIV = ComputeEncryptionKey( m_PendingExchangeContext.KexAlgorithm, exchangeHash, m_PendingExchangeContext.CipherServerToClient.BlockSize, sharedSecret, 'B'); // Encryption key client to server: HASH(K || H || "C" || session_id) byte[] clientCipherKey = ComputeEncryptionKey( m_PendingExchangeContext.KexAlgorithm, exchangeHash, m_PendingExchangeContext.CipherClientToServer.KeySize, sharedSecret, 'C'); // Encryption key server to client: HASH(K || H || "D" || session_id) byte[] serverCipherKey = ComputeEncryptionKey( m_PendingExchangeContext.KexAlgorithm, exchangeHash, m_PendingExchangeContext.CipherServerToClient.KeySize, sharedSecret, 'D'); // Integrity key client to server: HASH(K || H || "E" || session_id) byte[] clientHmacKey = ComputeEncryptionKey( m_PendingExchangeContext.KexAlgorithm, exchangeHash, m_PendingExchangeContext.MACAlgorithmClientToServer.KeySize, sharedSecret, 'E'); // Integrity key server to client: HASH(K || H || "F" || session_id) byte[] serverHmacKey = ComputeEncryptionKey( m_PendingExchangeContext.KexAlgorithm, exchangeHash, m_PendingExchangeContext.MACAlgorithmServerToClient.KeySize, sharedSecret, 'F'); // Set all keys we just generated m_PendingExchangeContext.CipherClientToServer.SetKey(clientCipherKey, clientCipherIV); m_PendingExchangeContext.CipherServerToClient.SetKey(serverCipherKey, serverCipherIV); m_PendingExchangeContext.MACAlgorithmClientToServer.SetKey(clientHmacKey); m_PendingExchangeContext.MACAlgorithmServerToClient.SetKey(serverHmacKey); // Send reply to client! KexDHReply reply = new KexDHReply() { ServerHostKey = hostKey, ServerValue = serverKeyExchange, Signature = m_PendingExchangeContext.HostKeyAlgorithm.CreateSignatureData(exchangeHash) }; Send(reply); Send(new NewKeys()); }
private void HandleSpecificPacket(KexDHInit packet) { logger.LogDebug("Processing KexDHInit packet."); if ((pendingExchangeContext == null) || (pendingExchangeContext.KexAlgorithm == null)) { throw new SwishServerException(DisconnectReason.SSH_DISCONNECT_PROTOCOL_ERROR, "Server did not receive SSH_MSG_KEX_INIT as expected."); } // Set the host key // TODO - better handling of missing config var hostKeyAlgoName = pendingExchangeContext.HostKeyAlgorithm.Name; if (!settings.HostKeyPaths.ContainsKey(hostKeyAlgoName)) { throw new Exception(string.Format("HostKey path for algo '{0}' not found in configuration.", hostKeyAlgoName)); } pendingExchangeContext.HostKeyAlgorithm.ImportKeyFromFile(settings.HostKeyPaths[hostKeyAlgoName]); // 1. C generates a random number x (1 < x < q) and computes e = g ^ x mod p. C sends e to S. // 2. S receives e. It computes K = e^y mod p byte[] sharedSecret = pendingExchangeContext.KexAlgorithm.DecryptKeyExchange(packet.ClientValue); // 2. S generates a random number y (0 < y < q) and computes f = g ^ y mod p. byte[] serverKeyExchange = pendingExchangeContext.KexAlgorithm.CreateKeyExchange(); byte[] hostKey = pendingExchangeContext.HostKeyAlgorithm.CreateKeyAndCertificatesData(); // H = hash(V_C || V_S || I_C || I_S || K_S || e || f || K) byte[] exchangeHash = ComputeExchangeHash( pendingExchangeContext.KexAlgorithm, hostKey, packet.ClientValue, serverKeyExchange, sharedSecret); if (sessionId == null) { sessionId = exchangeHash; } // https://tools.ietf.org/html/rfc4253#section-7.2 // Initial IV client to server: HASH(K || H || "A" || session_id) // (Here K is encoded as mpint and "A" as byte and session_id as raw // data. "A" means the single character A, ASCII 65). byte[] clientCipherIV = ComputeEncryptionKey( pendingExchangeContext.KexAlgorithm, exchangeHash, pendingExchangeContext.CipherClientToServer.BlockSize, sharedSecret, 'A'); // Initial IV server to client: HASH(K || H || "B" || session_id) byte[] serverCipherIV = ComputeEncryptionKey( pendingExchangeContext.KexAlgorithm, exchangeHash, pendingExchangeContext.CipherServerToClient.BlockSize, sharedSecret, 'B'); // Encryption key client to server: HASH(K || H || "C" || session_id) byte[] clientCipherKey = ComputeEncryptionKey( pendingExchangeContext.KexAlgorithm, exchangeHash, pendingExchangeContext.CipherClientToServer.KeySize, sharedSecret, 'C'); // Encryption key server to client: HASH(K || H || "D" || session_id) byte[] serverCipherKey = ComputeEncryptionKey( pendingExchangeContext.KexAlgorithm, exchangeHash, pendingExchangeContext.CipherServerToClient.KeySize, sharedSecret, 'D'); // Integrity key client to server: HASH(K || H || "E" || session_id) byte[] clientHmacKey = ComputeEncryptionKey( pendingExchangeContext.KexAlgorithm, exchangeHash, pendingExchangeContext.MACAlgorithmClientToServer.KeySize, sharedSecret, 'E'); // Integrity key server to client: HASH(K || H || "F" || session_id) byte[] serverHmacKey = ComputeEncryptionKey( pendingExchangeContext.KexAlgorithm, exchangeHash, pendingExchangeContext.MACAlgorithmServerToClient.KeySize, sharedSecret, 'F'); // Set all keys we just generated pendingExchangeContext.CipherClientToServer.SetKey(clientCipherKey, clientCipherIV); pendingExchangeContext.CipherServerToClient.SetKey(serverCipherKey, serverCipherIV); pendingExchangeContext.MACAlgorithmClientToServer.SetKey(clientHmacKey); pendingExchangeContext.MACAlgorithmServerToClient.SetKey(serverHmacKey); // Send reply to client! var reply = new KexDHReply { ServerHostKey = hostKey, ServerValue = serverKeyExchange, Signature = pendingExchangeContext.HostKeyAlgorithm.CreateSignatureData(exchangeHash) }; Send(reply); Send(new NewKeys()); }