From b9b704f8b584994cbbb4975133d6032d5d0d294e Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Mon, 4 Jan 2016 15:21:51 +0100
Subject: ssh: Optimization - inline encoding in ssh_message:encode/1, now 8
 times faster. Also fixes minor error in ssh_protocol_SUITE that the new
 encoder found.

---
 lib/ssh/src/ssh_bits.erl            | 141 +++++-------------------------
 lib/ssh/src/ssh_message.erl         | 169 ++++++++++++++++++++----------------
 lib/ssh/src/ssh_transport.erl       |  48 +++++-----
 lib/ssh/test/ssh_protocol_SUITE.erl |   2 +-
 4 files changed, 135 insertions(+), 225 deletions(-)

(limited to 'lib/ssh')

diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl
index 4da3a6018b..101bf76cd3 100644
--- a/lib/ssh/src/ssh_bits.erl
+++ b/lib/ssh/src/ssh_bits.erl
@@ -26,52 +26,30 @@
 
 -include("ssh.hrl").
 
--export([encode/2]).
--export([mpint/1, string/1, name_list/1]).
+-export([mpint/1, name_list/1]).
 -export([random/1]).
 
--define(name_list(X), 
-	(fun(B) -> ?binary(B) end)(list_to_binary(name_concat(X)))).
-
-
-name_concat([Name]) when is_atom(Name) -> atom_to_list(Name);
-name_concat([Name]) when is_list(Name) -> Name;
-name_concat([Name|Ns]) -> 
-    if is_atom(Name) ->
-	    [atom_to_list(Name),"," | name_concat(Ns)];
-       is_list(Name) ->
-	    [Name,"," | name_concat(Ns)]
-    end;
-name_concat([]) -> [].
-
-
-name_list(Ns) ->
-    ?name_list(Ns).
+%%%----------------------------------------------------------------
+name_list([Name]) -> to_bin(Name);
+name_list([Name|Ns]) -> <<(to_bin(Name))/binary, ",", (name_list(Ns))/binary>>;
+name_list([]) -> <<>>.
+
+to_bin(A) when is_atom(A) -> list_to_binary(atom_to_list(A));
+to_bin(S) when is_list(S) -> list_to_binary(S);
+to_bin(B) when is_binary(B) -> B.
+
+%%%----------------------------------------------------------------
+%%% Multi Precision Integer encoding
+mpint(-1) -> <<0,0,0,1,16#ff>>;
+mpint(0) -> <<0,0,0,0>>;
+mpint(X) when X < 0 -> mpint_neg(X,0,[]);
+mpint(X) -> mpint_pos(X,0,[]).
     
-
-string(Str) ->
-    ?string(Str).
-
-
-%% MP representaion  (SSH2)
-mpint(X) when X < 0 ->
-    if X == -1 ->
-	    <<0,0,0,1,16#ff>>;	    
-       true ->
-	    mpint_neg(X,0,[])
-    end;
-mpint(X) ->
-    if X == 0 ->
-	    <<0,0,0,0>>;
-       true ->
-	    mpint_pos(X,0,[])
-    end.
-
 mpint_neg(-1,I,Ds=[MSB|_]) ->
     if MSB band 16#80 =/= 16#80 ->
 	    <<?UINT32((I+1)), (list_to_binary([255|Ds]))/binary>>;
        true ->
-	    (<<?UINT32(I), (list_to_binary(Ds))/binary>>)
+	    <<?UINT32(I), (list_to_binary(Ds))/binary>>
     end;
 mpint_neg(X,I,Ds)  ->
     mpint_neg(X bsr 8,I+1,[(X band 255)|Ds]).
@@ -80,96 +58,17 @@ mpint_pos(0,I,Ds=[MSB|_]) ->
     if MSB band 16#80 == 16#80 ->
 	    <<?UINT32((I+1)), (list_to_binary([0|Ds]))/binary>>;
        true ->
-	    (<<?UINT32(I), (list_to_binary(Ds))/binary>>)
+	    <<?UINT32(I), (list_to_binary(Ds))/binary>>
     end;
 mpint_pos(X,I,Ds) ->
     mpint_pos(X bsr 8,I+1,[(X band 255)|Ds]).
 
 
-encode(List, Types) ->
-    list_to_binary(enc(List, Types)).
-
-%%
-%% Encode record element
-%%
-enc(Xs, Ts) ->
-    enc(Xs, Ts, 0).
-
-enc(Xs, [boolean|Ts], Offset) ->
-    X = hd(Xs),
-    [?boolean(X) | enc(tl(Xs), Ts, Offset+1)];
-enc(Xs, [byte|Ts], Offset) ->
-    X = hd(Xs),
-    [?byte(X) | enc(tl(Xs), Ts,Offset+1)];
-enc(Xs, [uint16|Ts], Offset) ->
-    X = hd(Xs),
-    [?uint16(X) | enc(tl(Xs), Ts,Offset+2)];
-enc(Xs, [uint32 |Ts], Offset) ->
-    X = hd(Xs),
-    [?uint32(X) | enc(tl(Xs), Ts,Offset+4)];
-enc(Xs, [uint64|Ts], Offset) ->
-    X = hd(Xs),
-    [?uint64(X) | enc(tl(Xs), Ts,Offset+8)];
-enc(Xs, [mpint|Ts], Offset) ->
-    Y = mpint(hd(Xs)),
-    [Y | enc(tl(Xs), Ts,Offset+size(Y))];
-enc(Xs, [string|Ts], Offset) ->
-    X0 = hd(Xs),
-    Y = ?string(X0),
-    [Y | enc(tl(Xs),Ts,Offset+size(Y))];
-enc(Xs, [string_utf8|Ts], Offset) ->
-    X0 = hd(Xs),
-    Y = ?string_utf8(X0),
-    [Y | enc(tl(Xs),Ts,Offset+size(Y))];
-enc(Xs, [binary|Ts], Offset) ->
-     X0 = hd(Xs),
-    Y = ?binary(X0),
-    [Y | enc(tl(Xs), Ts,Offset+size(Y))];
-enc(Xs, [name_list|Ts], Offset) ->
-    X0 = hd(Xs),
-    Y = ?name_list(X0),
-    [Y | enc(tl(Xs), Ts, Offset+size(Y))];
-enc(Xs, [cookie|Ts], Offset) ->
-    [random(16) | enc(tl(Xs), Ts, Offset+16)];
-enc(Xs, [{pad,N}|Ts], Offset) ->
-    K = (N - (Offset rem N)) rem N,
-    [fill_bits(K,0) | enc(Xs, Ts, Offset+K)];
-enc(Xs, ['...'| []], _Offset) ->
-    X = hd(Xs),
-    if is_binary(X) ->
-	    [X];
-       is_list(X) ->
-	    [list_to_binary(X)];
-       X==undefined ->
-	    []
-    end;
-enc([], [],_) ->
-    [].
-
-
-%%
-%% Create a binary with constant bytes 
-%%
-fill_bits(N,C) ->
-    list_to_binary(fill(N,C)).
-
-fill(0,_C) -> [];
-fill(1,C) -> [C];
-fill(N,C) ->
-    Cs = fill(N div 2, C),
-    Cs1 = [Cs,Cs],
-    if N band 1 == 0 ->
-	    Cs1;
-       true ->
-	    [C,Cs,Cs]
-    end.
-
-
+%%%----------------------------------------------------------------
 %% random/1
 %%   Generate N random bytes
 %%
-random(N) ->
-    crypto:strong_rand_bytes(N).
+random(N) -> crypto:strong_rand_bytes(N).
 
 
 
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index b6c4496be2..a0e9a4961c 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -32,16 +32,44 @@
 
 -export([encode/1, decode/1, decode_keyboard_interactive_prompts/2]).
 
+-define('2bin'(X), (if is_binary(X) -> X;
+		       is_list(X) -> list_to_binary(X);
+		       X==undefined -> <<>>
+		    end) ).
+
+-define('E...'(X),    ?'2bin'(X)/binary ).
+-define(Eboolean(X),  ?BOOLEAN(case X of
+				   true -> ?TRUE;
+				   false -> ?FALSE
+			       end) ).
+-define(Ebyte(X),        ?BYTE(X) ).
+-define(Euint32(X),      ?UINT32(X) ).
+-define(Estring(X),      ?STRING(?'2bin'(X)) ).
+-define(Estring_utf8(X), ?string_utf8(X)/binary ).
+-define(Ename_list(X),   ?STRING(ssh_bits:name_list(X)) ).
+-define(Empint(X),       (ssh_bits:mpint(X))/binary ).
+-define(Ebinary(X),      ?STRING(X) ).
+
+%% encode(Msg) ->
+%%     try encode1(Msg)
+%%     catch
+%% 	C:E ->
+%% 	    io:format('***********************~n~p:~p  ~p~n',[C,E,Msg]),
+%% 	    error(E)
+%%     end.
+
 encode(#ssh_msg_global_request{
 	  name = Name,
 	  want_reply = Bool,
 	  data = Data}) ->
-    ssh_bits:encode([?SSH_MSG_GLOBAL_REQUEST,
-		     Name, Bool, Data], [byte, string, boolean, '...']);
+    <<?Ebyte(?SSH_MSG_GLOBAL_REQUEST), ?Estring(Name), ?Eboolean(Bool), ?'E...'(Data)>>;
+
 encode(#ssh_msg_request_success{data = Data}) ->
-    <<?BYTE(?SSH_MSG_REQUEST_SUCCESS), Data/binary>>;
+    <<?Ebyte(?SSH_MSG_REQUEST_SUCCESS), Data/binary>>;
+
 encode(#ssh_msg_request_failure{}) ->
-    <<?BYTE(?SSH_MSG_REQUEST_FAILURE)>>;
+    <<?Ebyte(?SSH_MSG_REQUEST_FAILURE)>>;
+
 encode(#ssh_msg_channel_open{
 	  channel_type = Type,
 	  sender_channel = Sender,
@@ -49,9 +77,8 @@ encode(#ssh_msg_channel_open{
 	  maximum_packet_size = Max,
 	  data = Data
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_CHANNEL_OPEN,
-		     Type, Sender, Window, Max, Data], [byte, string, uint32,
-							uint32, uint32, '...']);
+    <<?Ebyte(?SSH_MSG_CHANNEL_OPEN), ?Estring(Type), ?Euint32(Sender), ?Euint32(Window), ?Euint32(Max), ?'E...'(Data)>>;
+
 encode(#ssh_msg_channel_open_confirmation{
 	  recipient_channel = Recipient,
 	  sender_channel = Sender,
@@ -59,60 +86,63 @@ encode(#ssh_msg_channel_open_confirmation{
 	  maximum_packet_size = MaxPacketSize,
 	  data = Data
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_CHANNEL_OPEN_CONFIRMATION, Recipient,
-		     Sender, InitWindowSize, MaxPacketSize, Data],
-		    [byte, uint32, uint32, uint32, uint32, '...']);
+    <<?Ebyte(?SSH_MSG_CHANNEL_OPEN_CONFIRMATION),
+      ?Euint32(Recipient), ?Euint32(Sender), ?Euint32(InitWindowSize), ?Euint32(MaxPacketSize),
+      ?'E...'(Data)>>;
+
 encode(#ssh_msg_channel_open_failure{
 	  recipient_channel = Recipient,
 	  reason = Reason,
 	  description = Desc,
 	  lang = Lang
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_CHANNEL_OPEN_FAILURE, Recipient,
-		     Reason, Desc, Lang], [byte, uint32, uint32, string, string]);
+    <<?Ebyte(?SSH_MSG_CHANNEL_OPEN_FAILURE), ?Euint32(Recipient),?Euint32(Reason), ?Estring(Desc), ?Estring(Lang)>>;
+
 encode(#ssh_msg_channel_window_adjust{
 	  recipient_channel = Recipient,
 	  bytes_to_add = Bytes
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_CHANNEL_WINDOW_ADJUST, Recipient, Bytes],
-		    [byte, uint32, uint32]);
+    <<?Ebyte(?SSH_MSG_CHANNEL_WINDOW_ADJUST), ?Euint32(Recipient), ?Euint32(Bytes)>>;
+
 encode(#ssh_msg_channel_data{
 	  recipient_channel = Recipient,
 	  data = Data
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_CHANNEL_DATA, Recipient, Data], [byte, uint32, binary]);
+   <<?Ebyte(?SSH_MSG_CHANNEL_DATA), ?Euint32(Recipient), ?Ebinary(Data)>>;
 
 encode(#ssh_msg_channel_extended_data{
 	  recipient_channel = Recipient,
 	  data_type_code = DataType,
 	  data = Data
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_CHANNEL_EXTENDED_DATA, Recipient,
-		     DataType, Data], [byte, uint32, uint32, binary]);
+    <<?Ebyte(?SSH_MSG_CHANNEL_EXTENDED_DATA), ?Euint32(Recipient), ?Euint32(DataType), ?Ebinary(Data)>>;
 
 encode(#ssh_msg_channel_eof{recipient_channel = Recipient
 			   }) ->
-    <<?BYTE(?SSH_MSG_CHANNEL_EOF), ?UINT32(Recipient)>>;
+    <<?Ebyte(?SSH_MSG_CHANNEL_EOF), ?Euint32(Recipient)>>;
+
 encode(#ssh_msg_channel_close{
 	   recipient_channel = Recipient
 	  }) ->
-    <<?BYTE(?SSH_MSG_CHANNEL_CLOSE),  ?UINT32(Recipient)>>;
+    <<?Ebyte(?SSH_MSG_CHANNEL_CLOSE), ?Euint32(Recipient)>>;
+
 encode(#ssh_msg_channel_request{
 	  recipient_channel = Recipient,
 	  request_type = Type,
 	  want_reply = Bool,
 	  data  = Data
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_CHANNEL_REQUEST, Recipient, Type, Bool, Data],
-		    [byte, uint32, string, boolean, '...']);
+    <<?Ebyte(?SSH_MSG_CHANNEL_REQUEST), ?Euint32(Recipient), ?Estring(Type), ?Eboolean(Bool), ?'E...'(Data)>>;
+
 encode(#ssh_msg_channel_success{
 	  recipient_channel = Recipient
 	 }) ->
-    <<?BYTE(?SSH_MSG_CHANNEL_SUCCESS), ?UINT32(Recipient)>>;
+    <<?Ebyte(?SSH_MSG_CHANNEL_SUCCESS), ?Euint32(Recipient)>>;
+
 encode(#ssh_msg_channel_failure{
 	  recipient_channel = Recipient
 	 }) ->
-    <<?BYTE(?SSH_MSG_CHANNEL_FAILURE), ?UINT32(Recipient)>>;
+    <<?Ebyte(?SSH_MSG_CHANNEL_FAILURE), ?Euint32(Recipient)>>;
 
 encode(#ssh_msg_userauth_request{
 	  user = User,
@@ -120,36 +150,33 @@ encode(#ssh_msg_userauth_request{
 	  method = Method,
 	  data = Data
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_USERAUTH_REQUEST, User, Service, Method, Data],
-		    [byte, string_utf8, string, string, '...']);
+    <<?Ebyte(?SSH_MSG_USERAUTH_REQUEST), ?Estring_utf8(User), ?Estring(Service), ?Estring(Method), ?'E...'(Data)>>;
+
 encode(#ssh_msg_userauth_failure{
 	  authentications = Auths,
 	  partial_success = Bool
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_USERAUTH_FAILURE, Auths, Bool],
-		    [byte, string, boolean]);
+    <<?Ebyte(?SSH_MSG_USERAUTH_FAILURE), ?Estring(Auths), ?Eboolean(Bool)>>;
+
 encode(#ssh_msg_userauth_success{}) ->
-    <<?BYTE(?SSH_MSG_USERAUTH_SUCCESS)>>;
+    <<?Ebyte(?SSH_MSG_USERAUTH_SUCCESS)>>;
 
 encode(#ssh_msg_userauth_banner{
        message = Banner,
        language = Lang
       }) ->
-    ssh_bits:encode([?SSH_MSG_USERAUTH_BANNER, Banner, Lang],
-		    [byte, string_utf8, string]);
+    <<?Ebyte(?SSH_MSG_USERAUTH_BANNER), ?Estring_utf8(Banner), ?Estring(Lang)>>;
 
 encode(#ssh_msg_userauth_pk_ok{
 	  algorithm_name = Alg,
 	  key_blob = KeyBlob
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_USERAUTH_PK_OK, Alg, KeyBlob],
-		    [byte, string, binary]);
+    <<?Ebyte(?SSH_MSG_USERAUTH_PK_OK), ?Estring(Alg), ?Ebinary(KeyBlob)>>;
 
 encode(#ssh_msg_userauth_passwd_changereq{prompt = Prompt,
 					  languge = Lang
 					 })->
-    ssh_bits:encode([?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, Prompt, Lang],
-		    [byte, string, string]);
+    <<?Ebyte(?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ), ?Estring(Prompt), ?Estring(Lang)>>;
 
 encode(#ssh_msg_userauth_info_request{
 	  name = Name,
@@ -157,41 +184,37 @@ encode(#ssh_msg_userauth_info_request{
 	  language_tag = Lang,
 	  num_prompts = NumPromtps,
 	  data = Data}) ->
-    ssh_bits:encode([?SSH_MSG_USERAUTH_INFO_REQUEST, Name, Inst, Lang, NumPromtps, Data],
-		    [byte, string, string, string, uint32, '...']);
+    <<?Ebyte(?SSH_MSG_USERAUTH_INFO_REQUEST), ?Estring(Name), ?Estring(Inst), ?Estring(Lang),
+      ?Euint32(NumPromtps), ?'E...'(Data)>>;
 
 encode(#ssh_msg_userauth_info_response{
 	  num_responses = Num,
 	  data = Data}) ->
-    Responses = lists:map(fun("") ->
-				  <<>>;
-			     (Response) ->
-				  ssh_bits:encode([Response], [string])
-			  end, Data),
-    Start = ssh_bits:encode([?SSH_MSG_USERAUTH_INFO_RESPONSE, Num],
-			    [byte, uint32]),
-    iolist_to_binary([Start, Responses]);
+    lists:foldl(fun %%("", Acc) -> Acc;  % commented out since it seem wrong
+		    (Response, Acc) -> <<Acc/binary, ?Estring(Response)>>
+		end,
+		<<?Ebyte(?SSH_MSG_USERAUTH_INFO_RESPONSE), ?Euint32(Num)>>,
+		Data);
 
 encode(#ssh_msg_disconnect{
 	  code = Code,
 	  description = Desc,
 	  language = Lang
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_DISCONNECT, Code, Desc, Lang],
-		    [byte, uint32, string, string]);
+    <<?Ebyte(?SSH_MSG_DISCONNECT), ?Euint32(Code), ?Estring(Desc), ?Estring(Lang)>>;
 
 encode(#ssh_msg_service_request{
 	  name = Service
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_SERVICE_REQUEST, Service], [byte, string]);
+    <<?Ebyte(?SSH_MSG_SERVICE_REQUEST), ?Estring(Service)>>;
 
 encode(#ssh_msg_service_accept{
 	  name = Service
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_SERVICE_ACCEPT, Service], [byte, string]);
+    <<?Ebyte(?SSH_MSG_SERVICE_ACCEPT), ?Estring(Service)>>;
 
 encode(#ssh_msg_newkeys{}) ->
-    <<?BYTE(?SSH_MSG_NEWKEYS)>>;
+    <<?Ebyte(?SSH_MSG_NEWKEYS)>>;
 
 encode(#ssh_msg_kexinit{
 	  cookie = Cookie,
@@ -208,19 +231,13 @@ encode(#ssh_msg_kexinit{
 	  first_kex_packet_follows = Bool,
 	  reserved = Reserved
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_KEXINIT, Cookie, KeyAlgs, HostKeyAlgs, EncAlgC2S, EncAlgS2C,
-		     MacAlgC2S, MacAlgS2C, CompAlgS2C, CompAlgC2S, LangC2S, LangS2C, Bool,
-		     Reserved],
-		    [byte, cookie,
-		     name_list, name_list,
-		     name_list, name_list,
-		     name_list, name_list,
-		     name_list, name_list,
-		     name_list, name_list,
-		     boolean, uint32]);
+    <<?Ebyte(?SSH_MSG_KEXINIT), Cookie/binary,
+      ?Ename_list(KeyAlgs), ?Ename_list(HostKeyAlgs), ?Ename_list(EncAlgC2S), ?Ename_list(EncAlgS2C), ?Ename_list(MacAlgC2S),
+      ?Ename_list(MacAlgS2C), ?Ename_list(CompAlgS2C), ?Ename_list(CompAlgC2S), ?Ename_list(LangC2S), ?Ename_list(LangS2C),
+      ?Eboolean(Bool), ?Euint32(Reserved)>>;
 
 encode(#ssh_msg_kexdh_init{e = E}) ->
-    ssh_bits:encode([?SSH_MSG_KEXDH_INIT, E], [byte, mpint]);
+    <<?Ebyte(?SSH_MSG_KEXDH_INIT), ?Empint(E)>>;
 
 encode(#ssh_msg_kexdh_reply{
 	  public_host_key = Key,
@@ -229,25 +246,23 @@ encode(#ssh_msg_kexdh_reply{
 	 }) ->
     EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
     EncSign = encode_signature(Key, Signature),
-    ssh_bits:encode([?SSH_MSG_KEXDH_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]);
+    <<?Ebyte(?SSH_MSG_KEXDH_REPLY), ?Ebinary(EncKey), ?Empint(F), ?Ebinary(EncSign)>>;
 
 encode(#ssh_msg_kex_dh_gex_request{
 	  min = Min,
 	  n = N,
 	  max = Max
 	 }) ->
-    ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REQUEST, Min, N, Max],
-		    [byte, uint32, uint32, uint32]);
+    <<?Ebyte(?SSH_MSG_KEX_DH_GEX_REQUEST), ?Euint32(Min), ?Euint32(N), ?Euint32(Max)>>;
+
 encode(#ssh_msg_kex_dh_gex_request_old{n = N}) ->
-    ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REQUEST_OLD, N],
-		    [byte, uint32]);
+    <<?Ebyte(?SSH_MSG_KEX_DH_GEX_REQUEST_OLD), ?Euint32(N)>>;
 
 encode(#ssh_msg_kex_dh_gex_group{p = Prime, g = Generator}) ->
-    ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_GROUP, Prime, Generator],
-		    [byte, mpint, mpint]);
+    <<?Ebyte(?SSH_MSG_KEX_DH_GEX_GROUP), ?Empint(Prime), ?Empint(Generator)>>;
 
 encode(#ssh_msg_kex_dh_gex_init{e = Public}) ->
-    ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_INIT, Public], [byte, mpint]);
+    <<?Ebyte(?SSH_MSG_KEX_DH_GEX_INIT), ?Empint(Public)>>;
 
 encode(#ssh_msg_kex_dh_gex_reply{
 	  %% Will be private key encode_host_key extracts only the public part!
@@ -257,26 +272,26 @@ encode(#ssh_msg_kex_dh_gex_reply{
 	 }) ->
     EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
     EncSign = encode_signature(Key, Signature),
-    ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]);
+    <<?Ebyte(?SSH_MSG_KEX_DH_GEX_REPLY), ?Ebinary(EncKey), ?Empint(F), ?Ebinary(EncSign)>>;
 
 encode(#ssh_msg_kex_ecdh_init{q_c = Q_c}) ->
-    ssh_bits:encode([?SSH_MSG_KEX_ECDH_INIT, Q_c], [byte, mpint]);
+    <<?Ebyte(?SSH_MSG_KEX_ECDH_INIT), ?Empint(Q_c)>>;
 
 encode(#ssh_msg_kex_ecdh_reply{public_host_key = Key, q_s = Q_s, h_sig = Sign}) ->
     EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
     EncSign = encode_signature(Key, Sign),
-    ssh_bits:encode([?SSH_MSG_KEX_ECDH_REPLY, EncKey, Q_s, EncSign], [byte, binary, mpint, binary]);
+    <<?Ebyte(?SSH_MSG_KEX_ECDH_REPLY), ?Ebinary(EncKey), ?Empint(Q_s), ?Ebinary(EncSign)>>;
 
 encode(#ssh_msg_ignore{data = Data}) ->
-    ssh_bits:encode([?SSH_MSG_IGNORE, Data], [byte, string]);
+    <<?Ebyte(?SSH_MSG_IGNORE), ?Estring(Data)>>;
 
 encode(#ssh_msg_unimplemented{sequence = Seq}) ->
-    ssh_bits:encode([?SSH_MSG_UNIMPLEMENTED, Seq], [byte, uint32]);
+    <<?Ebyte(?SSH_MSG_UNIMPLEMENTED), ?Euint32(Seq)>>;
 
 encode(#ssh_msg_debug{always_display = Bool,
 		      message = Msg,
 		      language = Lang}) ->
-    ssh_bits:encode([?SSH_MSG_DEBUG, Bool, Msg, Lang], [byte, boolean, string, string]).
+    <<?Ebyte(?SSH_MSG_DEBUG), ?Eboolean(Bool), ?Estring(Msg), ?Estring(Lang)>>.
 
 
 %% Connection Messages
@@ -553,10 +568,10 @@ decode_signature(<<?DEC_BIN(_Alg,__0), ?UINT32(_), Signature/binary>>) ->
 
 
 encode_signature(#'RSAPublicKey'{}, Signature) ->
-    ssh_bits:encode(["ssh-rsa", Signature],[string, binary]);
+    <<?Ebinary(<<"ssh-rsa">>), ?Ebinary(Signature)>>;
 encode_signature({_, #'Dss-Parms'{}}, Signature) ->
-    ssh_bits:encode(["ssh-dss", Signature],[string, binary]);
+    <<?Ebinary(<<"ssh-dss">>), ?Ebinary(Signature)>>;
 encode_signature({#'ECPoint'{}, {namedCurve,OID}}, Signature) ->
     CurveName = public_key:oid2ssh_curvename(OID),
-    ssh_bits:encode([<<"ecdsa-sha2-",CurveName/binary>>, Signature], [binary,binary]).
+    <<?Ebinary(<<"ecdsa-sha2-",CurveName/binary>>), ?Ebinary(Signature)>>.
 
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 18037b8461..a648c7af3d 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -52,6 +52,14 @@
 -export([pack/3]).
 -export([decompress/2,  decrypt_blocks/3, is_valid_mac/3 ]). % FIXME: remove
 
+-define(Estring(X), ?STRING((if is_binary(X) -> X;
+				is_list(X) -> list_to_binary(X);
+				X==undefined -> <<>>
+			     end))).
+-define(Empint(X),     (ssh_bits:mpint(X))/binary ).
+-define(Ebinary(X),    ?STRING(X) ).
+-define(Euint32(X),   ?UINT32(X) ).
+
 %%%----------------------------------------------------------------------------
 %%%
 %%% There is a difference between supported and default algorithms. The
@@ -1084,7 +1092,7 @@ sign(SigData, Hash,  #'DSAPrivateKey'{} = Key) ->
 sign(SigData, Hash, Key = #'ECPrivateKey'{}) ->
     DerEncodedSign =  public_key:sign(SigData, Hash, Key),
     #'ECDSA-Sig-Value'{r=R, s=S} = public_key:der_decode('ECDSA-Sig-Value', DerEncodedSign),
-    ssh_bits:encode([R,S], [mpint,mpint]);
+    <<?Empint(R),?Empint(S)>>;
 sign(SigData, Hash, Key) ->
     public_key:sign(SigData, Hash, Key).
 
@@ -1584,21 +1592,16 @@ hash(K, H, Ki, N, HASH) ->
 
 kex_h(SSH, Key, E, F, K) ->
     KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
-    L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version,
-			 SSH#ssh.c_keyinit, SSH#ssh.s_keyinit,
-			 KeyBin, E,F,K],
-			[string,string,binary,binary,binary,
-			 mpint,mpint,mpint]),
+    L = <<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
+	  ?Ebinary(SSH#ssh.c_keyinit), ?Ebinary(SSH#ssh.s_keyinit), ?Ebinary(KeyBin),
+	  ?Empint(E), ?Empint(F), ?Empint(K)>>,
     crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
-%%  crypto:hash(sha,L).
 
 kex_h(SSH, Curve, Key, Q_c, Q_s, K) ->
     KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
-    L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version,
-			 SSH#ssh.c_keyinit, SSH#ssh.s_keyinit,
-			 KeyBin, Q_c, Q_s, K],
-			[string,string,binary,binary,binary,
-			 mpint,mpint,mpint]),
+    L = <<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
+	  ?Ebinary(SSH#ssh.c_keyinit), ?Ebinary(SSH#ssh.s_keyinit), ?Ebinary(KeyBin),
+	  ?Empint(Q_c), ?Empint(Q_s), ?Empint(K)>>,
     crypto:hash(sha(Curve), L).
 
 kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
@@ -1607,21 +1610,14 @@ kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
 		%% flag from 'ssh_msg_kex_dh_gex_request_old'
 		%% It was like this before that message was supported,
 		%% why?
-		Ts = [string,string,binary,binary,binary,
-		      uint32,
-		      mpint,mpint,mpint,mpint,mpint],
-		ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version,
-				 SSH#ssh.c_keyinit,SSH#ssh.s_keyinit,
-				 KeyBin, NBits, Prime, Gen, E,F,K],
-				Ts);
+		<<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
+		  ?Ebinary(SSH#ssh.c_keyinit), ?Ebinary(SSH#ssh.s_keyinit), ?Ebinary(KeyBin),
+		  ?Empint(E), ?Empint(F), ?Empint(K)>>;
 	   true ->
-		Ts = [string,string,binary,binary,binary,
-		      uint32,uint32,uint32,
-		      mpint,mpint,mpint,mpint,mpint],
-		ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version,
-				 SSH#ssh.c_keyinit,SSH#ssh.s_keyinit,
-				 KeyBin, Min, NBits, Max,
-				 Prime, Gen, E,F,K], Ts)
+		<<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
+		  ?Ebinary(SSH#ssh.c_keyinit), ?Ebinary(SSH#ssh.s_keyinit), ?Ebinary(KeyBin),
+		  ?Euint32(Min), ?Euint32(NBits), ?Euint32(Max),
+		  ?Empint(Prime), ?Empint(Gen), ?Empint(E), ?Empint(F), ?Empint(K)>>
 	end,
     crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
   
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index fe197f8672..6b78a32a9b 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -307,7 +307,7 @@ no_common_alg_client_disconnects(Config) ->
 			  {send, hello},
 			  {match, #ssh_msg_kexinit{_='_'}, receive_msg},
 			  {send,  #ssh_msg_kexinit{ % with unsupported "SOME-UNSUPPORTED"
-				     cookie = 247381486335508958743193106082599558706,
+				     cookie = <<80,158,95,51,174,35,73,130,246,141,200,49,180,190,82,234>>,
 				     kex_algorithms = ["diffie-hellman-group1-sha1"],
 				     server_host_key_algorithms = ["SOME-UNSUPPORTED"],  % SIC!
 				     encryption_algorithms_client_to_server = ["aes128-ctr"],
-- 
cgit v1.2.3