ssh_bits.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 510 行

ERL
510
字号
%% ``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 via the world wide web at http://www.erlang.org/.%% %% 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.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%%%% Description : SSH 1/2 pdu elements encode/decode-module(ssh_bits).-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([irandom/1, irandom/3]).-export([random/1, random/3]).-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 atom(Name) -> atom_to_list(Name);name_concat([Name]) when list(Name) -> Name;name_concat([Name|Ns]) ->     if atom(Name) ->	    [atom_to_list(Name),"," | name_concat(Ns)];       list(Name) ->	    [Name,"," | name_concat(Ns)]    end;name_concat([]) -> [].name_list(Ns) ->    ?name_list(Ns).    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>>)    end;mpint_neg(X,I,Ds)  ->    mpint_neg(X bsr 8,I+1,[(X band 255)|Ds]).    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>>)    end;mpint_pos(X,I,Ds) ->    mpint_pos(X bsr 8,I+1,[(X band 255)|Ds]).%% BIGNUM representation SSH1bignum(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}) ->		    ?dbg(true, "install msg: ~s = ~w ~w\n", 			 [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}) ->		    ?dbg(true, "uninstall msg: ~s = ~w ~w\n", 			 [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=?string(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 binary(X) -> 		    [X];	       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 -> 	    {error, unimplemented};	{Name, Ts} ->	    {_, Elems} = decode(Binary,1,Ts),	    {ok,list_to_tuple([Name | Elems])}    end.%%%% Decode a binary form offset 0%%decode(Binary, Types) when binary(Binary), 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 ->	    <<_:Offset/binary,?UINT32(L), X:L/binary,_/binary>> = Binary,	    decode(Binary, Offset+4+L, Ts, [binary_to_list(X) | Acc]);	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 listisize_bytes([0|L]) ->    isize_bytes(L);isize_bytes([Top|L]) ->    isize_byte(Top) + length(L)*8.%% Well could be improvedisize_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 outputi2bin(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 binariesxor_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>>.%%%% irandom(N)%%%%  Generate a N bits size random number%%  note that the top most bit is always set%%  to guarantee that the number is N bits%%irandom(Bits) ->    irandom(Bits, 1, 0).%% irandom_odd(Bits) ->%%     irandom(Bits, 1, 1).%%%% irandom(N, Top, Bottom)%%%%  Generate a N bits size random number%% Where Top = 0 - do not set top bit%%           = 1 - set the most significant bit%%           = 2 - set two most significant bits%%       Bot = 0 - do not set the least signifcant bit%%       Bot = 1 - set the least signifcant bit (i.e always odd)%%irandom(0, _Top, _Bottom) ->     0;irandom(Bits, Top, Bottom) ->    Bytes = (Bits+7) div 8,    Skip  = (8-(Bits rem 8)) rem 8,    TMask = case Top of		  0 -> 0;		  1 -> 16#80;		  2 -> 16#c0	      end,    BMask = case Bottom of		0 -> 0;		1 -> (1 bsl Skip)	    end,    <<X:Bits/big-unsigned-integer, _:Skip>> = random(Bytes, TMask, BMask),    X.%%%% random/1%%   Generate N random bytes%%random(N) ->    random(N, 0, 0).random(N, TMask, BMask) ->    list_to_binary(rnd(N, TMask, BMask)).%% random/3%%   random(Bytes, TopMask, BotMask)%% where %% Bytes is the number of bytes to generate%% TopMask is bitwised or'ed to the first byte%% BotMask is bitwised or'ed to the last byte%%rnd(0, _TMask, _BMask) ->    [];rnd(1, TMask, BMask) ->    [(rand8() bor TMask) bor BMask];rnd(N, TMask, BMask) ->    [(rand8() bor TMask) | rnd_n(N-1, BMask)].rnd_n(1, BMask) ->    [rand8() bor BMask];rnd_n(I, BMask) ->    [rand8() | rnd_n(I-1, BMask)].rand8() ->    (rand32() bsr 8) band 16#ff.rand32() ->    random:uniform(16#100000000) -1.%%%% Base 64 encode/decode%%b64_encode(Bs) when list(Bs) ->     b64_enc(list_to_binary(Bs));    b64_encode(Bin) when binary(Bin) ->    b64_enc(Bin).b64_enc(<<C1:6, C2:6, C3:6, C4:6, Bs/binary>>) ->    [b64e(C1), b64e(C2), b64e(C3), b64e(C4)| b64_enc(Bs)];b64_enc(<<B:2/binary>>) ->    <<C1:6, C2:6, C3:6, _:6>> = <<B/binary, 0>>,    [b64e(C1), b64e(C2), b64e(C3), $=];b64_enc(<<B:1/binary>>) ->    <<C1:6, C2:6, _:4>> = <<B/binary, 0>>,    [b64e(C1), b64e(C2), $=, $=];b64_enc(<<>>) ->    [].b64e(C) when C =< 25 -> C+$A;b64e(C) when C =< 51 -> (C-26)+$a;b64e(C) when C =< 61 -> (C-52)+$0;b64e(62) -> $+;b64e(63) -> $/.b64_decode(Bin) when binary(Bin) ->     list_to_binary(b64_dec(binary_to_list(Bin)));b64_decode(Cs) when list(Cs) ->     list_to_binary(b64_dec(Cs)).b64_dec([$\s|Cs]) -> b64_dec(Cs);b64_dec([$\t|Cs]) -> b64_dec(Cs);b64_dec([$\r,$\n|Cs]) -> b64_dec(Cs);b64_dec([$\n|Cs]) -> b64_dec(Cs);b64_dec([C1,C2,$=,$=|_]) ->    <<B1, _:16>> = <<(b64d(C1)):6, (b64d(C2)):6, 0:12>>,    [B1];b64_dec([C1,C2,C3,$=|_]) ->    <<B1, B2, _:8>> = <<(b64d(C1)):6,(b64d(C2)):6,(b64d(C3)):6, 0:6>>,    [B1, B2];b64_dec([C1,C2,C3,C4| Cs]) ->    Bin = <<(b64d(C1)):6, (b64d(C2)):6, (b64d(C3)):6, (b64d(C4)):6>>,    [Bin| b64_dec(Cs)];b64_dec([]) ->    [].b64d(C) when C >= $A, C =< $Z -> C-$A;b64d(C) when C >= $a, C =< $z -> (C-$a)+26;b64d(C) when C >= $0, C =< $9 -> (C-$0)+52;b64d($+) -> 62;b64d($/) -> 63.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?