ssh_transport.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,781 行 · 第 1/4 页
ERL
1,781 行
encrypt_final(SSH) -> erase(encrypt_ctx), {ok, SSH#ssh { encrypt = none, encrypt_keys = undefined, encrypt_block_size = 8 }}.encrypt(SSH, Data) -> case SSH#ssh.encrypt of none -> Data; '3des-cbc' -> {K1,K2,K3} = SSH#ssh.encrypt_keys, IV0 = get(encrypt_ctx), ?dbg(?DBG_CRYPTO, "encrypt: IV=~p K1=~p, K2=~p, K3=~p\n", [IV0,K1,K2,K3]), Enc = crypto:des3_cbc_encrypt(K1,K2,K3,IV0,Data), ?dbg(?DBG_CRYPTO, "encrypt: ~p -> ~p\n", [Data, Enc]), %% Enc = list_to_binary(E0), IV = crypto:des_cbc_ivec(Enc), put(encrypt_ctx, IV), Enc; _ -> exit({bad_algorithm,SSH#ssh.encrypt}) end.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Decryption%% context stored in dictionary as 'decrypt_ctx'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%decrypt_init(SSH) -> case SSH#ssh.decrypt of none -> {ok,SSH}; '3des-cbc' -> {IV,KD} = case SSH#ssh.role of client -> {hash(SSH, "B", 64), hash(SSH, "D", 192)}; server -> {hash(SSH, "A", 64), hash(SSH, "C", 192)} end, <<K1:8/binary, K2:8/binary, K3:8/binary>> = KD, put(decrypt_ctx, IV), {ok,SSH#ssh{ decrypt_keys = {K1,K2,K3}, decrypt_block_size = 8 }}; _ -> exit({bad_algorithm,SSH#ssh.decrypt}) end.decrypt_final(SSH) -> erase(decrypt_ctx), {ok, SSH#ssh { decrypt = none, decrypt_keys = undefined, decrypt_block_size = 8 }}.decrypt(SSH, Data) -> case SSH#ssh.decrypt of none -> Data; '3des-cbc' -> {K1,K2,K3} = SSH#ssh.decrypt_keys, IV0 = get(decrypt_ctx), ?dbg(?DBG_CRYPTO, "decrypt: IV=~p K1=~p, K2=~p, K3=~p\n", [IV0,K1,K2,K3]), Dec = crypto:des3_cbc_decrypt(K1,K2,K3,IV0,Data), %% Enc = list_to_binary(E0), ?dbg(?DBG_CRYPTO, "decrypt: ~p -> ~p\n", [Data, Dec]), IV = crypto:des_cbc_ivec(Data), put(decrypt_ctx, IV), Dec; _ -> exit({bad_algorithm,SSH#ssh.decrypt}) end.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Compression%% context stored in dictionary as 'compress_ctx'%%%% none REQUIRED no compression%% zlib OPTIONAL ZLIB (LZ77) compression%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%compress_init(SSH) -> compress_init(SSH, 1).compress_init(SSH, Level) -> Compress = SSH#ssh.compress, ?dbg(?DBG_ZLIB, "compress_init: ~p Level ~p\n", [Compress, Level]), case Compress of none -> {ok,SSH}; zlib -> Z = zlib:open(), case zlib:deflateInit(Z, Level) of ok -> put(compress_ctx, Z), {ok, SSH}; Error -> zlib:close(Z), Error end; _ -> exit({bad_algorithm,SSH#ssh.compress}) end.compress_final(SSH) -> case SSH#ssh.compress of none -> {ok, SSH}; zlib -> zlib:close(get(compress_ctx)), erase(compress_ctx), {ok, SSH#ssh { compress = none }}; _ -> exit({bad_algorithm,SSH#ssh.compress}) end.compress(SSH, Data) -> case SSH#ssh.compress of none -> Data; zlib -> Compressed = zlib:deflate(get(compress_ctx), Data, sync), ?dbg(?DBG_ZLIB, "deflate: ~p -> ~p\n", [Data, Compressed]), list_to_binary(Compressed); _ -> exit({bad_algorithm,SSH#ssh.compress}) end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Decompression%% context stored in dictionary as 'decompress_ctx'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%decompress_init(SSH) -> case SSH#ssh.decompress of none -> {ok,SSH}; zlib -> Z = zlib:open(), case zlib:inflateInit(Z) of ok -> put(decompress_ctx, Z), {ok,SSH}; Error -> zlib:close(Z), Error end; _ -> exit({bad_algorithm,SSH#ssh.decompress}) end.decompress_final(SSH) -> case SSH#ssh.decompress of none -> {ok, SSH}; zlib -> zlib:close(get(decompress_ctx)), erase(decompress_ctx), {ok, SSH#ssh { decompress = none }}; _ -> exit({bad_algorithm,SSH#ssh.decompress}) end. decompress(SSH, Data) -> case SSH#ssh.decompress of none -> Data; zlib -> Decompressed = zlib:inflate(get(decompress_ctx), Data), ?dbg(?DBG_ZLIB, "inflate: ~p -> ~p\n", [Data, Decompressed]), list_to_binary(Decompressed); _ -> exit({bad_algorithm,SSH#ssh.decompress}) end.%%%% macs%%%% hmac-sha1 REQUIRED HMAC-SHA1 (digest length = key%% length = 20)%% hmac-sha1-96 RECOMMENDED first 96 bits of HMAC-SHA1 (digest%% length = 12, key length = 20)%% hmac-md5 OPTIONAL HMAC-MD5 (digest length = key%% length = 16)%% hmac-md5-96 OPTIONAL first 96 bits of HMAC-MD5 (digest%% length = 12, key length = 16)%% none OPTIONAL no MAC; NOT RECOMMENDED%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MAC calculation%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%send_mac_init(SSH) -> case SSH#ssh.role of client -> Key = hash(SSH, "E", mac_key_size(SSH#ssh.send_mac)), {ok, SSH#ssh { send_mac_key = Key }}; server -> Key = hash(SSH, "F", mac_key_size(SSH#ssh.send_mac)), {ok, SSH#ssh { send_mac_key = Key }} end.send_mac_final(SSH) -> {ok, SSH#ssh { send_mac = none, send_mac_key = undefined }}.send_mac(SSH, Data, Seq) -> case SSH#ssh.send_mac of none -> <<>>; 'hmac-sha1' -> crypto:sha_mac(SSH#ssh.send_mac_key, [<<?UINT32(Seq)>>, Data]); 'hmac-sha1-96' -> crypto:sha_mac_96(SSH#ssh.send_mac_key, [<<?UINT32(Seq)>>, Data]); 'hmac-md5' -> crypto:md5_mac(SSH#ssh.send_mac_key, [<<?UINT32(Seq)>>, Data]); 'hmac-md5-96' -> crypto:md5_mac_96(SSH#ssh.send_mac_key, [<<?UINT32(Seq)>>, Data]); _ -> exit({bad_algorithm,SSH#ssh.send_mac}) end. recv_mac_init(SSH) -> case SSH#ssh.role of client -> Key = hash(SSH, "F", mac_key_size(SSH#ssh.recv_mac)), {ok, SSH#ssh { recv_mac_key = Key }}; server -> Key = hash(SSH, "E", mac_key_size(SSH#ssh.recv_mac)), {ok, SSH#ssh { recv_mac_key = Key }} end.recv_mac_final(SSH) -> {ok, SSH#ssh { recv_mac = none, recv_mac_key = undefined }}.recv_mac(SSH, Data, Seq) -> case SSH#ssh.recv_mac of none -> <<>>; 'hmac-sha1' -> crypto:sha_mac(SSH#ssh.recv_mac_key, [<<?UINT32(Seq)>>, Data]); 'hmac-sha1-96' -> crypto:sha_mac_96(SSH#ssh.recv_mac_key, [<<?UINT32(Seq)>>, Data]); 'hmac-md5' -> crypto:md5_mac(SSH#ssh.recv_mac_key, [<<?UINT32(Seq)>>, Data]); 'hmac-md5-96' -> crypto:md5_mac_96(SSH#ssh.recv_mac_key, [<<?UINT32(Seq)>>, Data]); _ -> exit({bad_algorithm,SSH#ssh.recv_mac}) end.%% return N hash bytes (HASH)hash(SSH, Char, Bits) -> HASH = case SSH#ssh.kex of 'diffie-hellman-group1-sha1' -> fun(Data) -> crypto:sha(Data) end; 'diffie-hellman-group-exchange-sha1' -> fun(Data) -> crypto:sha(Data) end; _ -> exit({bad_algorithm,SSH#ssh.kex}) end, hash(SSH, Char, Bits, HASH).hash(_SSH, _Char, 0, _HASH) -> <<>>;hash(SSH, Char, N, HASH) -> K = ssh_bits:mpint(SSH#ssh.shared_secret), H = SSH#ssh.exchanged_hash, SessionID = SSH#ssh.session_id, K1 = HASH([K, H, Char, SessionID]), Sz = N div 8, <<Key:Sz/binary, _/binary>> = hash(K, H, K1, N-128, HASH), ?dbg(?DBG_KEX, "Key ~s: ~s\n", [Char, fmt_binary(Key, 16, 4)]), Key.hash(_K, _H, Ki, N, _HASH) when N =< 0 -> Ki;hash(K, H, Ki, N, HASH) -> Kj = HASH([K, H, Ki]), hash(K, H, <<Ki/binary, Kj/binary>>, N-128, HASH).%%%% calcuation of H (diffie-hellman-group1-sha1)%% Must use ssh#ssh.algorithms here because new algorithms%% are not install at this point%%kex_h(SSH, K_S, E, F, K) -> L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version, SSH#ssh.c_keyinit, SSH#ssh.s_keyinit, K_S, E,F,K], [string,string,string,string,string, mpint,mpint,mpint]), crypto:sha(L).kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) -> L = if Min==-1; Max==-1 -> Ts = [string,string,string,string,string, 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, K_S, NBits, Prime, Gen, E,F,K], Ts); true -> Ts = [string,string,string,string,string, 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, K_S, Min, NBits, Max, Prime, Gen, E,F,K], Ts) end, crypto:sha(L). mac_key_size('hmac-sha1') -> 20*8;mac_key_size('hmac-sha1-96') -> 20*8;mac_key_size('hmac-md5') -> 16*8;mac_key_size('hmac-md5-96') -> 16*8;mac_key_size(none) -> 0;mac_key_size(_) -> exit(bad_algoritm).mac_digest_size('hmac-sha1') -> 20;mac_digest_size('hmac-sha1-96') -> 12;mac_digest_size('hmac-md5') -> 20;mac_digest_size('hmac-md5-96') -> 12;mac_digest_size(none) -> 0;mac_digest_size(_) -> exit(bad_algoritm).%% integrity_char(send, client) -> "E";%% integrity_char(recv, server) -> "E";%% integrity_char(send, server) -> "F";%% integrity_char(recv, client) -> "F". valid_mac(SSH, S, Data, Seq) -> if SSH#ssh.recv_mac_size == 0 -> true; true -> {ok,MAC0} = gen_tcp:recv(S, SSH#ssh.recv_mac_size), ?dbg(?DBG_MAC, "~p: MAC0=~p\n", [Seq, MAC0]), MAC1 = recv_mac(SSH, Data, Seq), ?dbg(?DBG_MAC, "~p: MAC1=~p\n", [Seq, MAC1]), MAC0 == MAC1 end.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Diffie-Hellman utils%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%dh_group1() -> {2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF}.dh_gen_key(G,P, _Bits) -> Private = ssh_bits:irandom(ssh_bits:isize(P)-1, 1, 1), Public = ssh_math:ipow(G, Private, P), {Private,Public}.%% trim(Str) ->%% reverse(trim_head(reverse(trim_head(Str)))).trim_tail(Str) -> reverse(trim_head(reverse(Str))).trim_head([$\s|Cs]) -> trim_head(Cs);trim_head([$\t|Cs]) -> trim_head(Cs);trim_head([$\n|Cs]) -> trim_head(Cs);trim_head([$\r|Cs]) -> trim_head(Cs);trim_head(Cs) -> Cs.%%%% DEBUG utils%% Format integers and binaries as hex blocks%%-ifdef(debug).%% fmt_binary(B) ->%% fmt_binary(B, 0, 0).%% fmt_binary(B, BlockSize) ->%% fmt_binary(B, BlockSize, 0).fmt_binary(B, BlockSize, GroupSize) -> fmt_block(fmt_bin(B), BlockSize, GroupSize).fmt_block(Bin, BlockSize, GroupSize) -> fmt_block(Bin, BlockSize, 0, GroupSize). fmt_block(Bin, 0, _I, _G) -> binary_to_list(Bin);fmt_block(Bin, Sz, G, G) when G =/= 0 -> ["\n" | fmt_block(Bin, Sz, 0, G)];fmt_block(Bin, Sz, I, G) -> case Bin of <<Block:Sz/binary, Tail/binary>> -> if Tail == <<>> -> [binary_to_list(Block)]; true -> [binary_to_list(Block), " " | fmt_block(Tail, Sz, I+1, G)] end; <<>> -> []; _ -> [binary_to_list(Bin)] end.%% Format integer or binary as hexfmt_bin(X) when integer(X) -> list_to_binary(io_lib:format("~.16B", [X]));fmt_bin(X) when binary(X) -> Sz = size(X)*8, <<Y:Sz/unsigned-big>> = X, Fmt = "~"++integer_to_list(size(X)*2)++".16.0B", list_to_binary(io_lib:format(Fmt, [Y])).-endif.%% Retrieve session_id from ssh, needed by public-key authget_session_id(SSH) -> {ok, SessionID} = call(SSH, get_session_id), SessionID.await_user(User) -> receive {User, ok} -> ok after ?DEFAULT_TIMEOUT -> error end.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?