Current section
7 Versions
Jump to
Current section
7 Versions
Compare versions
9
files changed
+334
additions
-126
deletions
| @@ -1,24 +1,51 @@ | |
| 1 | - # Mtproto |
| 1 | + ### [MTProto](https://core.telegram.org/mtproto) transport for Elixir [](https://hex.pm/packages/mtproto) [](https://travis-ci.org/ccsteam/mtproto) [](https://coveralls.io/github/ccsteam/mtproto?branch=master) |
| 2 2 | |
| 3 | - **TODO: Add description** |
| 3 | + --- |
| 4 | + |
| 5 | + MTProto (protocol) transport implementation in Elixir, acts like gen_tcp and others, supports most service commands. |
| 6 | + |
| 7 | + --- |
| 8 | + |
| 9 | + ### TODO |
| 10 | + |
| 11 | + * Tests, more testing; |
| 12 | + * Add checks for numbers in DH algorithm; |
| 13 | + * Checks for salts and nonce hashes during authorization; |
| 14 | + * Data Center migration; |
| 15 | + * Fix handling msg_seqno (?). |
| 16 | + |
| 17 | + --- |
| 4 18 | |
| 5 19 | ## Installation |
| 6 20 | |
| 7 | - If [available in Hex](https://hex.pm/docs/publish), the package can be installed as: |
| 21 | + 1. Add `mtproto` to your list of dependencies in `mix.exs`: |
| 8 22 | |
| 9 | - 1. Add `mtproto` to your list of dependencies in `mix.exs`: |
| 23 | + ```elixir |
| 24 | + def deps do |
| 25 | + [{:mtproto, "~> 57.0.0-alpha"}] |
| 26 | + end |
| 27 | + ``` |
| 10 28 | |
| 11 | - ```elixir |
| 12 | - def deps do |
| 13 | - [{:mtproto, "~> 0.1.0"}] |
| 14 | - end |
| 15 | - ``` |
| 29 | + 2. Ensure `mtproto` is started before your application: |
| 16 30 | |
| 17 | - 2. Ensure `mtproto` is started before your application: |
| 31 | + ```elixir |
| 32 | + def application do |
| 33 | + [applications: [:mtproto]] |
| 34 | + end |
| 35 | + ``` |
| 18 36 | |
| 19 | - ```elixir |
| 20 | - def application do |
| 21 | - [applications: [:mtproto]] |
| 22 | - end |
| 23 | - ``` |
| 37 | + --- |
| 24 38 | |
| 39 | + ### Usage |
| 40 | + |
| 41 | + ... |
| 42 | + |
| 43 | + --- |
| 44 | + |
| 45 | + ### Contributing |
| 46 | + |
| 47 | + 1. Fork it |
| 48 | + 2. Create your feature branch (`git checkout -b my-new-feature`) |
| 49 | + 3. Commit your changes (`git commit -am 'add some feature'`) |
| 50 | + 4. Push to the branch (`git push origin my-new-feature`) |
| 51 | + 5. Create new Pull Request |
| @@ -1,11 +1,12 @@ | |
| 1 1 | {<<"app">>,<<"mtproto">>}. |
| 2 2 | {<<"build_tools">>,[<<"mix">>]}. |
| 3 | - {<<"description">>,<<"TL language parser for Elixir">>}. |
| 3 | + {<<"description">>,<<"MTProto transport for Elixir">>}. |
| 4 4 | {<<"elixir">>,<<"~> 1.3">>}. |
| 5 5 | {<<"files">>, |
| 6 6 | [<<"lib/mtproto.ex">>,<<"lib/mtproto/auth.ex">>,<<"lib/mtproto/crypto.ex">>, |
| 7 | - <<"lib/mtproto/math.ex">>,<<"lib/mtproto/packet.ex">>, |
| 8 | - <<"priv/server_public.key">>,<<"mix.exs">>,<<"README.md">>]}. |
| 7 | + <<"lib/mtproto/dc.ex">>,<<"lib/mtproto/math.ex">>, |
| 8 | + <<"lib/mtproto/packet.ex">>,<<"priv/server_public.key">>,<<"mix.exs">>, |
| 9 | + <<"README.md">>]}. |
| 9 10 | {<<"licenses">>,[<<"MIT">>]}. |
| 10 11 | {<<"links">>,[{<<"GitHub">>,<<"https://github.com/ccsteam/mtproto">>}]}. |
| 11 12 | {<<"maintainers">>,[<<"Yuri Artemev">>,<<"Alexander Malaev">>]}. |
| @@ -18,5 +19,5 @@ | |
| 18 19 | [{<<"app">>,<<"tl">>}, |
| 19 20 | {<<"name">>,<<"tl">>}, |
| 20 21 | {<<"optional">>,false}, |
| 21 | - {<<"requirement">>,<<"~> 57.0.0-beta">>}]]}. |
| 22 | - {<<"version">>,<<"0.1.0-alpha">>}. |
| 22 | + {<<"requirement">>,<<"~> 57.1.0-rc">>}]]}. |
| 23 | + {<<"version">>,<<"57.0.0-alpha">>}. |
| @@ -3,10 +3,10 @@ defmodule MTProto do | |
| 3 3 | |
| 4 4 | require Logger |
| 5 5 | |
| 6 | - alias MTProto.{Auth, Crypto, Packet} |
| 6 | + alias MTProto.{Auth, Crypto, DC, Packet} |
| 7 7 | |
| 8 | - def start_link(notifier_pid) do |
| 9 | - Connection.start_link(__MODULE__, [notifier: notifier_pid]) |
| 8 | + def start_link(opts) do |
| 9 | + Connection.start_link(__MODULE__, opts) |
| 10 10 | end |
| 11 11 | |
| 12 12 | def notifier_process(client, notifier_pid) do |
| @@ -25,11 +25,11 @@ defmodule MTProto do | |
| 25 25 | Connection.call(client, {:send, request}) |
| 26 26 | end |
| 27 27 | |
| 28 | - def dump_state(client) do |
| 29 | - Connection.call(client, :dump_state) |
| 28 | + def close(client) do |
| 29 | + Connection.call(client, :close) |
| 30 30 | end |
| 31 31 | |
| 32 | - # ... |
| 32 | + # gen_server callbacks |
| 33 33 | |
| 34 34 | defmodule State do |
| 35 35 | @moduledoc """ |
| @@ -54,7 +54,8 @@ defmodule MTProto do | |
| 54 54 | :msg_seqno - used for storing message sequence number, for using in MTProto packets; |
| 55 55 | :msg_ids - list of message IDs, using for server acks; |
| 56 56 | :dc_options - list of telegram datacenters; |
| 57 | - :dc - current datacenter ID. |
| 57 | + :dc - current datacenter ID; |
| 58 | + :reconnect - reconnect state, see MTProto.DC for details. |
| 58 59 | """ |
| 59 60 | defstruct [:notifier, :socket, |
| 60 61 | :packet_buffer, |
| @@ -62,7 +63,8 @@ defmodule MTProto do | |
| 62 63 | :auth_state, :auth_params, |
| 63 64 | :auth_key, :auth_key_hash, :server_salt, |
| 64 65 | :msg_seqno, :msg_ids, |
| 65 | - :dc_options, :dc] |
| 66 | + :dc_options, :dc, |
| 67 | + :reconnect] |
| 66 68 | end |
| 67 69 | |
| 68 70 | defmodule AuthParams do |
| @@ -70,37 +72,44 @@ defmodule MTProto do | |
| 70 72 | end |
| 71 73 | |
| 72 74 | def init(opts) do |
| 75 | + notifier = opts[:notifier] |
| 76 | + session_id = Keyword.get(opts, :session_id, Crypto.make_session_id) |
| 77 | + msg_seqno = Keyword.get(opts, :msg_seqno, 0) |
| 78 | + |
| 73 79 | {:connect, :init, |
| 74 | - %State{notifier: opts[:notifier], packet_buffer: <<>>, |
| 75 | - msg_seqno: 0, msg_ids: []}} |
| 80 | + %State{auth_state: :connected, notifier: opts[:notifier], packet_buffer: <<>>, |
| 81 | + session_id: session_id, msg_seqno: msg_seqno, msg_ids: []}} |
| 76 82 | end |
| 77 83 | |
| 78 | - def connect(_, %{socket: nil,} = state) do |
| 84 | + def connect(_, %{socket: nil} = state) do |
| 79 85 | {host, port} = choose_server(state) |
| 80 86 | Logger.debug("connect to #{inspect host}, #{inspect port}") |
| 81 87 | |
| 82 88 | case :gen_tcp.connect(host, port, [:binary, active: false], 5000) do |
| 83 89 | {:ok, socket} -> |
| 84 | - Logger.debug("connected") |
| 85 90 | send(self, :after_connect) |
| 86 | - send(state.notifier, :connected) |
| 87 | - session_id = Crypto.make_session_id() |
| 88 | - {:ok, %{state|socket: socket, session_id: session_id, auth_state: :connected}} |
| 91 | + send_to_notifier(state, {:connected, host, port}) |
| 92 | + {:ok, %{state|socket: socket}} |
| 89 93 | {:error, _} -> |
| 90 94 | {:backoff, 1000, state} |
| 91 95 | end |
| 92 96 | end |
| 93 97 | |
| 98 | + def disconnect({:close, _from}, %{socket: socket} = state) do |
| 99 | + :ok = :gen_tcp.close(socket) |
| 100 | + {:stop, :normal, state} |
| 101 | + end |
| 102 | + def disconnect({:reconnect, reason}, %{socket: socket} = state) do |
| 103 | + Logger.debug("need to reconnect #{inspect reason}") |
| 104 | + :ok = :gen_tcp.close(socket) |
| 105 | + {:connect, :reconnect, %{state|socket: nil}} |
| 106 | + end |
| 94 107 | def disconnect(info, %{socket: socket} = state) do |
| 95 108 | Logger.debug("disconnected #{inspect info}") |
| 96 109 | :ok = :gen_tcp.close(socket) |
| 97 | - :error_logger.format("Connection error: ~p~n", [info]) |
| 98 | - {:connect, :reconnect, %{state | socket: nil}} |
| 110 | + {:connect, :reconnect, %{state|socket: nil}} |
| 99 111 | end |
| 100 112 | |
| 101 | - def handle_call(:dump_state, _, state) do |
| 102 | - {:reply, state, state} |
| 103 | - end |
| 104 113 | def handle_call(:authorize, _, state) do |
| 105 114 | # init MTProto authorization |
| 106 115 | state = Auth.init(self(), state) |
| @@ -144,17 +153,32 @@ defmodule MTProto do | |
| 144 153 | |
| 145 154 | Logger.debug("connection ok!") |
| 146 155 | |
| 147 | - {:noreply, state} |
| 156 | + # TODO migrate to another DC |
| 157 | + # if we tried to reconnect |
| 158 | + # state = |
| 159 | + # case state.reconnect do |
| 160 | + # {:dc, dc_id} -> |
| 161 | + # # auth_key used from %TL.Auth.ExportedAuthorization{id: user_id, bytes: auth_key} |
| 162 | + # %TL.Auth.ImportAuthorization{id: user_id, bytes: auth_key} |
| 163 | + # _ -> |
| 164 | + # state |
| 165 | + # end |
| 166 | + |
| 167 | + if state.auth_key && state.auth_key_hash && state.server_salt do |
| 168 | + send(self, :authorized) |
| 169 | + end |
| 170 | + |
| 171 | + {:noreply, %{state|reconnect: nil}} |
| 172 | + end |
| 173 | + def handle_info({:reconnect, {:change_dc, dc_id} = reason}, state) do |
| 174 | + Logger.debug("migrate to DC##{dc_id}") |
| 175 | + {:disconnect, {:reconnect, reason}, %{state|reconnect: {:dc, dc_id}}} |
| 148 176 | end |
| 149 177 | def handle_info({:reconnect, reason}, state) do |
| 150 178 | Logger.debug("reconnect #{inspect reason}") |
| 151 | - {:disconnect, {:reconnect, reason}, state} |
| 179 | + {:disconnect, {:reconnect, reason}, %{state|reconnect: :random}} |
| 152 180 | end |
| 153 181 | def handle_info(:authorized, %{socket: socket} = state) do |
| 154 | - # notify about authorization result |
| 155 | - send(state.notifier, |
| 156 | - {:authorized, state.auth_key, state.auth_key_hash, state.server_salt}) |
| 157 | - |
| 158 182 | # init connection |
| 159 183 | case send_rpc_request(socket, init_connection_request(), state) do |
| 160 184 | {:ok, state} -> {:noreply, state} |
| @@ -176,11 +200,8 @@ defmodule MTProto do | |
| 176 200 | {:noreply, %{state|packet_buffer: incomplete_packet}} |
| 177 201 | {:ok, packet, rest} -> |
| 178 202 | state = %{state|packet_buffer: rest} |
| 179 | - |
| 180 | - # IO.puts " |-| packet: #{inspect packet, limit: 50_000}" |
| 181 203 | decode_result = Packet.decode_packet(packet, state) |
| 182 204 | |
| 183 | - # IO.puts " |-| decoded: #{inspect decode_result}" |
| 184 205 | case decode_result do |
| 185 206 | {:error, reason} -> |
| 186 207 | {:stop, {:error, reason}, state} |
| @@ -203,22 +224,41 @@ defmodule MTProto do | |
| 203 224 | {:noreply, state} |
| 204 225 | end |
| 205 226 | |
| 227 | + def terminate(_reason, state) do |
| 228 | + # :gen_tcp.close(state.socket) |
| 229 | + end |
| 230 | + |
| 206 231 | defp handle_packet(state, packet) do |
| 207 | - IO.puts "\n\n ---- handle_packet #{inspect packet, limit: 100_000}\n" |
| 232 | + Logger.debug "handle_packet #{inspect packet, limit: 100_000}" |
| 208 233 | case packet do |
| 209 234 | %TL.MTProto.Msg.Container{messages: messages} -> |
| 210 | - # calls `handle_packet#(state, %TL.MTProto.Message{...})` on each message |
| 211 235 | Enum.reduce(messages, state, fn(message, state) -> |
| 212 236 | handle_packet(state, message) |
| 213 237 | end) |
| 214 | - %TL.MTProto.Message{msg_id: msg_id, body: body} -> |
| 215 | - handle_packet(state, body) |
| 238 | + %TL.MTProto.Message{seqno: seqno, msg_id: msg_id, body: body} -> |
| 239 | + state = handle_packet(state, body) |
| 240 | + %{state|msg_seqno: state.msg_seqno + 2} |
| 216 241 | %TL.MTProto.Msgs.Ack{msg_ids: msg_ids} -> |
| 217 242 | %{state|msg_ids: state.msg_ids -- msg_ids} |
| 218 243 | %TL.MTProto.New.Session.Created{server_salt: server_salt} -> |
| 219 | - %{state|server_salt: <<server_salt :: little-size(64)>>} |
| 244 | + # convert to binary |
| 245 | + server_salt = <<server_salt :: little-size(64)>> |
| 246 | + # notify about authorization result, because this packet means |
| 247 | + # that connection is initialized after authorization |
| 248 | + send_to_notifier(state, |
| 249 | + {:authorized, state.auth_key, state.auth_key_hash, server_salt}) |
| 250 | + # update state |
| 251 | + %{state|server_salt: server_salt} |
| 252 | + # TODO migrate to another DC |
| 253 | + # %TL.MTProto.Rpc.Error{error_code: 303, error_message: <<"NETWORK_MIGRATE_", dc_id :: binary>> = message} -> |
| 254 | + # send_to_notifier(state, {:error, 303, message}) |
| 255 | + # dc_id = String.to_integer(dc_id) |
| 256 | + # request = %TL.Auth.ExportAuthorization{dc_id: dc_id} |
| 257 | + # send_rpc_request(state.socket, request, state) |
| 258 | + # # send(self, {:reconnect, {:change_dc, dc_id}}) |
| 259 | + # %{state|reconnect: {:dc, dc_id}} |
| 220 260 | %TL.MTProto.Rpc.Error{error_code: code, error_message: message} -> |
| 221 | - send(state.notifier, {:error, code, message}) |
| 261 | + send_to_notifier(state, {:error, code, message}) |
| 222 262 | # TODO do we need to reconnect when server responds with error? |
| 223 263 | # send(self, {:reconnect, :change_dc}) |
| 224 264 | state |
| @@ -226,17 +266,29 @@ defmodule MTProto do | |
| 226 266 | state = handle_packet(state, result) |
| 227 267 | # FIXME do we need to remove msg_id from current state in this place? |
| 228 268 | %{state|msg_ids: state.msg_ids -- [msg_id]} |
| 269 | + %TL.MTProto.Bad.Server.Salt{new_server_salt: server_salt} -> |
| 270 | + # convert to binary |
| 271 | + server_salt = <<server_salt :: little-size(64)>> |
| 272 | + # reconnect to use new server_salt |
| 273 | + send(self, {:reconnect, :server_salt_changed}) |
| 274 | + # notify handler |
| 275 | + send_to_notifier(state, {:config, :server_salt, server_salt}) |
| 276 | + %{state|server_salt: server_salt} |
| 277 | + %TL.MTProto.Bad.Msg.Notification{error_code: code} -> |
| 278 | + send_to_notifier(state, {:error, code, "bad_msg_id"}) |
| 279 | + state |
| 229 280 | %TL.MTProto.Gzip.Packed{packed_data: packed_data} -> |
| 230 281 | {:ok, data} = TL.Serializer.decode(:zlib.gunzip(packed_data)) |
| 231 282 | handle_packet(state, data) |
| 232 283 | # stores this_dc and dc list, changes when server fails |
| 233 284 | # or returns Rpc.Error, or accidentally disconnected |
| 234 | - %TL.Config{dc_options: dc_options, this_dc: dc} -> |
| 235 | - Logger.debug("set dc options, current: #{inspect dc}, list: #{inspect dc_options}") |
| 285 | + %TL.Config{dc_options: dc_options, this_dc: dc} = config -> |
| 286 | + # notify config |
| 287 | + send_to_notifier(state, {:config, :server_config, config}) |
| 236 288 | %{state|dc_options: dc_options, dc: dc} |
| 237 289 | result -> |
| 238 290 | # IO.puts " --- handle_packet result: #{inspect result}" |
| 239 | - send(state.notifier, {:result, result}) |
| 291 | + send_to_notifier(state, {:result, result}) |
| 240 292 | state |
| 241 293 | end |
| 242 294 | end |
| @@ -263,9 +315,15 @@ defmodule MTProto do | |
| 263 315 | query: %TL.Help.GetConfig{}}} |
| 264 316 | end |
| 265 317 | |
| 266 | - def send_rpc_request(socket, request, state) do |
| 318 | + defp send_to_notifier(state, message) do |
| 319 | + send(state.notifier, {:tl, message}) |
| 320 | + end |
| 321 | + |
| 322 | + defp send_rpc_request(socket, request, state) do |
| 267 323 | {packet, state} = Packet.encode(request, state) |
| 268 324 | |
| 325 | + send_to_notifier(state, {:msg_seqno, state.msg_seqno}) |
| 326 | + |
| 269 327 | case :gen_tcp.send(socket, packet) do |
| 270 328 | :ok -> |
| 271 329 | {:ok, state} |
| @@ -278,25 +336,8 @@ defmodule MTProto do | |
| 278 336 | :ok = :inet.setopts(socket, active: :once) |
| 279 337 | end |
| 280 338 | |
| 281 | - defp choose_server(%{dc: dc, dc_options: dc_options} = state) when length(dc_options) > 0 do |
| 282 | - acceptable_dcs = Enum.filter(dc_options, fn(dc_opt) -> |
| 283 | - dc_opt.ipv6 == false and dc_opt.id != dc |
| 284 | - end) |
| 285 | - |
| 286 | - new_dc = Enum.random(acceptable_dcs) |
| 287 | - |
| 288 | - {String.to_charlist(new_dc.ip_address), new_dc.port} |
| 289 | - end |
| 290 | - defp choose_server(_state) do |
| 291 | - {telegram_host(), telegram_port()} |
| 292 | - end |
| 293 | - |
| 294 | - defp telegram_host do |
| 295 | - config(:host) |
| 296 | - end |
| 297 | - |
| 298 | - defp telegram_port do |
| 299 | - config(:port) |
| 339 | + defp choose_server(state) do |
| 340 | + DC.choose(state.reconnect, state.dc, state.dc_options) |
| 300 341 | end |
| 301 342 | |
| 302 343 | defp config(key, default \\ nil) do |
| @@ -11,8 +11,7 @@ defmodule MTProto.Auth do | |
| 11 11 | # make req_pq#60469778 |
| 12 12 | req_pq = TL.MTProto.encode(%TL.MTProto.Req.Pq{nonce: nonce}) |
| 13 13 | |
| 14 | - # make auth |
| 15 | - # :ok = :gen_tcp.send(socket, Packet.encode_bare(req_pq, Math.make_message_id())) |
| 14 | + # send req_pq |
| 16 15 | send_bare_packet(client, req_pq) |
| 17 16 | |
| 18 17 | # create auth_params |
| @@ -131,13 +130,7 @@ defmodule MTProto.Auth do | |
| 131 130 | {:ok, %TL.MTProto.Dh.Gen.Ok{} = dh_gen} -> |
| 132 131 | # check nonce_hash1 |
| 133 132 | if state.auth_params.nonce_hash1 == dh_gen.new_nonce_hash1 do |
| 134 | - IO.puts " -- authorized" |
| 135 | - IO.puts " --- auth_key #{inspect state.auth_key, limit: 10240}" |
| 136 | - IO.puts " --- auth_key_hash #{inspect state.auth_key_hash, limit: 10240}" |
| 137 | - IO.puts " --- server_salt #{inspect state.server_salt, limit: 10240}" |
| 138 | - |
| 139 133 | send(client, :authorized) |
| 140 | - |
| 141 134 | {:ok, %State{state|auth_state: :encrypted, auth_params: nil}} |
| 142 135 | else |
| 143 136 | {:error, :mismatched_nonce_hash1, state} |
| @@ -72,23 +72,53 @@ defmodule MTProto.Crypto do | |
| 72 72 | encrypt_aes_ige256(tmp_aes_key, tmp_aes_iv, data_with_hash) |
| 73 73 | end |
| 74 74 | |
| 75 | + @doc """ |
| 76 | + auth_key_hash is computed := 64 lower-order bits of SHA1(auth_key). |
| 77 | + |
| 78 | + The server checks whether there already is another key with the same |
| 79 | + `auth_key_hash` and responds in one of the following ways. |
| 80 | + """ |
| 75 81 | def auth_key_hash(auth_key) do |
| 76 | - sha = sha1(auth_key) |
| 77 | - :binary.part(sha, {byte_size(sha), -8}) |
| 82 | + substr(sha1(auth_key), 12, 8) |
| 78 83 | end |
| 79 84 | |
| 85 | + @doc """ |
| 86 | + `new_nonce_hash1`, `new_nonce_hash2`, and `new_nonce_hash3` are obtained |
| 87 | + as the 128 lower-order bits of SHA1 of the byte string derived from the |
| 88 | + new_nonce string by adding a single byte with the value of 1, 2, or 3, |
| 89 | + and followed by another 8 bytes with auth_key_aux_hash. |
| 90 | + |
| 91 | + Different values are required to prevent an intruder from changing server |
| 92 | + response `dh_gen_ok` into `dh_gen_retry`. |
| 93 | + """ |
| 80 94 | def make_nonce_hash1(new_nonce, auth_key) do |
| 81 | - auth_key_hash = :binary.part(sha1(auth_key), 0, 8) |
| 95 | + auth_key_hash = substr(sha1(auth_key), 0, 8) |
| 82 96 | nonce = |
| 83 97 | <<new_nonce :: binary-size(32), 1 :: size(8), |
| 84 98 | auth_key_hash :: binary-size(8)>> |
| 85 99 | |
| 86 | - :binary.part(sha1(nonce), 4, 16) |
| 100 | + substr(sha1(nonce), 4, 16) |
| 87 101 | end |
| 88 102 | |
| 103 | + @doc """ |
| 104 | + server_salt := substr(new_nonce, 0, 8) XOR substr(server_nonce, 0, 8) |
| 105 | + |
| 106 | + https://core.telegram.org/mtproto/auth_key#dh-key-exchange-complete (9) |
| 107 | + """ |
| 89 108 | def make_server_salt(new_nonce, server_nonce) do |
| 90 | - server_salt = :binary.part(new_nonce, 0, 8) |
| 91 | - Math.binary_bxor(server_salt, :binary.part(server_nonce, 0, 8)) |
| 109 | + Math.binary_bxor(substr(new_nonce, 0, 8), substr(server_nonce, 0, 8)) |
| 110 | + end |
| 111 | + |
| 112 | + def sha1(data) do |
| 113 | + :crypto.hash(:sha, data) |
| 114 | + end |
| 115 | + |
| 116 | + def encrypt_aes_ige256(aes_key, aes_iv, plain) do |
| 117 | + :crypto.block_encrypt(:aes_ige256, aes_key, aes_iv, plain) |
| 118 | + end |
| 119 | + |
| 120 | + def decrypt_aes_ige256(aes_key, aes_iv, encrypted) do |
| 121 | + :crypto.block_decrypt(:aes_ige256, aes_key, aes_iv, encrypted) |
| 92 122 | end |
| 93 123 | |
| 94 124 | ### internal functions |
| @@ -96,18 +126,6 @@ defmodule MTProto.Crypto do | |
| 96 126 | defp action_value(:decode), do: 8 |
| 97 127 | defp action_value(:encode), do: 0 |
| 98 128 | |
| 99 | - defp sha1(data) do |
| 100 | - :crypto.hash(:sha, data) |
| 101 | - end |
| 102 | - |
| 103 | - defp encrypt_aes_ige256(aes_key, aes_iv, plain) do |
| 104 | - :crypto.block_encrypt(:aes_ige256, aes_key, aes_iv, plain) |
| 105 | - end |
| 106 | - |
| 107 | - defp decrypt_aes_ige256(aes_key, aes_iv, encrypted) do |
| 108 | - :crypto.block_decrypt(:aes_ige256, aes_key, aes_iv, encrypted) |
| 109 | - end |
| 110 | - |
| 111 129 | defp substr(bin, start, length) do |
| 112 130 | :binary.part(bin, start, length) |
| 113 131 | end |
Loading more files…