public void sendKexInit() throws KexException {
// Check if already in middle of a kex
if( _inKeyExchange.getAndSet(true) ) { // Flip state flag entering kex
return; // Return if already in process of kex
}
Buffer kexBuffer = new Buffer(); // Use a separate packet and buffer since
Packet kexPacket = new Packet(kexBuffer); // kex may be invoked by user thread
try {
// Random instance for generating the kex cookie. The 'cookie' MUST
// be a random value generated by the sender. Its purpose is to make
// it impossible for either side to fully determine the keys and the
// session identifier.
final Random random = AlgorithmManager.getManager().createAlgorithm(Algorithms.RANDOM, _session);
// Construct the KEX INIT message packet
// byte SSH_MSG_KEXINIT(20)
// byte[16] cookie (random bytes)
// string kex_algorithms
// string server_host_key_algorithms
// string encryption_algorithms_client_to_server
// string encryption_algorithms_server_to_client
// string mac_algorithms_client_to_server
// string mac_algorithms_server_to_client
// string compression_algorithms_client_to_server
// string compression_algorithms_server_to_client
// string languages_client_to_server
// string languages_server_to_client
// byte boolean first_kex_packet_follows
// uint32 0 (reserved for future extension)
kexPacket.reset();
kexBuffer.putByte(SSH_MSG_KEXINIT);
random.fill(kexBuffer.getArray(), kexBuffer.getIndex(), KEX_COOKIE_LENGTH);
kexBuffer.skip(KEX_COOKIE_LENGTH); // Move index forward
kexBuffer.putString(_session.getConfig().getString(SessionConfig.KEX_ALGORITHMS));
kexBuffer.putString(_session.getConfig().getString(SessionConfig.KEX_SERVER_HOST_KEY));
kexBuffer.putString(_session.getConfig().getCiphersC2S()); // Checked list of client-to-server ciphers
kexBuffer.putString(_session.getConfig().getCiphersS2C()); // Checked list of server-to-client ciphers
kexBuffer.putString(_session.getConfig().getString(SessionConfig.KEX_MAC_C2S));
kexBuffer.putString(_session.getConfig().getString(SessionConfig.KEX_MAC_S2C));
kexBuffer.putString(_session.getConfig().getString(SessionConfig.KEX_COMPRESSION_C2S));
kexBuffer.putString(_session.getConfig().getString(SessionConfig.KEX_COMPRESSION_S2C));
kexBuffer.putString(_session.getConfig().getString(SessionConfig.KEX_LANG_C2S));
kexBuffer.putString(_session.getConfig().getString(SessionConfig.KEX_LANG_S2C));
kexBuffer.putByte((byte) 0); // 0 is false, not sending guessed packet
kexBuffer.putInt(0);
// Set the client's kex algorithm initialization message
I_C = new byte[kexBuffer.getIndex()-5];
System.arraycopy(kexBuffer.getArray(), 5, I_C, 0, I_C.length);
_session.write(kexPacket); // Send key exchange init message to server
JSch.getLogger().log(Logger.Level.INFO, "SSH_MSG_KEXINIT sent");
} catch(Exception e) {
throw new KexException("Failed to send SSH_MSG_KEXINIT", e);
} finally {
kexBuffer.clear(); // Clear buffer to ensure sensitive data is wiped
}
}