File openssh-8.3p1-obfuscated.patch of Package openssh

diff -Nurp openssh-8.3p1/kex.c openssh-8.3p1-ob/kex.c
--- openssh-8.3p1/kex.c	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/kex.c	2020-05-28 11:38:51.097260934 +0800
@@ -58,6 +58,7 @@
 #include "monitor.h"
 #include "xmalloc.h"
 
+#include "obfuscate.h"
 #include "ssherr.h"
 #include "sshbuf.h"
 #include "digest.h"
@@ -460,9 +461,12 @@ kex_send_newkeys(struct ssh *ssh)
 		return r;
 	debug("SSH2_MSG_NEWKEYS sent");
 	ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys);
-	if (ssh->kex->ext_info_c && (ssh->kex->flags & KEX_INITIAL) != 0)
+	if (ssh->kex->ext_info_c && (ssh->kex->flags & KEX_INITIAL) != 0) {
+		sshpkt_disable_obfuscation(ssh);
 		if ((r = kex_send_ext_info(ssh)) != 0)
 			return r;
+		sshpkt_enable_obfuscation(ssh);
+	}
 	debug("expecting SSH2_MSG_NEWKEYS");
 	return 0;
 }
@@ -525,6 +529,7 @@ kex_input_newkeys(int type, u_int32_t se
 	kex->flags &= ~KEX_INIT_SENT;
 	free(kex->name);
 	kex->name = NULL;
+	sshpkt_disable_obfuscation(ssh);
 	return 0;
 }
 
@@ -1191,14 +1196,42 @@ kex_exchange_identification(struct ssh *
 		goto out;
 	}
 
+	/* Make copy and obfuscate the original */
+	if (sshpkt_get_obfuscation(ssh) == 1) {
+		if ((cp = sshbuf_dup_string(our_version)) == NULL) {
+			error("%s: sshbuf_dup_string failed for obfuscation", __func__);
+			r = SSH_ERR_ALLOC_FAIL;
+			goto out;
+		}
+		obfuscate_output(sshbuf_mutable_ptr(our_version), sshbuf_len(our_version));
+	}
+
 	if (atomicio(vwrite, ssh_packet_get_connection_out(ssh),
 	    sshbuf_mutable_ptr(our_version),
 	    sshbuf_len(our_version)) != sshbuf_len(our_version)) {
 		oerrno = errno;
 		debug("%s: write: %.100s", __func__, strerror(errno));
 		r = SSH_ERR_SYSTEM_ERROR;
+		if (sshpkt_get_obfuscation(ssh) == 1) {
+			free(cp);
+		}
 		goto out;
 	}
+
+	/* Restore the original */
+	if (sshpkt_get_obfuscation(ssh) == 1) {
+		if ((r = sshbuf_consume(our_version, sshbuf_len(our_version))) != 0) {
+			error("%s: sshbuf_consume failed for obfuscation", __func__);
+			free(cp);
+			goto out;
+		}
+		if ((r = sshbuf_put(our_version, cp, strlen(cp))) != 0) {
+			error("%s: sshbuf_put failed for obfuscation", __func__);
+			free(cp);
+			goto out;
+		}
+	}
+
 	if ((r = sshbuf_consume_end(our_version, 2)) != 0) { /* trim \r\n */
 		oerrno = errno;
 		error("%s: sshbuf_consume_end: %s", __func__, ssh_err(r));
@@ -1258,6 +1291,8 @@ kex_exchange_identification(struct ssh *
 				r = SSH_ERR_SYSTEM_ERROR;
 				goto out;
 			}
+			if(sshpkt_get_obfuscation(ssh) == 1)
+			  obfuscate_input(&c, 1);
 			if (c == '\r') {
 				expect_nl = 1;
 				continue;
diff -Nurp openssh-8.3p1/Makefile.in openssh-8.3p1-ob/Makefile.in
--- openssh-8.3p1/Makefile.in	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/Makefile.in	2020-05-28 11:24:13.083779498 +0800
@@ -110,7 +110,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
 	sntrup4591761.o kexsntrup4591761x25519.o kexgen.o \
 	kexgssc.o \
 	sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \
-	sshbuf-io.o auditstub.o
+	sshbuf-io.o auditstub.o obfuscate.o
 
 SKOBJS=	ssh-sk-client.o
 
diff -Nurp openssh-8.3p1/obfuscate.c openssh-8.3p1-ob/obfuscate.c
--- openssh-8.3p1/obfuscate.c	1970-01-01 08:00:00.000000000 +0800
+++ openssh-8.3p1-ob/obfuscate.c	2020-05-28 11:24:13.083779498 +0800
@@ -0,0 +1,220 @@
+#include "includes.h"
+#include <openssl/evp.h>
+#include <openssl/rc4.h>
+#include "openbsd-compat/openssl-compat.h"
+#include <unistd.h>
+#include <string.h>
+#include "atomicio.h"
+#include "canohost.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "packet.h"
+#include "obfuscate.h"
+
+static RC4_KEY rc4_input;
+static RC4_KEY rc4_output;
+
+static const char *obfuscate_keyword = NULL;
+
+#define OBFUSCATE_KEY_LENGTH 	16
+#define OBFUSCATE_SEED_LENGTH	16
+#define OBFUSCATE_HASH_ITERATIONS 6000
+#define OBFUSCATE_MAX_PADDING	8192
+#define OBFUSCATE_MAGIC_VALUE	0x0BF5CA7E
+
+struct seed_msg {
+	u_char seed_buffer[OBFUSCATE_SEED_LENGTH];
+	u_int32_t magic;
+	u_int32_t padding_length;
+	u_char padding[];
+};
+
+static void generate_key_pair(const u_char *, u_char *, u_char *);
+static void generate_key(const u_char *, const u_char *, u_int, u_char *);
+static void set_keys(const u_char *, const u_char *);
+static void initialize(const u_char *, int);
+static void read_forever(int);
+
+
+/*
+ * Server calls this
+ */
+void
+obfuscate_receive_seed(struct ssh *ssh, int sock_in)
+{
+	struct seed_msg seed;
+
+	u_char padding_drain[OBFUSCATE_MAX_PADDING];
+	u_int len;
+	u_int32_t padding_length;
+
+	len = atomicio(read, sock_in, &seed, sizeof(struct seed_msg));
+
+	debug2("obfuscate_receive_seed: read %d byte seed message from client", len);
+	if(len != sizeof(struct seed_msg))
+		fatal("obfuscate_receive_seed: read failed");
+
+	initialize(seed.seed_buffer, 1);
+	obfuscate_input((u_char *)&seed.magic, 8);
+
+	if(OBFUSCATE_MAGIC_VALUE != ntohl(seed.magic)) {
+		logit("Magic value check failed (%u) on obfuscated handshake "
+ 			"from %.200s port %d", ntohl(seed.magic),
+			ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
+		read_forever(sock_in);
+	}
+	padding_length = ntohl(seed.padding_length);
+	if(padding_length > OBFUSCATE_MAX_PADDING) {
+		logit("Illegal padding length %d for obfuscated handshake "
+ 			"from %.200s port %d", ntohl(seed.padding_length),
+			ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
+		read_forever(sock_in);
+	}
+	len = atomicio(read, sock_in, padding_drain, padding_length);
+	if(len != padding_length)
+		fatal("obfuscate_receive_seed: read failed");
+	debug2("obfuscate_receive_seed: read %d bytes of padding from client.", len);
+	obfuscate_input(padding_drain, padding_length);
+}
+
+/*
+ * Client calls this
+ */
+void
+obfuscate_send_seed(int sock_out)
+{
+	struct seed_msg *seed;
+	int i;
+	u_int32_t rnd = 0;
+	u_int message_length;
+	u_int padding_length;
+
+	padding_length = arc4random() % OBFUSCATE_MAX_PADDING;
+	message_length = padding_length + sizeof(struct seed_msg);
+	seed = xmalloc(message_length);
+
+	for(i = 0; i < OBFUSCATE_SEED_LENGTH; i++) {
+		if(i % 4 == 0)
+			rnd = arc4random();
+		seed->seed_buffer[i] = rnd & 0xff;
+		rnd >>= 8;
+	}
+	seed->magic = htonl(OBFUSCATE_MAGIC_VALUE);
+	seed->padding_length = htonl(padding_length);
+	for(i = 0; i < (int)padding_length; i++) {
+		if(i % 4 == 0)
+			rnd = arc4random();
+		seed->padding[i] = rnd & 0xff;
+	}
+	initialize(seed->seed_buffer, 0);
+	obfuscate_output(((u_char *)seed) + OBFUSCATE_SEED_LENGTH,
+		message_length - OBFUSCATE_SEED_LENGTH);
+	debug2("obfuscate_send_seed: Sending seed message with %d bytes of padding", padding_length);
+	atomicio(vwrite, sock_out, seed, message_length);
+	free(seed);
+
+}
+
+void
+obfuscate_set_keyword(const char *keyword)
+{
+	debug2("obfuscate_set_keyword: Setting obfuscation keyword to '%s'", keyword);
+	obfuscate_keyword = keyword;
+}
+
+void
+obfuscate_input(u_char *buffer, u_int buffer_len)
+{
+	RC4(&rc4_input, buffer_len, buffer, buffer);
+}
+
+void
+obfuscate_output(u_char *buffer, u_int buffer_len)
+{
+	RC4(&rc4_output, buffer_len, buffer, buffer);
+}
+
+static void
+initialize(const u_char *seed, int server)
+{
+	u_char client_to_server_key[OBFUSCATE_KEY_LENGTH];
+	u_char server_to_client_key[OBFUSCATE_KEY_LENGTH];
+
+	generate_key_pair(seed, client_to_server_key, server_to_client_key);
+
+	if(server)
+		set_keys(client_to_server_key, server_to_client_key);
+	else
+		set_keys(server_to_client_key, client_to_server_key);
+}
+
+static void
+generate_key_pair(const u_char *seed, u_char *client_to_server_key, u_char *server_to_client_key)
+{
+	generate_key(seed, "client_to_server", strlen("client_to_server"), client_to_server_key);
+	generate_key(seed, "server_to_client", strlen("server_to_client"), server_to_client_key);
+}
+
+static void
+generate_key(const u_char *seed, const u_char *iv, u_int iv_len, u_char *key_data)
+{
+	EVP_MD_CTX *ctx;
+	u_char md_output[EVP_MAX_MD_SIZE];
+	int md_len;
+	int i;
+	u_char *buffer;
+	u_char *p;
+	u_int buffer_length;
+
+	if ((ctx = EVP_MD_CTX_new()) == NULL)
+		fatal("Cannot create new digest context");
+
+	buffer_length = OBFUSCATE_SEED_LENGTH + iv_len;
+	if(obfuscate_keyword)
+		buffer_length += strlen(obfuscate_keyword);
+
+	p = buffer = xmalloc(buffer_length);
+
+	memcpy(p, seed, OBFUSCATE_SEED_LENGTH);
+	p += OBFUSCATE_SEED_LENGTH;
+
+	if(obfuscate_keyword) {
+		memcpy(p, obfuscate_keyword, strlen(obfuscate_keyword));
+		p += strlen(obfuscate_keyword);
+	}
+	memcpy(p, iv, iv_len);
+
+	EVP_DigestInit(ctx, EVP_sha1());
+	EVP_DigestUpdate(ctx, buffer, OBFUSCATE_SEED_LENGTH + iv_len);
+	EVP_DigestFinal(ctx, md_output, &md_len);
+
+	free(buffer);
+
+	for(i = 0; i < OBFUSCATE_HASH_ITERATIONS; i++) {
+		EVP_DigestInit(ctx, EVP_sha1());
+		EVP_DigestUpdate(ctx, md_output, md_len);
+		EVP_DigestFinal(ctx, md_output, &md_len);
+	}
+
+	if(md_len < OBFUSCATE_KEY_LENGTH)
+		fatal("Cannot derive obfuscation keys from hash length of %d", md_len);
+
+	memcpy(key_data, md_output, OBFUSCATE_KEY_LENGTH);
+}
+
+static void
+set_keys(const u_char *input_key, const u_char *output_key)
+{
+	RC4_set_key(&rc4_input, OBFUSCATE_KEY_LENGTH, input_key);
+	RC4_set_key(&rc4_output, OBFUSCATE_KEY_LENGTH, output_key);
+}
+
+static void
+read_forever(int sock_in)
+{
+	u_char discard_buffer[1024];
+
+	while(atomicio(read, sock_in, discard_buffer, sizeof(discard_buffer)) > 0)
+		;
+	cleanup_exit(255);
+}
diff -Nurp openssh-8.3p1/obfuscate.h openssh-8.3p1-ob/obfuscate.h
--- openssh-8.3p1/obfuscate.h	1970-01-01 08:00:00.000000000 +0800
+++ openssh-8.3p1-ob/obfuscate.h	2020-05-28 11:24:13.083779498 +0800
@@ -0,0 +1,10 @@
+#ifndef _OBFUSCATE_H
+#define _OBFUSCATE_H
+
+void obfuscate_receive_seed(struct ssh *, int);
+void obfuscate_send_seed(int);
+void obfuscate_set_keyword(const char *);
+void obfuscate_input(u_char *, u_int);
+void obfuscate_output(u_char *, u_int);
+
+#endif
diff -Nurp openssh-8.3p1/packet.c openssh-8.3p1-ob/packet.c
--- openssh-8.3p1/packet.c	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/packet.c	2020-05-28 11:24:13.083779498 +0800
@@ -94,6 +94,7 @@
 #include "channels.h"
 #include "ssh.h"
 #include "packet.h"
+#include "obfuscate.h"
 #include "ssherr.h"
 #include "sshbuf.h"
 
@@ -177,6 +178,8 @@ struct session_state {
 	/* Set to true if we are authenticated. */
 	int after_authentication;
 
+	int obfuscation;
+
 	int keep_alive_timeouts;
 
 	/* The maximum time that we will wait to send or receive a packet */
@@ -1198,6 +1201,8 @@ ssh_packet_send2_wrapped(struct ssh *ssh
 		if ((r = sshbuf_put(state->output, macbuf, mac->mac_len)) != 0)
 			goto out;
 	}
+	if(state->obfuscation)
+		obfuscate_output(cp, sshbuf_len(state->outgoing_packet));
 #ifdef PACKET_DEBUG
 	fprintf(stderr, "encrypted: ");
 	sshbuf_dump(state->output, stderr);
@@ -1540,6 +1545,8 @@ ssh_packet_read_poll2(struct ssh *ssh, u
 		if ((r = sshbuf_reserve(state->incoming_packet, block_size,
 		    &cp)) != 0)
 			goto out;
+		if(state->obfuscation)
+			obfuscate_input(sshbuf_mutable_ptr(state->input), block_size);
 		if ((r = cipher_crypt(state->receive_context,
 		    state->p_send.seqnr, cp, sshbuf_ptr(state->input),
 		    block_size, 0, 0)) != 0)
@@ -1605,6 +1612,8 @@ ssh_packet_read_poll2(struct ssh *ssh, u
 			goto out;
 		}
 	}
+	if(state->obfuscation)
+		obfuscate_input(sshbuf_mutable_ptr(state->input), need);
 	if ((r = sshbuf_reserve(state->incoming_packet, aadlen + need,
 	    &cp)) != 0)
 		goto out;
@@ -2740,3 +2749,25 @@ sshpkt_add_padding(struct ssh *ssh, u_ch
 	ssh->state->extra_pad = pad;
 	return 0;
 }
+
+void
+sshpkt_enable_obfuscation(struct ssh *ssh)
+{
+	debug("Obfuscation enabled");
+	ssh->state->obfuscation = 1;
+}
+
+void
+sshpkt_disable_obfuscation(struct ssh *ssh)
+{
+	if(ssh->state->obfuscation) {
+		debug("Obfuscation disabled");
+		ssh->state->obfuscation = 0;
+	}
+}
+
+int
+sshpkt_get_obfuscation(struct ssh *ssh)
+{
+	return ssh->state->obfuscation;
+}
diff -Nurp openssh-8.3p1/packet.h openssh-8.3p1-ob/packet.h
--- openssh-8.3p1/packet.h	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/packet.h	2020-05-28 11:24:13.083779498 +0800
@@ -180,6 +180,9 @@ void	sshpkt_fatal(struct ssh *ssh, int r
 	    __attribute__((format(printf, 3, 4)))
 	    __attribute__((noreturn));
 int	sshpkt_msg_ignore(struct ssh *, u_int);
+void	sshpkt_enable_obfuscation(struct ssh *);
+void	sshpkt_disable_obfuscation(struct ssh *);
+int sshpkt_get_obfuscation(struct ssh *);
 
 int	sshpkt_put(struct ssh *ssh, const void *v, size_t len);
 int	sshpkt_putb(struct ssh *ssh, const struct sshbuf *b);
diff -Nurp openssh-8.3p1/readconf.c openssh-8.3p1-ob/readconf.c
--- openssh-8.3p1/readconf.c	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/readconf.c	2020-05-28 11:24:13.083779498 +0800
@@ -143,7 +143,7 @@ typedef enum {
 	oBadOption,
 	oHost, oMatch, oInclude,
 	oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
-	oGatewayPorts, oExitOnForwardFailure,
+	oGatewayPorts, oExitOnForwardFailure, oObfuscateHandshake, oObfuscateKeyword,
 	oPasswordAuthentication,
 	oChallengeResponseAuthentication, oXAuthLocation,
 	oIdentityFile, oHostname, oPort, oRemoteForward, oLocalForward,
@@ -310,6 +310,8 @@ static struct {
 	{ "ignoreunknown", oIgnoreUnknown },
 	{ "proxyjump", oProxyJump },
 	{ "securitykeyprovider", oSecurityKeyProvider },
+	{ "obfuscatehandshake", oObfuscateHandshake },
+	{ "obfuscatekeyword", oObfuscateKeyword },
 
 	{ NULL, oBadOption }
 };
@@ -1812,6 +1814,16 @@ parse_keytypes:
 			*charptr = xstrdup(arg);
 		break;
 
+	case oObfuscateHandshake:
+		intptr = &options->obfuscate_handshake;
+		goto parse_flag;
+
+	case oObfuscateKeyword:
+		if (*activep)
+			options->obfuscate_handshake = 1;
+		charptr = &options->obfuscate_keyword;
+		goto parse_string;
+
 	case oDeprecated:
 		debug("%s line %d: Deprecated option \"%s\"",
 		    filename, linenum, keyword);
@@ -2005,6 +2017,8 @@ initialize_options(Options * options)
 	options->add_keys_to_agent = -1;
 	options->identity_agent = NULL;
 	options->visual_host_key = -1;
+	options->obfuscate_handshake = 0;
+	options->obfuscate_keyword = NULL;
 	options->ip_qos_interactive = -1;
 	options->ip_qos_bulk = -1;
 	options->request_tty = -1;
diff -Nurp openssh-8.3p1/readconf.h openssh-8.3p1-ob/readconf.h
--- openssh-8.3p1/readconf.h	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/readconf.h	2020-05-28 11:24:13.083779498 +0800
@@ -140,6 +140,8 @@ typedef struct {
 	int	permit_local_command;
 	char	*remote_command;
 	int	visual_host_key;
+	int obfuscate_handshake;
+	char *obfuscate_keyword;
 
 	int	request_tty;
 
diff -Nurp openssh-8.3p1/scp.c openssh-8.3p1-ob/scp.c
--- openssh-8.3p1/scp.c	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/scp.c	2020-05-28 11:24:13.083779498 +0800
@@ -430,7 +430,7 @@ main(int argc, char **argv)
 
 	fflag = Tflag = tflag = 0;
 	while ((ch = getopt(argc, argv,
-	    "dfl:prtTvBCc:i:P:q12346S:o:F:J:")) != -1) {
+	    "dfl:prtTvBCc:i:P:q12346S:o:F:J:zZ:")) != -1) {
 		switch (ch) {
 		/* User-visible flags. */
 		case '1':
@@ -442,6 +442,7 @@ main(int argc, char **argv)
 		case '4':
 		case '6':
 		case 'C':
+		case 'z':
 			addargs(&args, "-%c", ch);
 			addargs(&remote_remote_args, "-%c", ch);
 			break;
@@ -453,6 +454,7 @@ main(int argc, char **argv)
 		case 'i':
 		case 'F':
 		case 'J':
+		case 'Z':
 			addargs(&remote_remote_args, "-%c", ch);
 			addargs(&remote_remote_args, "%s", optarg);
 			addargs(&args, "-%c", ch);
diff -Nurp openssh-8.3p1/servconf.c openssh-8.3p1-ob/servconf.c
--- openssh-8.3p1/servconf.c	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/servconf.c	2020-05-28 11:24:13.083779498 +0800
@@ -94,6 +94,7 @@ initialize_server_options(ServerOptions
 
 	/* Standard Options */
 	options->num_ports = 0;
+	options->num_obfuscated_ports = 0;
 	options->ports_from_cmdline = 0;
 	options->queued_listen_addrs = NULL;
 	options->num_queued_listens = 0;
@@ -176,6 +177,7 @@ initialize_server_options(ServerOptions
 	options->permitted_listens = NULL;
 	options->adm_forced_command = NULL;
 	options->chroot_directory = NULL;
+	options->obfuscate_keyword = NULL;
 	options->authorized_keys_command = NULL;
 	options->authorized_keys_command_user = NULL;
 	options->revoked_keys_file = NULL;
@@ -317,7 +319,7 @@ fill_default_server_options(ServerOption
 #endif /* WITH_XMSS */
 	}
 	/* No certificates by default */
-	if (options->num_ports == 0)
+	if (options->num_ports == 0 && options->num_obfuscated_ports == 0)
 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
 	if (options->address_family == -1)
 		options->address_family = AF_UNSPEC;
@@ -511,7 +513,7 @@ typedef enum {
 	/* Portable-specific options */
 	sUsePAM, sUsePAMChecklocks,
 	/* Standard Options */
-	sPort, sHostKeyFile, sLoginGraceTime,
+	sPort, sObfuscatedPort, sObfuscateKeyword, sHostKeyFile, sLoginGraceTime,
 	sPermitRootLogin, sLogFacility, sLogLevel,
 	sRhostsRSAAuthentication, sRSAAuthentication,
 	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
@@ -566,6 +568,8 @@ static struct {
 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
 	/* Standard Options */
 	{ "port", sPort, SSHCFG_GLOBAL },
+	{ "obfuscatedport", sObfuscatedPort, SSHCFG_GLOBAL },
+	{ "obfuscatekeyword", sObfuscateKeyword, SSHCFG_GLOBAL },
 	{ "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
 	{ "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },		/* alias */
 	{ "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL },
@@ -774,6 +778,10 @@ add_listen_addr(ServerOptions *options,
 			add_one_listen_addr(options, addr, rdomain,
 			    options->ports[i]);
 		}
+		for (i = 0; i < options->num_obfuscated_ports; i++) {
+			add_one_listen_addr(options, addr, rdomain,
+				options->obfuscated_ports[i]);
+		}
 	}
 }
 
@@ -888,7 +896,7 @@ process_queued_listen_addrs(ServerOption
 	u_int i;
 	struct queued_listenaddr *qla;
 
-	if (options->num_ports == 0)
+	if (options->num_ports == 0 && options->num_obfuscated_ports == 0)
 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
 	if (options->address_family == -1)
 		options->address_family = AF_UNSPEC;
@@ -1339,6 +1347,30 @@ process_server_config_line_depth(ServerO
 			    filename, linenum);
 		break;
 
+	case sObfuscatedPort:
+		if(options->ports_from_cmdline)
+			return 0;
+		if(options->listen_addrs != NULL)
+			fatal("%s line %d: ports must be specified before ListenAddress.", filename, linenum);
+		if(options->num_obfuscated_ports >= MAX_PORTS)
+			fatal("%s line %d: too many ports.", filename, linenum);
+		arg = strdelim(&cp);
+		if(!arg || *arg == '\0')
+			fatal("%s line %d: missing port number.", filename, linenum);
+		options->obfuscated_ports[options->num_obfuscated_ports++] = a2port(arg);
+		if(options->obfuscated_ports[options->num_obfuscated_ports - 1] <= 0)
+			fatal("%s line %d: badly formatted port number.", filename, linenum);
+		break;
+	case sObfuscateKeyword:
+		charptr = &options->obfuscate_keyword;
+		arg = strdelim(&cp);
+		if(!arg || *arg == '\0')
+			fatal("%s line %d: missing keyword argument.",
+					filename, linenum);
+		if(*activep && *charptr == NULL)
+			*charptr = xstrdup(arg);
+		break;
+
 	case sLoginGraceTime:
 		intptr = &options->login_grace_time;
  parse_time:
diff -Nurp openssh-8.3p1/servconf.h openssh-8.3p1-ob/servconf.h
--- openssh-8.3p1/servconf.h	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/servconf.h	2020-05-28 11:24:13.083779498 +0800
@@ -203,6 +203,11 @@ typedef struct {
 	u_int   num_permitted_listens;
 
 	char   *chroot_directory;
+
+	int obfuscated_ports[MAX_PORTS];
+	u_int num_obfuscated_ports;
+	char *obfuscate_keyword;
+
 	char   *revoked_keys_file;
 	char   *trusted_user_ca_keys;
 	char   *authorized_keys_command;
diff -Nurp openssh-8.3p1/sftp.c openssh-8.3p1-ob/sftp.c
--- openssh-8.3p1/sftp.c	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/sftp.c	2020-05-28 11:40:23.848559334 +0800
@@ -2409,12 +2409,13 @@ main(int argc, char **argv)
 	infile = stdin;
 
 	while ((ch = getopt(argc, argv,
-	    "1246afhNpQqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:")) != -1) {
+	    "1246afhNpQqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:zZ:")) != -1) {
 		switch (ch) {
 		/* Passed through to ssh(1) */
 		case '4':
 		case '6':
 		case 'C':
+		case 'z':
 			addargs(&args, "-%c", ch);
 			break;
 		/* Passed through to ssh(1) with argument */
@@ -2423,6 +2424,7 @@ main(int argc, char **argv)
 		case 'c':
 		case 'i':
 		case 'o':
+		case 'Z':
 			addargs(&args, "-%c", ch);
 			addargs(&args, "%s", optarg);
 			break;
diff -Nurp openssh-8.3p1/ssh.c openssh-8.3p1-ob/ssh.c
--- openssh-8.3p1/ssh.c	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/ssh.c	2020-05-28 11:24:13.083779498 +0800
@@ -202,13 +202,14 @@ static void
 usage(void)
 {
 	fprintf(stderr,
-"usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface]\n"
+"usage: ssh [-46AaCfGgKkMNnqsTtVvXxYyz] [-B bind_interface]\n"
 "           [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]\n"
 "           [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]\n"
 "           [-i identity_file] [-J [user@]host[:port]] [-L address]\n"
 "           [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n"
 "           [-Q query_option] [-R address] [-S ctl_path] [-W host:port]\n"
-"           [-w local_tun[:remote_tun]] destination [command]\n"
+"           [-w local_tun[:remote_tun]] [-Z obfuscate_keyword]\n"
+"			destination [command]\n"
 	);
 	exit(255);
 }
@@ -694,7 +695,7 @@ main(int ac, char **av)
 
  again:
 	while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
-	    "AB:CD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
+	    "AB:CD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYyzZ:")) != -1) {
 		switch (opt) {
 		case '1':
 			fatal("SSH protocol v.1 is no longer supported");
@@ -1038,6 +1039,13 @@ main(int ac, char **av)
 		case 'F':
 			config = optarg;
 			break;
+		case 'z':
+			options.obfuscate_handshake = 1;
+			break;
+		case 'Z':
+			options.obfuscate_handshake = 1;
+			options.obfuscate_keyword = optarg;
+			break;
 		default:
 			usage();
 		}
diff -Nurp openssh-8.3p1/sshconnect.c openssh-8.3p1-ob/sshconnect.c
--- openssh-8.3p1/sshconnect.c	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/sshconnect.c	2020-05-28 11:24:13.083779498 +0800
@@ -64,6 +64,7 @@
 #include "monitor_fdpass.h"
 #include "ssh2.h"
 #include "version.h"
+#include "obfuscate.h"
 #include "authfile.h"
 #include "ssherr.h"
 #include "authfd.h"
@@ -281,6 +282,12 @@ ssh_proxy_connect(struct ssh *ssh, const
 	if (ssh_packet_set_connection(ssh, pout[0], pin[1]) == NULL)
 		return -1; /* ssh_packet_set_connection logs error */
 
+	if(options.obfuscate_handshake) {
+		if(options.obfuscate_keyword)
+			obfuscate_set_keyword(options.obfuscate_keyword);
+		sshpkt_enable_obfuscation(ssh);
+	}
+
 	return 0;
 }
 
@@ -541,6 +548,11 @@ ssh_connect_direct(struct ssh *ssh, cons
 	/* Set the connection. */
 	if (ssh_packet_set_connection(ssh, sock, sock) == NULL)
 		return -1; /* ssh_packet_set_connection logs error */
+	if(options.obfuscate_handshake) {
+		if(options.obfuscate_keyword)
+			obfuscate_set_keyword(options.obfuscate_keyword);
+		sshpkt_enable_obfuscation(ssh);
+	}
 
 	return 0;
 }
@@ -1285,6 +1297,9 @@ ssh_login(struct ssh *ssh, Sensitive *se
 	host = xstrdup(orighost);
 	lowercase(host);
 
+	if(options.obfuscate_handshake)
+		obfuscate_send_seed(ssh_packet_get_connection_out(ssh));
+
 	/* Exchange protocol version identification strings with the server. */
 	if ((r = kex_exchange_identification(ssh, timeout_ms, NULL)) != 0)
 		sshpkt_fatal(ssh, r, "banner exchange");
diff -Nurp openssh-8.3p1/sshd.c openssh-8.3p1-ob/sshd.c
--- openssh-8.3p1/sshd.c	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/sshd.c	2020-05-28 11:41:40.747866453 +0800
@@ -118,6 +118,7 @@
 #endif
 #include "monitor_wrap.h"
 #include "audit.h"
+#include "obfuscate.h"
 #include "ssh-sandbox.h"
 #include "auth-options.h"
 #include "version.h"
@@ -257,6 +258,9 @@ struct include_list includes = TAILQ_HEA
 /* message to be displayed after login */
 struct sshbuf *loginmsg;
 
+/* Enable handshake obfuscation */
+int use_obfuscation = 0;
+
 /* Unprivileged user */
 struct passwd *privsep_pw = NULL;
 
@@ -1489,7 +1493,7 @@ main(int ac, char **av)
 	struct ssh *ssh = NULL;
 	extern char *optarg;
 	extern int optind;
-	int r, opt, on = 1, already_daemon, remote_port;
+	int r, opt, on = 1, already_daemon, remote_port, local_port;
 	int sock_in = -1, sock_out = -1, newsock = -1;
 	const char *remote_ip, *rdomain;
 	char *fp, *line, *laddr, *logfile = NULL;
@@ -2108,6 +2112,14 @@ main(int ac, char **av)
 	channel_set_af(ssh, options.address_family);
 	process_permitopen(ssh, &options);
 
+	local_port = ssh_local_port(ssh);
+	for(i = 0; i < options.num_obfuscated_ports; i++) {
+		if(options.obfuscated_ports[i] == local_port) {
+			use_obfuscation = 1;
+			break;
+		}
+	}
+
 	/* Set SO_KEEPALIVE if requested. */
 	if (options.tcp_keep_alive && ssh_packet_connection_is_on_socket(ssh) &&
 	    setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1)
@@ -2155,6 +2167,13 @@ main(int ac, char **av)
 	if (!debug_flag)
 		alarm(options.login_grace_time);
 
+	if(use_obfuscation) {
+		if(options.obfuscate_keyword)
+			obfuscate_set_keyword(options.obfuscate_keyword);
+		sshpkt_enable_obfuscation(ssh);
+		obfuscate_receive_seed(ssh, sock_in);
+	}
+
 	if ((r = kex_exchange_identification(ssh, -1,
 	    options.version_addendum)) != 0)
 		sshpkt_fatal(ssh, r, "banner exchange");
@@ -2180,8 +2199,12 @@ main(int ac, char **av)
 	auth_debug_reset();
 
 	if (use_privsep) {
-		if (privsep_preauth(ssh) == 1)
+
+		if (privsep_preauth(ssh) == 1) {
+			if(use_obfuscation)
+				sshpkt_disable_obfuscation(ssh);
 			goto authenticated;
+		}
 	} else if (have_agent) {
 		if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) {
 			error("Unable to get agent socket: %s", ssh_err(r));
diff -Nurp openssh-8.3p1/sshd_config openssh-8.3p1-ob/sshd_config
--- openssh-8.3p1/sshd_config	2020-05-27 08:38:00.000000000 +0800
+++ openssh-8.3p1-ob/sshd_config	2020-05-28 11:24:13.083779498 +0800
@@ -11,6 +11,8 @@
 # default value.
 
 #Port 22
+#ObfuscatedPort 222
+#ObfuscateKeyword key
 #AddressFamily any
 #ListenAddress 0.0.0.0
 #ListenAddress ::
openSUSE Build Service is sponsored by