aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh/src/ssh_bits.erl
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2017-08-30 20:55:08 +0200
committerSverker Eriksson <[email protected]>2017-08-30 20:55:08 +0200
commit7c67bbddb53c364086f66260701bc54a61c9659c (patch)
tree92ab0d4b91d5e2f6e7a3f9d61ea25089e8a71fe0 /lib/ssh/src/ssh_bits.erl
parent97dc5e7f396129222419811c173edc7fa767b0f8 (diff)
parent3b7a6ffddc819bf305353a593904cea9e932e7dc (diff)
downloadotp-7c67bbddb53c364086f66260701bc54a61c9659c.tar.gz
otp-7c67bbddb53c364086f66260701bc54a61c9659c.tar.bz2
otp-7c67bbddb53c364086f66260701bc54a61c9659c.zip
Merge tag 'OTP-19.0' into sverker/19/binary_to_atom-utf8-crash/ERL-474/OTP-14590
Diffstat (limited to 'lib/ssh/src/ssh_bits.erl')
-rw-r--r--lib/ssh/src/ssh_bits.erl398
1 files changed, 31 insertions, 367 deletions
diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl
index fc6efc817f..8bedaaf0c5 100644
--- a/lib/ssh/src/ssh_bits.erl
+++ b/lib/ssh/src/ssh_bits.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
%%
%% %CopyrightEnd%
%%
@@ -25,62 +26,30 @@
-include("ssh.hrl").
--export([encode/1, encode/2]).
--export([decode/1, decode/2, decode/3]).
--export([mpint/1, bignum/1, string/1, name_list/1]).
--export([b64_encode/1, b64_decode/1]).
--export([install_messages/1, uninstall_messages/1]).
-
-%% integer utils
--export([isize/1]).
+-export([mpint/1, name_list/1]).
-export([random/1]).
--export([xor_bits/2, fill_bits/2]).
--export([i2bin/2, bin2i/1]).
-
--import(lists, [foreach/2, reverse/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]).
@@ -89,322 +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]).
-%% BIGNUM representation SSH1
-bignum(X) ->
- XSz = isize(X),
- Pad = (8 - (XSz rem 8)) rem 8,
- <<?UINT16(XSz),0:Pad/unsigned-integer,X:XSz/big-unsigned-integer>>.
-
-
-install_messages(Codes) ->
- foreach(fun({Name, Code, Ts}) ->
- put({msg_name,Code}, {Name,Ts}),
- put({msg_code,Name}, {Code,Ts})
- end, Codes).
-
-uninstall_messages(Codes) ->
- foreach(fun({Name, Code, _Ts}) ->
- erase({msg_name,Code}),
- erase({msg_code,Name})
- end, Codes).
-
-%%
-%% Encode a record, the type spec is expected to be
-%% in process dictionary under the key {msg_code, RecodeName}
-%%
-encode(Record) ->
- case get({msg_code, element(1, Record)}) of
- undefined ->
- {error, unimplemented};
- {Code, Ts} ->
- Data = enc(tl(tuple_to_list(Record)), Ts),
- list_to_binary([Code, Data])
- end.
-
-encode(List, Types) ->
- list_to_binary(enc(List, Types)).
-
-%%
-%% Encode record element
-%%
-enc(Xs, Ts) ->
- enc(Xs, Ts, 0).
-
-enc(Xs, [Type|Ts], Offset) ->
- case Type of
- boolean ->
- X=hd(Xs),
- [?boolean(X) | enc(tl(Xs), Ts, Offset+1)];
- byte ->
- X=hd(Xs),
- [?byte(X) | enc(tl(Xs), Ts,Offset+1)];
- uint16 ->
- X=hd(Xs),
- [?uint16(X) | enc(tl(Xs), Ts,Offset+2)];
- uint32 ->
- X=hd(Xs),
- [?uint32(X) | enc(tl(Xs), Ts,Offset+4)];
- uint64 ->
- X=hd(Xs),
- [?uint64(X) | enc(tl(Xs), Ts,Offset+8)];
- mpint ->
- Y=mpint(hd(Xs)),
- [Y | enc(tl(Xs), Ts,Offset+size(Y))];
- bignum ->
- Y=bignum(hd(Xs)),
- [Y | enc(tl(Xs),Ts,Offset+size(Y))];
- string ->
- X0=hd(Xs),
- Y=?string(X0),
- [Y | enc(tl(Xs),Ts,Offset+size(Y))];
- binary ->
- X0=hd(Xs),
- Y=?binary(X0),
- [Y | enc(tl(Xs), Ts,Offset+size(Y))];
- name_list ->
- X0=hd(Xs),
- Y=?name_list(X0),
- [Y | enc(tl(Xs), Ts, Offset+size(Y))];
- cookie ->
- [random(16) | enc(tl(Xs), Ts, Offset+16)];
- {pad,N} ->
- K = (N - (Offset rem N)) rem N,
- [fill_bits(K,0) | enc(Xs, Ts, Offset+K)];
- '...' when Ts==[] ->
- X=hd(Xs),
- if is_binary(X) ->
- [X];
- is_list(X) ->
- [list_to_binary(X)];
- X==undefined ->
- []
- end
- end;
-enc([], [],_) ->
- [].
-
-
-
-%%
-%% Decode a SSH record the type is encoded as the first byte
-%% and the type spec MUST be installed in {msg_name, ID}
-%%
-
-decode(Binary = <<?BYTE(ID), _/binary>>) ->
- case get({msg_name, ID}) of
- undefined ->
- {unknown, Binary};
- {Name, Ts} ->
- {_, Elems} = decode(Binary,1,Ts),
- list_to_tuple([Name | Elems])
- end.
-
-%%
-%% Decode a binary form offset 0
-%%
-
-decode(Binary, Types) when is_binary(Binary) andalso is_list(Types) ->
- {_,Elems} = decode(Binary, 0, Types),
- Elems.
-
-
-%%
-%% Decode a binary from byte offset Offset
-%% return {UpdatedOffset, DecodedElements}
-%%
-decode(Binary, Offset, Types) ->
- decode(Binary, Offset, Types, []).
-
-decode(Binary, Offset, [Type|Ts], Acc) ->
- case Type of
- boolean ->
- <<_:Offset/binary, ?BOOLEAN(X0), _/binary>> = Binary,
- X = if X0 == 0 -> false; true -> true end,
- decode(Binary, Offset+1, Ts, [X | Acc]);
-
- byte ->
- <<_:Offset/binary, ?BYTE(X), _/binary>> = Binary,
- decode(Binary, Offset+1, Ts, [X | Acc]);
-
- uint16 ->
- <<_:Offset/binary, ?UINT16(X), _/binary>> = Binary,
- decode(Binary, Offset+2, Ts, [X | Acc]);
-
- uint32 ->
- <<_:Offset/binary, ?UINT32(X), _/binary>> = Binary,
- decode(Binary, Offset+4, Ts, [X | Acc]);
-
- uint64 ->
- <<_:Offset/binary, ?UINT64(X), _/binary>> = Binary,
- decode(Binary, Offset+8, Ts, [X | Acc]);
-
- mpint ->
- <<_:Offset/binary, ?UINT32(L), X0:L/binary,_/binary>> = Binary,
- Sz = L*8,
- <<X:Sz/big-signed-integer>> = X0,
- decode(Binary, Offset+4+L, Ts, [X | Acc]);
-
- bignum ->
- <<_:Offset/binary, ?UINT16(Bits),_/binary>> = Binary,
- L = (Bits+7) div 8,
- Pad = (8 - (Bits rem 8)) rem 8,
- <<_:Offset/binary, _:16, _:Pad, X:Bits/big-unsigned-integer,
- _/binary>> = Binary,
- decode(Binary, Offset+2+L, Ts, [X | Acc]);
-
- string ->
- Size = size(Binary),
- if Size < Offset + 4 ->
- %% empty string at end
- {Size, reverse(["" | Acc])};
- true ->
- <<_:Offset/binary,?UINT32(L), X:L/binary,_/binary>> =
- Binary,
- decode(Binary, Offset+4+L, Ts, [binary_to_list(X) |
- Acc])
- end;
-
- binary ->
- <<_:Offset/binary,?UINT32(L), X:L/binary,_/binary>> = Binary,
- decode(Binary, Offset+4+L, Ts, [X | Acc]);
-
- name_list ->
- <<_:Offset/binary,?UINT32(L), X:L/binary,_/binary>> = Binary,
- List = string:tokens(binary_to_list(X), ","),
- decode(Binary, Offset+4+L, Ts, [List | Acc]);
-
- cookie ->
- <<_:Offset/binary, X:16/binary, _/binary>> = Binary,
- decode(Binary, Offset+16, Ts, [X | Acc]);
-
- {pad,N} -> %% pad offset to a multiple of N
- K = (N - (Offset rem N)) rem N,
- decode(Binary, Offset+K, Ts, Acc);
-
-
- '...' when Ts==[] ->
- <<_:Offset/binary, X/binary>> = Binary,
- {Offset+size(X), reverse([X | Acc])}
- end;
-decode(_Binary, Offset, [], Acc) ->
- {Offset, reverse(Acc)}.
-
-
-
-%% HACK WARNING :-)
--define(VERSION_MAGIC, 131).
--define(SMALL_INTEGER_EXT, $a).
--define(INTEGER_EXT, $b).
--define(SMALL_BIG_EXT, $n).
--define(LARGE_BIG_EXT, $o).
-
-isize(N) when N > 0 ->
- case term_to_binary(N) of
- <<?VERSION_MAGIC, ?SMALL_INTEGER_EXT, X>> ->
- isize_byte(X);
- <<?VERSION_MAGIC, ?INTEGER_EXT, X3,X2,X1,X0>> ->
- isize_bytes([X3,X2,X1,X0]);
- <<?VERSION_MAGIC, ?SMALL_BIG_EXT, S:8/big-unsigned-integer, 0,
- Ds:S/binary>> ->
- K = S - 1,
- <<_:K/binary, Top>> = Ds,
- isize_byte(Top)+K*8;
- <<?VERSION_MAGIC, ?LARGE_BIG_EXT, S:32/big-unsigned-integer, 0,
- Ds:S/binary>> ->
- K = S - 1,
- <<_:K/binary, Top>> = Ds,
- isize_byte(Top)+K*8
- end;
-isize(0) -> 0.
-
-%% big endian byte list
-isize_bytes([0|L]) ->
- isize_bytes(L);
-isize_bytes([Top|L]) ->
- isize_byte(Top) + length(L)*8.
-
-%% Well could be improved
-isize_byte(X) ->
- if X >= 2#10000000 -> 8;
- X >= 2#1000000 -> 7;
- X >= 2#100000 -> 6;
- X >= 2#10000 -> 5;
- X >= 2#1000 -> 4;
- X >= 2#100 -> 3;
- X >= 2#10 -> 2;
- X >= 2#1 -> 1;
- true -> 0
- end.
-
-%% Convert integer into binary
-%% When XLen is the wanted size in octets of the output
-i2bin(X, XLen) ->
- XSz = isize(X),
- Sz = XLen*8,
- if Sz < XSz ->
- exit(integer_to_large);
- true ->
- (<<X:Sz/big-unsigned-integer>>)
- end.
-
-%% Convert a binary into an integer
-%%
-bin2i(X) ->
- Sz = size(X)*8,
- <<Y:Sz/big-unsigned-integer>> = X,
- Y.
-
-%%
-%% 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.
-
-%% xor 2 binaries
-xor_bits(XBits, YBits) ->
- XSz = size(XBits)*8,
- YSz = size(YBits)*8,
- Sz = if XSz < YSz -> XSz; true -> YSz end, %% min
- <<X:Sz, _/binary>> = XBits,
- <<Y:Sz, _/binary>> = YBits,
- <<(X bxor Y):Sz>>.
-
-
+%%%----------------------------------------------------------------
%% random/1
%% Generate N random bytes
%%
-random(N) ->
- crypto:strong_rand_bytes(N).
-
-%%
-%% Base 64 encode/decode
-%%
-
-b64_encode(Bs) when is_list(Bs) ->
- base64:encode(Bs);
-b64_encode(Bin) when is_binary(Bin) ->
- base64:encode(Bin).
+random(N) -> crypto:strong_rand_bytes(N).
-b64_decode(Bin) when is_binary(Bin) ->
- base64:mime_decode(Bin);
-b64_decode(Cs) when is_list(Cs) ->
- base64:mime_decode(Cs).