Partial support for encrypted chats.

This commit is contained in:
vysheng 2013-11-04 21:34:27 +04:00
parent 9dd3627afa
commit 923845d668
14 changed files with 1082 additions and 233 deletions

View File

@ -48,9 +48,8 @@ long long cur_downloading_bytes;
long long cur_downloaded_bytes;
char *line_ptr;
extern int user_num;
extern int chat_num;
extern peer_t *Peers[];
extern int peer_num;
int is_same_word (const char *s, size_t l, const char *word) {
return s && word && strlen (word) == l && !memcmp (s, word, l);
@ -106,10 +105,10 @@ peer_id_t next_token_user (void) {
}
int index = 0;
while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_USER)) {
while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_USER)) {
index ++;
}
if (index < user_num + chat_num) {
if (index < peer_num) {
return Peers[index]->id;
} else {
return PEER_NOT_FOUND;
@ -130,10 +129,10 @@ peer_id_t next_token_chat (void) {
}
int index = 0;
while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_CHAT)) {
while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_CHAT)) {
index ++;
}
if (index < user_num + chat_num) {
if (index < peer_num) {
return Peers[index]->id;
} else {
return PEER_NOT_FOUND;
@ -161,10 +160,10 @@ peer_id_t next_token_peer (void) {
}
int index = 0;
while (index < user_num + chat_num && (!is_same_word (s, l, Peers[index]->print_name))) {
while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name))) {
index ++;
}
if (index < user_num + chat_num) {
if (index < peer_num) {
return Peers[index]->id;
} else {
return PEER_NOT_FOUND;
@ -232,6 +231,7 @@ char *commands[] = {
"rename_contact",
"show_license",
"search",
"mark_read",
0 };
int commands_flags[] = {
@ -258,6 +258,7 @@ int commands_flags[] = {
071,
07,
072,
072,
};
int get_complete_mode (void) {
@ -297,10 +298,10 @@ int get_complete_mode (void) {
int complete_user_list (int index, const char *text, int len, char **R) {
index ++;
while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_USER)) {
while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_USER)) {
index ++;
}
if (index < user_num + chat_num) {
if (index < peer_num) {
*R = strdup (Peers[index]->print_name);
return index;
} else {
@ -310,10 +311,10 @@ int complete_user_list (int index, const char *text, int len, char **R) {
int complete_chat_list (int index, const char *text, int len, char **R) {
index ++;
while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_CHAT)) {
while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_CHAT)) {
index ++;
}
if (index < user_num + chat_num) {
if (index < peer_num) {
*R = strdup (Peers[index]->print_name);
return index;
} else {
@ -323,10 +324,10 @@ int complete_chat_list (int index, const char *text, int len, char **R) {
int complete_user_chat_list (int index, const char *text, int len, char **R) {
index ++;
while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) {
while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) {
index ++;
}
if (index < user_num + chat_num) {
if (index < peer_num) {
*R = strdup (Peers[index]->print_name);
return index;
} else {
@ -663,6 +664,8 @@ void interpreter (char *line UU) {
"load_photo/load_video/load_video_thumb <msg-seqno> - loads photo/video to download dir\n"
"view_photo/view_video/view_video_thumb <msg-seqno> - loads photo/video to download dir and starts system default viewer\n"
"show_license - prints contents of GPLv2\n"
"search <peer> pattern - searches pattern in messages with peer\n"
"mark_read <peer> - mark read all received messages with peer\n"
);
pop_color ();
rl_on_new_line ();
@ -685,6 +688,9 @@ void interpreter (char *line UU) {
RET;
}
do_msg_search (id, from, to, limit, s);
} else if (IS_WORD ("mark_read")) {
GET_PEER;
do_mark_read (id);
}
#undef IS_WORD
#undef RET
@ -796,30 +802,6 @@ void logprintf (const char *format, ...) {
}
}
const char *message_media_type_str (struct message_media *M) {
static char buf[1000];
switch (M->type) {
case CODE_message_media_empty:
return "";
case CODE_message_media_photo:
return "[photo]";
case CODE_message_media_video:
return "[video]";
case CODE_message_media_geo:
sprintf (buf, "[geo] https://maps.google.com/maps?ll=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude);
return buf;
case CODE_message_media_contact:
snprintf (buf, 999, "[contact] " COLOR_RED "%s %s" COLOR_NORMAL " %s", M->first_name, M->last_name, M->phone);
return buf;
case CODE_message_media_unsupported:
return "[unsupported]";
default:
assert (0);
return "";
}
}
int color_stack_pos;
const char *color_stack[10];
@ -853,6 +835,12 @@ void print_media (struct message_media *M) {
case CODE_message_media_video:
printf ("[video]");
return;
case CODE_decrypted_message_media_photo:
printf ("[photo]");
return;
case CODE_decrypted_message_media_video:
printf ("[video]");
return;
case CODE_message_media_geo:
printf ("[geo] https://maps.google.com/?q=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude);
return;
@ -1009,6 +997,9 @@ peer_id_t last_from_id;
peer_id_t last_to_id;
void print_message (struct message *M) {
if (M->flags & (FLAG_EMPTY | FLAG_DELETED)) {
return;
}
if (M->service) {
print_service_message (M);
return;
@ -1050,7 +1041,42 @@ void print_message (struct message *M) {
printf (" »»» ");
}
}
} else if (get_peer_type (M->to_id) == PEER_ENCR_CHAT) {
peer_t *P = user_chat_get (M->to_id);
assert (P);
if (M->out) {
push_color (COLOR_GREEN);
if (msg_num_mode) {
printf ("%lld ", M->id);
}
print_date (M->date);
printf (" ");
push_color (COLOR_CYAN);
printf (" %s", P->print_name);
pop_color ();
if (M->unread) {
printf (" <<< ");
} else {
printf (" ««« ");
}
} else {
push_color (COLOR_BLUE);
if (msg_num_mode) {
printf ("%lld ", M->id);
}
print_date (M->date);
push_color (COLOR_CYAN);
printf (" %s", P->print_name);
pop_color ();
if (M->unread) {
printf (" >>> ");
} else {
printf (" »»» ");
}
}
} else {
assert (get_peer_type (M->to_id) == PEER_CHAT);
push_color (COLOR_MAGENTA);
if (msg_num_mode) {
printf ("%lld ", M->id);

View File

@ -28,7 +28,7 @@
#define COLOR_YELLOW "\033[33;1m"
#define COLOR_BLUE "\033[34;1m"
#define COLOR_MAGENTA "\033[35;1m"
#define COLOR_CYAN "\033[36;1m"
char *get_default_prompt (void);
char *complete_none (const char *text, int state);

156
loop.c
View File

@ -39,6 +39,7 @@
#include "mtproto-common.h"
#include "queries.h"
#include "telegram.h"
#include "loop.h"
extern char *default_username;
extern char *auth_token;
@ -59,6 +60,7 @@ void net_loop (int flags, int (*is_end)(void)) {
cc ++;
}
write_state_file ();
int x = connections_make_poll_array (fds + cc, 101 - cc) + cc;
double timer = next_timer_in ();
if (timer > 1000) { timer = 1000; }
@ -116,6 +118,8 @@ struct dc *DC_working;
int dc_working_num;
int auth_state;
char *get_auth_key_filename (void);
char *get_state_filename (void);
char *get_secret_chat_filename (void);
int zero[512];
@ -231,11 +235,157 @@ void read_auth_file (void) {
}
}
int pts, qts, seq, last_date;
void read_state_file (void) {
int state_file_fd = open (get_state_filename (), O_CREAT | O_RDWR, 0600);
if (state_file_fd < 0) {
return;
}
int version, magic;
if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return; }
if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return; }
if (read (state_file_fd, &version, 4) < 4) { close (state_file_fd); return; }
assert (version >= 0);
int x[4];
if (read (state_file_fd, x, 16) < 16) {
close (state_file_fd);
return;
}
pts = x[0];
qts = x[1];
seq = x[2];
last_date = x[3];
close (state_file_fd);
}
void write_state_file (void) {
static int wseq;
static int wpts;
static int wqts;
static int wdate;
if (wseq >= seq && wpts >= pts && wqts >= qts && wdate >= last_date) { return; }
int state_file_fd = open (get_state_filename (), O_CREAT | O_RDWR, 0600);
if (state_file_fd < 0) {
return;
}
int x[6];
x[0] = STATE_FILE_MAGIC;
x[1] = 0;
x[2] = pts;
x[3] = qts;
x[4] = seq;
x[5] = last_date;
assert (write (state_file_fd, x, 24) == 24);
close (state_file_fd);
wseq = seq; wpts = pts; wqts = qts; wdate = last_date;
}
extern peer_t *Peers[];
extern int peer_num;
void read_secret_chat_file (void) {
int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600);
if (fd < 0) {
return;
}
int x[2];
if (read (fd, x, 8) < 8) {
close (fd); return;
}
if (x[0] != (int)SECRET_CHAT_FILE_MAGIC) { close (fd); return; }
int version = x[1];
assert (version >= 0);
int cc;
assert (read (fd, &cc, 4) == 4);
int i;
for (i = 0; i < cc; i++) {
peer_t *P = malloc (sizeof (*P));
memset (P, 0, sizeof (*P));
struct secret_chat *E = &P->encr_chat;
int t;
assert (read (fd, &t, 4) == 4);
P->id = MK_ENCR_CHAT (t);
assert (read (fd, &P->flags, 4) == 4);
assert (read (fd, &t, 4) == 4);
assert (t > 0);
P->print_name = malloc (t + 1);
assert (read (fd, P->print_name, t) == t);
P->print_name[t] = 0;
assert (read (fd, &E->state, 4) == 4);
assert (read (fd, &E->user_id, 4) == 4);
assert (read (fd, &E->admin_id, 4) == 4);
assert (read (fd, &E->ttl, 4) == 4);
assert (read (fd, &E->access_hash, 8) == 8);
if (E->state != sc_waiting) {
E->g_key = malloc (256);
assert (read (fd, E->g_key, 256) == 256);
}
E->nonce = malloc (256);
assert (read (fd, E->nonce, 256) == 256);
assert (read (fd, E->key, 256) == 256);
assert (read (fd, &E->key_fingerprint, 8) == 8);
insert_encrypted_chat (P);
}
close (fd);
}
void write_secret_chat_file (void) {
int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600);
if (fd < 0) {
return;
}
int x[2];
x[0] = SECRET_CHAT_FILE_MAGIC;
x[1] = 0;
assert (write (fd, x, 8) == 8);
int i;
int cc = 0;
for (i = 0; i < peer_num; i++) if (get_peer_type (Peers[i]->id) == PEER_ENCR_CHAT) {
if (Peers[i]->encr_chat.state != sc_none && Peers[i]->encr_chat.state != sc_deleted) {
cc ++;
}
}
assert (write (fd, &cc, 4) == 4);
for (i = 0; i < peer_num; i++) if (get_peer_type (Peers[i]->id) == PEER_ENCR_CHAT) {
if (Peers[i]->encr_chat.state != sc_none && Peers[i]->encr_chat.state != sc_deleted) {
int t = get_peer_id (Peers[i]->id);
assert (write (fd, &t, 4) == 4);
t = Peers[i]->flags;
assert (write (fd, &t, 4) == 4);
t = strlen (Peers[i]->print_name);
assert (write (fd, &t, 4) == 4);
assert (write (fd, Peers[i]->print_name, t) == t);
assert (write (fd, &Peers[i]->encr_chat.state, 4) == 4);
assert (write (fd, &Peers[i]->encr_chat.user_id, 4) == 4);
assert (write (fd, &Peers[i]->encr_chat.admin_id, 4) == 4);
assert (write (fd, &Peers[i]->encr_chat.ttl, 4) == 4);
assert (write (fd, &Peers[i]->encr_chat.access_hash, 8) == 8);
if (Peers[i]->encr_chat.state != sc_waiting) {
assert (write (fd, Peers[i]->encr_chat.g_key, 256) == 256);
}
assert (write (fd, Peers[i]->encr_chat.nonce, 256) == 256);
assert (write (fd, Peers[i]->encr_chat.key, 256) == 256);
assert (write (fd, &Peers[i]->encr_chat.key_fingerprint, 8) == 8);
}
}
close (fd);
}
extern int max_chat_size;
int mcs (void) {
return max_chat_size;
}
extern int difference_got;
int dgot (void) {
return !difference_got;
}
int readline_active;
int new_dc_num;
int loop (void) {
@ -368,7 +518,11 @@ int loop (void) {
rl_attempted_completion_function = (CPPFunction *) complete_text;
rl_completion_entry_function = complete_none;
do_get_dialog_list_ex ();
read_state_file ();
read_secret_chat_file ();
do_get_difference ();
net_loop (0, dgot);
do_get_dialog_list ();
return main_loop ();
}

2
loop.h
View File

@ -21,4 +21,6 @@
int loop (void);
void net_loop (int flags, int (*end)(void));
void write_auth_file (void);
void write_state_file (void);
void write_secret_chat_file (void);
#endif

20
main.c
View File

@ -41,6 +41,8 @@
#define CONFIG_DIRECTORY ".telegram/"
#define CONFIG_FILE CONFIG_DIRECTORY "config"
#define AUTH_KEY_FILE CONFIG_DIRECTORY "auth"
#define STATE_FILE CONFIG_DIRECTORY "state"
#define SECRET_CHAT_FILE CONFIG_DIRECTORY "secret"
#define DOWNLOADS_DIRECTORY "downloads/"
#define CONFIG_DIRECTORY_MODE 0700
@ -130,6 +132,24 @@ char *get_auth_key_filename (void) {
return auth_key_filename;
}
char *get_state_filename (void) {
char *state_filename;
int length = strlen (get_home_directory ()) + strlen (STATE_FILE) + 2;
state_filename = (char *) calloc (length, sizeof (char));
sprintf (state_filename, "%s/" STATE_FILE, get_home_directory ());
return state_filename;
}
char *get_secret_chat_filename (void) {
char *secret_chat_filename;
int length = strlen (get_home_directory ()) + strlen (SECRET_CHAT_FILE) + 2;
secret_chat_filename = (char *) calloc (length, sizeof (char));
sprintf (secret_chat_filename, "%s/" SECRET_CHAT_FILE, get_home_directory ());
return secret_chat_filename;
}
char *get_downloads_directory (void)
{
char *downloads_directory;

View File

@ -637,14 +637,18 @@ int unread_messages;
int our_id;
int pts;
int qts;
int last_date;
int seq;
void fetch_pts (void) {
int p = fetch_int ();
if (p <= pts) { return; }
if (p != pts + 1) {
if (pts) {
logprintf ("Hole in pts p = %d, pts = %d\n", p, pts);
//logprintf ("Hole in pts p = %d, pts = %d\n", p, pts);
// get difference should be here
pts = p;
} else {
pts = p;
}
@ -655,10 +659,12 @@ void fetch_pts (void) {
void fetch_qts (void) {
int p = fetch_int ();
if (p <= qts) { return; }
if (p != qts + 1) {
if (qts) {
logprintf ("Hole in qts\n");
//logprintf ("Hole in qts\n");
// get difference should be here
qts = p;
} else {
qts = p;
}
@ -667,6 +673,24 @@ void fetch_qts (void) {
}
}
void fetch_date (void) {
int p = fetch_int ();
if (p > last_date) {
last_date = p;
}
}
void fetch_seq (void) {
int x = fetch_int ();
if (x > seq + 1) {
logprintf ("Hole in seq: seq = %d, x = %d\n", seq, x);
//do_get_difference ();
seq = x;
} else if (x >= seq + 1) {
seq = x;
}
}
void work_update (struct connection *c UU, long long msg_id UU) {
unsigned op = fetch_int ();
switch (op) {
@ -993,9 +1017,11 @@ void work_update (struct connection *c UU, long long msg_id UU) {
printf (" is now in deleted state\n");
break;
}
/*if (E->state == state_requested) {
pop_color ();
print_end ();
if (E->state == sc_request) {
do_accept_encr_chat_request (E);
}*/
}
fetch_int (); // date
}
break;
@ -1041,7 +1067,7 @@ void work_update (struct connection *c UU, long long msg_id UU) {
void work_update_short (struct connection *c, long long msg_id) {
assert (fetch_int () == CODE_update_short);
work_update (c, msg_id);
fetch_int (); // date
fetch_date ();
}
void work_updates (struct connection *c, long long msg_id) {
@ -1062,9 +1088,8 @@ void work_updates (struct connection *c, long long msg_id) {
for (i = 0; i < n; i++) {
fetch_alloc_chat ();
}
fetch_int (); // date
fetch_int (); // seq
fetch_date (); // date
fetch_seq (); // seq
}
void work_update_short_message (struct connection *c UU, long long msg_id UU) {
@ -1073,6 +1098,9 @@ void work_update_short_message (struct connection *c UU, long long msg_id UU) {
unread_messages ++;
print_message (M);
update_prompt ();
if (M->date > last_date) {
last_date = M->date;
}
}
void work_update_short_chat_message (struct connection *c UU, long long msg_id UU) {
@ -1081,6 +1109,9 @@ void work_update_short_chat_message (struct connection *c UU, long long msg_id U
unread_messages ++;
print_message (M);
update_prompt ();
if (M->date > last_date) {
last_date = M->date;
}
}
void work_container (struct connection *c, long long msg_id UU) {
@ -1211,6 +1242,10 @@ void work_detained_info (struct connection *c UU, long long msg_id UU) {
fetch_int (); // status
}
void work_updates_to_long (struct connection *c UU, long long msg_id UU) {
assert (fetch_int () == (int)CODE_updates_too_long);
do_get_difference ();
}
void rpc_execute_answer (struct connection *c, long long msg_id UU) {
if (verbosity >= 5) {
logprintf ("rpc_execute_answer: fd=%d\n", c->fd);
@ -1254,6 +1289,9 @@ void rpc_execute_answer (struct connection *c, long long msg_id UU) {
case CODE_msg_detained_info:
work_detained_info (c, msg_id);
return;
case CODE_updates_too_long:
work_updates_to_long (c, msg_id);
return;
}
logprintf ( "Unknown message: \n");
hexdump_in ();

View File

@ -23,4 +23,5 @@
void on_start (void);
long long encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful);
void dc_authorize (struct dc *DC);
void work_update (struct connection *c, long long msg_id);
#endif

View File

@ -37,6 +37,9 @@
#include "mtproto-common.h"
#include "interface.h"
int __packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr;
int *packet_buffer = __packet_buffer + 16;
long long rsa_encrypted_chunks, rsa_decrypted_chunks;
BN_CTX *BN_ctx;

View File

@ -83,6 +83,7 @@
#define MAX_MESSAGE_INTS 1048576
#define MAX_PROTO_MESSAGE_INTS 1048576
#define PACKET_BUFFER_SIZE (16384 * 100 + 16) // temp fix
#pragma pack(push,4)
struct encrypted_message {
// unencrypted header
@ -219,8 +220,8 @@ void prng_seed (const char *password_filename, int password_length);
int serialize_bignum (BIGNUM *b, char *buffer, int maxlen);
long long compute_rsa_key_fingerprint (RSA *key);
#define PACKET_BUFFER_SIZE (16384 * 100) // temp fix
int packet_buffer[PACKET_BUFFER_SIZE], *packet_ptr;
extern int *packet_buffer;
extern int *packet_ptr;
static inline void out_ints (int *what, int len) {
assert (packet_ptr + len <= packet_buffer + PACKET_BUFFER_SIZE);
@ -262,6 +263,9 @@ static inline void out_bignum (BIGNUM *n) {
extern int *in_ptr, *in_end;
void fetch_pts (void);
void fetch_qts (void);
void fetch_date (void);
void fetch_seq (void);
static inline int prefetch_strlen (void) {
if (in_ptr >= in_end) {
return -1;

5
net.h
View File

@ -26,7 +26,7 @@ struct dc;
//#define TG_SERVER "95.142.192.66"
#define TG_APP_HASH "36722c72256a24c1225de00eb6a1ca74"
#define TG_APP_ID 2899
#define TG_BUILD "200"
#define TG_BUILD "203"
#define TG_VERSION "0.01-beta"
@ -79,6 +79,9 @@ struct dc {
#define DC_SERIALIZED_MAGIC 0x64582faa
#define DC_SERIALIZED_MAGIC_V2 0x94032abb
#define STATE_FILE_MAGIC 0x84217a0d
#define SECRET_CHAT_FILE_MAGIC 0xa9840add
struct dc_serialized {
int magic;
int port;

470
queries.c
View File

@ -37,6 +37,12 @@
#include "structures.h"
#include "interface.h"
#include "net.h"
#include <openssl/bn.h>
#include <openssl/rand.h>
#include <openssl/aes.h>
#include <openssl/sha.h>
#define sha1 SHA1
char *get_downloads_directory (void);
int verbosity;
@ -276,6 +282,8 @@ int new_dc_num;
extern struct dc *DC_list[];
extern struct dc *DC_working;
/* {{{ Get config */
int help_get_config_on_answer (struct query *q UU) {
assert (fetch_int () == CODE_config);
fetch_int ();
@ -323,7 +331,9 @@ void do_help_get_config (void) {
out_int (CODE_help_get_config);
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, 0);
}
/* }}} */
/* {{{ Send code */
char *phone_code_hash;
int send_code_on_answer (struct query *q UU) {
assert (fetch_int () == CODE_auth_sent_code);
@ -407,8 +417,9 @@ void do_send_code (const char *user) {
net_loop (0, code_is_sent);
assert (want_dc_num == -1);
}
/* }}} */
/* {{{ Check phone */
int check_phone_result;
int cr_f (void) {
return check_phone_result >= 0;
@ -460,7 +471,9 @@ int do_auth_check_phone (const char *user) {
net_loop (0, cr_f);
return check_phone_result;
}
/* }}} */
/* {{{ Nearest DC */
int nearest_dc_num;
int nr_f (void) {
return nearest_dc_num >= 0;
@ -497,7 +510,9 @@ int do_get_nearest_dc (void) {
net_loop (0, nr_f);
return nearest_dc_num;
}
/* }}} */
/* {{{ Sign in / Sign up */
int sign_in_ok;
int sign_in_is_ok (void) {
return sign_in_ok;
@ -554,7 +569,9 @@ int do_send_code_result_auth (const char *code, const char *first_name, const ch
net_loop (0, sign_in_is_ok);
return sign_in_ok;
}
/* }}} */
/* {{{ Get contacts */
extern char *user_list[];
int get_contacts_on_answer (struct query *q UU) {
@ -612,18 +629,106 @@ void do_update_contact_list (void) {
out_string ("");
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_contacts_methods, 0);
}
/* }}} */
/* {{{ Encrypt decrypted */
int *encr_extra;
int *encr_ptr;
int *encr_end;
char *encrypt_decrypted_message (struct secret_chat *E) {
static int msg_key[4];
static unsigned char sha1a_buffer[20];
static unsigned char sha1b_buffer[20];
static unsigned char sha1c_buffer[20];
static unsigned char sha1d_buffer[20];
int x = *(encr_ptr);
assert (x >= 0 && !(x & 3));
sha1 ((void *)encr_ptr, 4 + x, sha1a_buffer);
memcpy (msg_key, sha1a_buffer + 4, 16);
static unsigned char buf[64];
memcpy (buf, msg_key, 16);
memcpy (buf + 16, E->key, 32);
sha1 (buf, 48, sha1a_buffer);
memcpy (buf, E->key + 8, 16);
memcpy (buf + 16, msg_key, 16);
memcpy (buf + 32, E->key + 12, 16);
sha1 (buf, 48, sha1b_buffer);
memcpy (buf, E->key + 16, 32);
memcpy (buf + 32, msg_key, 16);
sha1 (buf, 48, sha1c_buffer);
memcpy (buf, msg_key, 16);
memcpy (buf + 16, E->key + 24, 32);
sha1 (buf, 48, sha1d_buffer);
static unsigned char key[32];
memcpy (key, sha1a_buffer + 0, 8);
memcpy (key + 8, sha1b_buffer + 8, 12);
memcpy (key + 20, sha1c_buffer + 4, 12);
static unsigned char iv[32];
memcpy (iv, sha1a_buffer + 8, 12);
memcpy (iv + 12, sha1b_buffer + 0, 8);
memcpy (iv + 20, sha1c_buffer + 16, 4);
memcpy (iv + 24, sha1d_buffer + 0, 8);
AES_KEY aes_key;
AES_set_encrypt_key (key, 256, &aes_key);
AES_ige_encrypt ((void *)encr_ptr, (void *)encr_ptr, 4 * (encr_end - encr_ptr), &aes_key, iv, 1);
return (void *)msg_key;
}
void encr_start (void) {
encr_extra = packet_ptr;
packet_ptr += 1; // str len
packet_ptr += 2; // fingerprint
packet_ptr += 4; // msg_key
packet_ptr += 1; // len
}
void encr_finish (struct secret_chat *E) {
int l = packet_ptr - (encr_extra + 8);
while (((packet_ptr - encr_extra) - 3) & 3) {
out_int (mrand48 ());
}
*encr_extra = ((packet_ptr - encr_extra) - 1) * 4 * 256 + 0xfe;
encr_extra ++;
*(long long *)encr_extra = E->key_fingerprint;
encr_extra += 2;
encr_extra[4] = l * 4;
encr_ptr = encr_extra + 4;
encr_end = packet_ptr;
memcpy (encr_extra, encrypt_decrypted_message (E), 16);
}
/* }}} */
/* {{{ Seng msg (plain text) */
int msg_send_encr_on_answer (struct query *q UU) {
assert (fetch_int () == CODE_messages_sent_encrypted_message);
logprintf ("Sent\n");
struct message *M = q->extra;
M->date = fetch_int ();
message_insert (M);
return 0;
}
int msg_send_on_answer (struct query *q UU) {
assert (fetch_int () == (int)CODE_messages_sent_message);
int id = fetch_int (); // id
int date = fetch_int (); // date
fetch_date ();
fetch_pts ();
int seq = fetch_int (); // seq
fetch_seq ();
struct message *M = q->extra;
M->id = id;
message_insert (M);
logprintf ("Sent: id = %d, date = %d, seq = %d\n", id, date, seq);
logprintf ("Sent: id = %d\n", id);
return 0;
}
@ -631,10 +736,71 @@ struct query_methods msg_send_methods = {
.on_answer = msg_send_on_answer
};
struct query_methods msg_send_encr_methods = {
.on_answer = msg_send_encr_on_answer
};
int out_message_num;
int our_id;
void out_peer_id (peer_id_t id);
void do_send_encr_message (peer_id_t id, const char *msg, int len) {
peer_t *P = user_chat_get (id);
if (!P) {
logprintf ("Can not send to unknown encrypted chat\n");
return;
}
if (P->encr_chat.state != sc_ok) {
logprintf ("Chat is not yet initialized\n");
return;
}
clear_packet ();
out_int (CODE_messages_send_encrypted);
out_int (CODE_input_encrypted_chat);
out_int (get_peer_id (id));
out_long (P->encr_chat.access_hash);
if (!out_message_num) {
out_message_num = -lrand48 ();
}
out_long ((--out_message_num) - (4ll << 32));
encr_start ();
//out_int (CODE_decrypted_message_layer);
//out_int (8);
out_int (CODE_decrypted_message);
out_long ((out_message_num) - (4ll << 32));
static int buf[4];
int i;
for (i = 0; i < 3; i++) {
buf[i] = mrand48 ();
}
out_cstring ((void *)buf, 16);
out_cstring ((void *)msg, len);
out_int (CODE_decrypted_message_media_empty);
encr_finish (&P->encr_chat);
struct message *M = malloc (sizeof (*M));
memset (M, 0, sizeof (*M));
M->from_id = MK_USER (our_id);
M->to_id = id;
M->unread = 1;
M->message = malloc (len + 1);
memcpy (M->message, msg, len);
M->message[len] = 0;
M->message_len = len;
M->out = 1;
M->media.type = CODE_message_media_empty;
M->id = (out_message_num) - (4ll << 32);
M->date = time (0);
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M);
print_message (M);
}
void do_send_message (peer_id_t id, const char *msg, int len) {
if (get_peer_type (id) == PEER_ENCR_CHAT) {
do_send_encr_message (id, msg, len);
return;
}
if (!out_message_num) {
out_message_num = -lrand48 ();
}
@ -659,7 +825,9 @@ void do_send_message (peer_id_t id, const char *msg, int len) {
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_methods, M);
print_message (M);
}
/* }}} */
/* {{{ Send text file */
void do_send_text (peer_id_t id, char *file_name) {
int fd = open (file_name, O_RDONLY);
if (fd < 0) {
@ -681,19 +849,29 @@ void do_send_text (peer_id_t id, char *file_name) {
close (fd);
}
}
/* }}} */
int mark_read_on_receive (struct query *q UU) {
assert (fetch_int () == (int)CODE_messages_affected_history);
fetch_int (); // pts
fetch_int (); // seq
fetch_pts ();
fetch_seq ();
fetch_int (); // offset
return 0;
}
int mark_read_encr_on_receive (struct query *q UU) {
fetch_bool ();
return 0;
}
struct query_methods mark_read_methods = {
.on_answer = mark_read_on_receive
};
struct query_methods mark_read_encr_methods = {
.on_answer = mark_read_encr_on_receive
};
void do_messages_mark_read (peer_id_t id, int max_id) {
clear_packet ();
out_int (CODE_messages_read_history);
@ -703,6 +881,34 @@ void do_messages_mark_read (peer_id_t id, int max_id) {
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_methods, 0);
}
void do_messages_mark_read_encr (peer_id_t id, long long access_hash, int last_time) {
clear_packet ();
out_int (CODE_messages_read_encrypted_history);
out_int (CODE_input_encrypted_chat);
out_int (get_peer_id (id));
out_long (access_hash);
out_int (last_time);
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_encr_methods, 0);
}
void do_mark_read (peer_id_t id) {
peer_t *P = user_chat_get (id);
if (!P) {
rprintf ("Unknown peer\n");
return;
}
if (!P->last) {
rprintf ("Unknown last peer message\n");
return;
}
if (get_peer_type (id) == PEER_USER || get_peer_type (id) == PEER_CHAT) {
do_messages_mark_read (id, P->last->id);
return;
}
assert (get_peer_type (id) == PEER_ENCR_CHAT);
do_messages_mark_read_encr (id, P->encr_chat.access_hash, P->last->date);
}
int get_history_on_answer (struct query *q UU) {
static struct message *ML[10000];
int i;
@ -919,8 +1125,8 @@ int send_file_on_answer (struct query *q UU) {
for (i = 0; i < n; i++) {
fetch_alloc_user ();
}
fetch_int (); // pts
fetch_int (); // seq
fetch_pts ();
fetch_seq ();
print_message (M);
return 0;
}
@ -1029,8 +1235,8 @@ int fwd_msg_on_answer (struct query *q UU) {
for (i = 0; i < n; i++) {
fetch_alloc_user ();
}
fetch_int (); // pts
fetch_int (); // seq
fetch_pts ();
fetch_seq ();
print_message (M);
return 0;
}
@ -1041,7 +1247,7 @@ struct query_methods fwd_msg_methods = {
void do_forward_message (peer_id_t id, int n) {
clear_packet ();
out_int (CODE_invoke_with_layer3);
out_int (CODE_invoke_with_layer9);
out_int (CODE_messages_forward_message);
out_peer_id (id);
out_int (n);
@ -1063,8 +1269,8 @@ int rename_chat_on_answer (struct query *q UU) {
for (i = 0; i < n; i++) {
fetch_alloc_user ();
}
fetch_int (); // pts
fetch_int (); // seq
fetch_pts ();
fetch_seq ();
print_message (M);
return 0;
}
@ -1509,3 +1715,241 @@ void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s) {
out_int (limit);
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_search_methods, 0);
}
int send_encr_accept_on_answer (struct query *q UU) {
struct secret_chat *E = fetch_alloc_encrypted_chat ();
if (E->state == sc_ok) {
print_start ();
push_color (COLOR_YELLOW);
printf ("Encrypted connection with ");
print_encr_chat_name (E->id, (void *)E);
printf (" established\n");
pop_color ();
print_end ();
} else {
print_start ();
push_color (COLOR_YELLOW);
printf ("Encrypted connection with ");
print_encr_chat_name (E->id, (void *)E);
printf (" failed\n");
pop_color ();
print_end ();
}
return 0;
}
struct query_methods send_encr_accept_methods = {
.on_answer = send_encr_accept_on_answer
};
int encr_root;
unsigned char *encr_prime;
int encr_param_version;
BN_CTX *ctx;
void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) {
int i;
for (i = 0; i < 64; i++) {
*(((int *)random) + i) ^= mrand48 ();
}
BIGNUM *b = BN_bin2bn (random, 256, 0);
assert (b);
BIGNUM *g_a = BN_bin2bn (E->g_key, 256, 0);
assert (g_a);
if (!ctx) {
ctx = BN_CTX_new ();
BN_CTX_init (ctx);
}
BIGNUM *p = BN_bin2bn (encr_prime, 256, 0);
BIGNUM *r = BN_new ();
BN_init (r);
BN_mod_exp (r, g_a, b, p, ctx);
memset (E->key, 0, sizeof (E->key));
BN_bn2bin (r, (void *)E->key);
for (i = 0; i < 64; i++) {
E->key[i] ^= *(((int *)E->nonce) + i);
}
static unsigned char sha_buffer[20];
sha1 ((void *)E->key, 256, sha_buffer);
E->key_fingerprint = *(long long *)(sha_buffer + 12);
clear_packet ();
out_int (CODE_messages_accept_encryption);
out_int (CODE_input_encrypted_chat);
logprintf ("id = %d\n", get_peer_id (E->id));
out_int (get_peer_id (E->id));
out_long (E->access_hash);
BN_set_word (g_a, encr_root);
BN_mod_exp (r, g_a, b, p, ctx);
static unsigned char buf[256];
memset (buf, 0, sizeof (buf));
BN_bn2bin (r, buf);
out_cstring ((void *)buf, 256);
out_long (E->key_fingerprint);
BN_clear_free (b);
BN_clear_free (g_a);
BN_clear_free (p);
BN_clear_free (r);
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_accept_methods, E);
}
int get_dh_config_on_answer (struct query *q UU) {
unsigned x = fetch_int ();
assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified);
if (x == CODE_messages_dh_config) {
encr_root = fetch_int ();
if (encr_prime) { free (encr_prime); }
int l = prefetch_strlen ();
assert (l == 256);
encr_prime = (void *)fetch_str_dup ();
encr_param_version = fetch_int ();
}
int l = prefetch_strlen ();
assert (l == 256);
unsigned char *random = (void *)fetch_str_dup ();
if (q->extra) {
do_send_accept_encr_chat (q->extra, random);
free (random);
} else {
free (random);
}
return 0;
}
struct query_methods get_dh_config_methods = {
.on_answer = get_dh_config_on_answer
};
void do_accept_encr_chat_request (struct secret_chat *E) {
assert (E->state == sc_request);
clear_packet ();
out_int (CODE_messages_get_dh_config);
out_int (encr_param_version);
out_int (256);
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, E);
}
int unread_messages;
int difference_got;
int seq, pts, qts, last_date;
int get_state_on_answer (struct query *q UU) {
assert (fetch_int () == (int)CODE_updates_state);
pts = fetch_int ();
qts = fetch_int ();
last_date = fetch_int ();
seq = fetch_int ();
unread_messages = fetch_int ();
write_state_file ();
difference_got = 1;
return 0;
}
int get_difference_on_answer (struct query *q UU) {
unsigned x = fetch_int ();
if (x == CODE_updates_difference_empty) {
fetch_date ();
fetch_seq ();
difference_got = 1;
} else if (x == CODE_updates_difference || x == CODE_updates_difference_slice) {
int n, i;
assert (fetch_int () == CODE_vector);
n = fetch_int ();
static struct message *ML[10000];
int ml_pos = 0;
for (i = 0; i < n; i++) {
if (ml_pos < 10000) {
ML[ml_pos ++] = fetch_alloc_message ();
} else {
fetch_alloc_message ();
}
}
assert (fetch_int () == CODE_vector);
n = fetch_int ();
for (i = 0; i < n; i++) {
if (ml_pos < 10000) {
ML[ml_pos ++] = fetch_alloc_encrypted_message ();
} else {
fetch_alloc_encrypted_message ();
}
}
assert (fetch_int () == CODE_vector);
n = fetch_int ();
for (i = 0; i < n; i++) {
work_update (0, 0);
}
assert (fetch_int () == CODE_vector);
n = fetch_int ();
for (i = 0; i < n; i++) {
fetch_alloc_chat ();
}
assert (fetch_int () == CODE_vector);
n = fetch_int ();
for (i = 0; i < n; i++) {
fetch_alloc_user ();
}
assert (fetch_int () == (int)CODE_updates_state);
pts = fetch_int ();
qts = fetch_int ();
last_date = fetch_int ();
seq = fetch_int ();
unread_messages = fetch_int ();
write_state_file ();
for (i = 0; i < ml_pos; i++) {
print_message (ML[i]);
}
if (x == CODE_updates_difference_slice) {
do_get_difference ();
} else {
difference_got = 1;
}
} else {
assert (0);
}
return 0;
}
struct query_methods get_state_methods = {
.on_answer = get_state_on_answer
};
struct query_methods get_difference_methods = {
.on_answer = get_difference_on_answer
};
void do_get_difference (void) {
difference_got = 0;
clear_packet ();
out_int (CODE_invoke_with_layer9);
out_int (CODE_init_connection);
out_int (TG_APP_ID);
if (allow_send_linux_version) {
struct utsname st;
uname (&st);
out_string (st.machine);
static char buf[1000000];
sprintf (buf, "%s %s %s", st.sysname, st.release, st.version);
out_string (buf);
out_string (TG_VERSION " (build " TG_BUILD ")");
out_string ("En");
} else {
out_string ("x86");
out_string ("Linux");
out_string (TG_VERSION);
out_string ("en");
}
if (seq > 0) {
out_int (CODE_updates_get_difference);
out_int (pts);
out_int (last_date);
out_int (qts);
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_difference_methods, 0);
} else {
out_int (CODE_updates_get_state);
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_state_methods, 0);
}
}

View File

@ -94,5 +94,8 @@ void do_import_auth (int num);
void do_export_auth (int num);
void do_add_contact (const char *phone, int phone_len, const char *first_name, int first_name_len, const char *last_name, int last_name_len, int force);
void do_msg_search (peer_id_t id, int from, int to, int limit, const char *s);
void do_accept_encr_chat_request (struct secret_chat *E);
void do_get_difference (void);
void do_mark_read (peer_id_t id);
#endif

View File

@ -32,6 +32,10 @@
int verbosity;
peer_t *Peers[MAX_USER_NUM];
int peer_num;
int encr_chats_allocated;
int geo_chats_allocated;
void fetch_file_location (struct file_location *loc) {
int x = fetch_int ();
if (x == CODE_file_location_unavailable) {
@ -68,8 +72,63 @@ void fetch_user_status (struct user_status *S) {
}
int our_id;
int user_num;
int chat_num;
char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4) {
const char *d[4];
d[0] = a1; d[1] = a2; d[2] = a3; d[3] = a4;
static char buf[10000];
int i;
int p = 0;
for (i = 0; i < 4; i++) {
if (d[i] && strlen (d[i])) {
p += snprintf (buf + p, 9999 - p, "%s%s", p ? "_" : "", d[i]);
assert (p < 9990);
}
}
char *s = buf;
while (*s) {
if (*s == ' ') { *s = '_'; }
s++;
}
s = buf;
int cc = 0;
while (1) {
int ok = 1;
int i;
for (i = 0; i < peer_num; i++) {
if (cmp_peer_id (Peers[i]->id, id) && Peers[i]->print_name && !strcmp (Peers[i]->print_name, s)) {
ok = 0;
break;
}
}
if (ok) {
break;
}
cc ++;
assert (cc <= 99);
if (cc == 1) {
int l = strlen (s);
s[l + 2] = 0;
s[l] = '#';
s[l + 1] = '1';
} else if (cc == 10) {
int l = strlen (s);
s[l + 1] = 0;
s[l] = '0';
s[l - 1] = '1';
} else {
int l = strlen (s);
s[l - 1] ++;
int cc = l - 1;
while (s[cc] > '9') {
s[cc] = '0';
s[cc - 1] ++;
cc --;
}
}
}
return strdup (s);
}
void fetch_user (struct user *U) {
unsigned x = fetch_int ();
@ -92,67 +151,8 @@ void fetch_user (struct user *U) {
if (U->print_name) { free (U->print_name); }
U->first_name = fetch_str_dup ();
U->last_name = fetch_str_dup ();
if (!strlen (U->first_name)) {
if (!strlen (U->last_name)) {
U->print_name = strdup ("none");
} else {
U->print_name = strdup (U->last_name);
}
} else {
if (!strlen (U->last_name)) {
U->print_name = strdup (U->first_name);
} else {
U->print_name = malloc (strlen (U->first_name) + strlen (U->last_name) + 2);
sprintf (U->print_name, "%s_%s", U->first_name, U->last_name);
}
}
char *s = U->print_name;
while (*s) {
if (*s == ' ') { *s = '_'; }
s++;
}
int cc = 0;
while (1) {
int ok = 1;
int i;
for (i = 0; i < user_num + chat_num; i++) {
if (Peers[i] != (void *)U && Peers[i]->print_name && !strcmp (Peers[i]->print_name, U->print_name)) {
ok = 0;
break;
}
}
if (ok) {
break;
}
cc ++;
assert (cc <= 99);
if (cc == 1) {
int l = strlen (U->print_name);
char *s = malloc (l + 3);
memcpy (s, U->print_name, l);
s[l + 2] = 0;
s[l] = '#';
s[l + 1] = '1';
free (U->print_name);
U->print_name = s;
} else if (cc == 10) {
int l = strlen (U->print_name);
char *s = malloc (l + 2);
memcpy (s, U->print_name, l);
s[l + 1] = 0;
s[l] = '0';
s[l - 1] = '1';
free (U->print_name);
U->print_name = s;
} else {
int l = strlen (U->print_name);
U->print_name[l - 1] ++;
if (U->print_name[l - 1] > '9') {
U->print_name[l - 1] = '0';
U->print_name[l - 2] ++;
}
}
}
U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0);
if (x == CODE_user_deleted) {
U->flags |= FLAG_DELETED;
return;
@ -197,20 +197,38 @@ void fetch_encrypted_chat (struct secret_chat *U) {
assert (x == CODE_encrypted_chat_empty || x == CODE_encrypted_chat_waiting || x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat || x == CODE_encrypted_chat_discarded);
U->id = MK_ENCR_CHAT (fetch_int ());
U->flags &= ~(FLAG_EMPTY | FLAG_DELETED);
enum secret_chat_state old_state = U->state;
if (x == CODE_encrypted_chat_empty) {
U->state = sc_none;
U->flags |= FLAG_EMPTY;
if (U->state != old_state) {
write_secret_chat_file ();
}
return;
}
if (x == CODE_encrypted_chat_discarded) {
U->state = sc_deleted;
U->flags |= FLAG_DELETED;
if (U->state != old_state) {
write_secret_chat_file ();
}
return;
}
U->access_hash = fetch_long ();
U->date = fetch_int ();
U->admin_id = fetch_int ();
U->user_id = fetch_int () + U->admin_id - our_id;
if (U->print_name) { free (U->print_name); }
peer_t *P = user_chat_get (MK_USER (U->user_id));
if (P) {
U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0);
} else {
static char buf[100];
sprintf (buf, "user#%d", U->user_id);
U->print_name = create_print_name (U->id, "!", buf, 0, 0);
}
if (x == CODE_encrypted_chat_waiting) {
U->state = sc_waiting;
} else if (x == CODE_encrypted_chat_requested) {
@ -218,26 +236,57 @@ void fetch_encrypted_chat (struct secret_chat *U) {
if (!U->g_key) {
U->g_key = malloc (256);
}
memset (U->g_key, 0, 256);
if (!U->nonce) {
U->nonce = malloc (256);
}
assert (prefetch_strlen () == 256);
memcpy (U->g_key, fetch_str (256), 256);
assert (prefetch_strlen () == 256);
memcpy (U->nonce, fetch_str (256), 256);
memset (U->nonce, 0, 256);
int l = prefetch_strlen ();
char *s = fetch_str (l);
if (l < 256) {
memcpy (U->g_key + 256 - l, s, l);
} else {
memcpy (U->g_key, s + (l - 256), 256);
}
l = prefetch_strlen ();
s = fetch_str (l);
if (l < 256) {
memcpy (U->nonce + 256 - l, s, l);
} else {
memcpy (U->nonce, s + (l - 256), 256);
}
} else {
U->state = sc_ok;
if (!U->g_key) {
U->g_key = malloc (256);
}
memset (U->g_key, 0, 256);
if (!U->nonce) {
U->nonce = malloc (256);
}
assert (prefetch_strlen () == 256);
memcpy (U->g_key, fetch_str (256), 256);
assert (prefetch_strlen () == 256);
memcpy (U->nonce, fetch_str (256), 256);
memset (U->nonce, 0, 256);
int l = prefetch_strlen ();
char *s = fetch_str (l);
if (l < 256) {
memcpy (U->g_key + 256 - l, s, l);
} else {
memcpy (U->g_key, s + (l - 256), 256);
}
l = prefetch_strlen ();
s = fetch_str (l);
if (l < 256) {
memcpy (U->nonce + 256 - l, s, l);
} else {
memcpy (U->nonce, s + (l - 256), 256);
}
if (!U->key_fingerprint) {
U->key_fingerprint = fetch_long ();
} else {
assert (U->key_fingerprint == fetch_long ());
}
}
if (U->state != old_state) {
write_secret_chat_file ();
}
}
@ -294,12 +343,7 @@ void fetch_chat (struct chat *C) {
if (C->title) { free (C->title); }
if (C->print_title) { free (C->print_title); }
C->title = fetch_str_dup ();
C->print_title = strdup (C->title);
char *s = C->print_title;
while (*s) {
if (*s == ' ') { *s = '_'; }
s ++;
}
C->print_title = create_print_name (C->id, C->title, 0, 0, 0);
if (x == CODE_chat) {
unsigned y = fetch_int ();
if (y == CODE_chat_photo_empty) {
@ -499,9 +543,9 @@ void fetch_message_short (struct message *M) {
M->to_id = MK_USER (our_id);
M->from_id = MK_USER (fetch_int ());
M->message = fetch_str_dup ();
fetch_int (); // pts
fetch_pts ();
M->date = fetch_int ();
fetch_int (); // seq
fetch_seq ();
M->media.type = CODE_message_media_empty;
M->unread = 1;
}
@ -512,9 +556,9 @@ void fetch_message_short_chat (struct message *M) {
M->from_id = MK_USER (fetch_int ());
M->to_id = MK_CHAT (fetch_int ());
M->message = fetch_str_dup ();
fetch_int (); // pts
fetch_pts ();
M->date = fetch_int ();
fetch_int (); // seq
fetch_seq ();
M->media.type = CODE_message_media_empty;
M->unread = 1;
}
@ -554,7 +598,7 @@ void fetch_message_media_encrypted (struct message_media *M) {
memset (M, 0, sizeof (*M));
unsigned x = fetch_int ();
int l;
switch (M->type) {
switch (x) {
case CODE_decrypted_message_media_empty:
M->type = CODE_message_media_empty;
break;
@ -567,15 +611,25 @@ void fetch_message_media_encrypted (struct message_media *M) {
M->encr_photo.w = fetch_int ();
M->encr_photo.h = fetch_int ();
M->encr_photo.size = fetch_int ();
l = fetch_int ();
assert (l > 0);
M->encr_photo.key = malloc (l);
memcpy (M->encr_photo.key, fetch_str (l), l);
l = fetch_int ();
l = prefetch_strlen ();
assert (l > 0);
M->encr_photo.iv = malloc (l);
memcpy (M->encr_photo.iv, fetch_str (l), l);
M->encr_photo.key = malloc (32);
memset (M->encr_photo.key, 0, 32);
if (l <= 32) {
memcpy (M->encr_photo.key + (32 - l), fetch_str (l), l);
} else {
memcpy (M->encr_photo.key, fetch_str (l) + (l - 32), 32);
}
M->encr_photo.iv = malloc (32);
l = prefetch_strlen ();
assert (l > 0);
memset (M->encr_photo.iv, 0, 32);
if (l <= 32) {
memcpy (M->encr_photo.iv + (32 - l), fetch_str (l), l);
} else {
memcpy (M->encr_photo.iv, fetch_str (l) + (l - 32), 32);
}
break;
case CODE_decrypted_message_media_video:
M->type = x;
@ -587,15 +641,25 @@ void fetch_message_media_encrypted (struct message_media *M) {
M->encr_video.h = fetch_int ();
M->encr_video.size = fetch_int ();
M->encr_video.duration = fetch_int ();
l = fetch_int ();
assert (l > 0);
M->encr_video.key = malloc (l);
memcpy (M->encr_video.key, fetch_str (l), l);
l = fetch_int ();
l = prefetch_strlen ();
assert (l > 0);
M->encr_video.iv = malloc (l);
memcpy (M->encr_video.iv, fetch_str (l), l);
M->encr_video.key = malloc (32);
memset (M->encr_photo.key, 0, 32);
if (l <= 32) {
memcpy (M->encr_video.key + (32 - l), fetch_str (l), l);
} else {
memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32);
}
M->encr_video.iv = malloc (32);
l = prefetch_strlen ();
assert (l > 0);
memset (M->encr_video.iv, 0, 32);
if (l <= 32) {
memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l);
} else {
memcpy (M->encr_video.iv, fetch_str (l) + (l - 32), 32);
}
break;
/* case CODE_decrypted_message_media_file:
M->type = x;
@ -719,24 +783,26 @@ int decrypt_encrypted_message (struct secret_chat *E) {
memcpy (buf + 16, E->key + 24, 32);
sha1 (buf, 48, sha1d_buffer);
static unsigned char iv[32];
memcpy (iv, sha1a_buffer + 0, 8);
memcpy (iv + 8, sha1b_buffer + 8, 12);
memcpy (iv + 20, sha1c_buffer + 4, 12);
static unsigned char key[32];
memcpy (key, sha1a_buffer + 8, 12);
memcpy (key + 12, sha1b_buffer + 0, 8);
memcpy (key + 20, sha1c_buffer + 16, 4);
memcpy (key + 24, sha1d_buffer + 0, 8);
memcpy (key, sha1a_buffer + 0, 8);
memcpy (key + 8, sha1b_buffer + 8, 12);
memcpy (key + 20, sha1c_buffer + 4, 12);
static unsigned char iv[32];
memcpy (iv, sha1a_buffer + 8, 12);
memcpy (iv + 12, sha1b_buffer + 0, 8);
memcpy (iv + 20, sha1c_buffer + 16, 4);
memcpy (iv + 24, sha1d_buffer + 0, 8);
AES_KEY aes_key;
AES_set_decrypt_key (key, 256, &aes_key);
AES_ige_encrypt ((void *)decr_ptr, (void *)decr_ptr, 4 * (decr_end - decr_ptr), &aes_key, iv, 0);
sha1 ((void *)decr_ptr, 4 * (decr_end - decr_ptr), sha1a_buffer);
int x = *(decr_ptr);
assert (x >= 0 && !(x & 3));
sha1 ((void *)decr_ptr, 4 + x, sha1a_buffer);
if (memcmp (sha1a_buffer, msg_key, 16)) {
if (memcmp (sha1a_buffer + 4, msg_key, 16)) {
logprintf ("Sha1 mismatch\n");
return -1;
}
@ -747,39 +813,71 @@ void fetch_encrypted_message (struct message *M) {
memset (M, 0, sizeof (*M));
unsigned x = fetch_int ();
assert (x == CODE_encrypted_message || x == CODE_encrypted_message_service);
peer_id_t chat = MK_ENCR_CHAT (fetch_int ());
unsigned sx = x;
M->id = fetch_long ();
peer_id_t chat = MK_ENCR_CHAT (fetch_int ());
M->to_id = chat;
peer_t *P = user_chat_get (chat);
if (!P) {
logprintf ("Encrypted message to unknown chat. Dropping\n");
M->flags |= FLAG_EMPTY;
}
M->date = fetch_int ();
int len = prefetch_strlen ();
assert (!(len & 15));
assert ((len & 15) == 8);
decr_ptr = (void *)fetch_str (len);
decr_end = in_ptr;
decr_end = decr_ptr + (len / 4);
M->flags |= FLAG_ENCRYPTED;
int ok = 0;
if (P) {
if (*(long long *)decr_ptr != P->encr_chat.key_fingerprint) {
logprintf ("Encrypted message with bad fingerprint to chat %s\n", P->print_name);
P = 0;
}
decr_ptr += 2;
}
if (P && decrypt_encrypted_message (&P->encr_chat) >= 0) {
ok = 1;
int *save_in_ptr = in_ptr;
int *save_in_end = in_end;
in_ptr = decr_ptr;
int l = fetch_int ();
in_end = in_ptr + l;
unsigned x = fetch_int ();
if (x == CODE_decrypted_message_layer) {
int layer = fetch_int ();
assert (layer >= 0);
x = fetch_int ();
}
assert (x == CODE_decrypted_message);
assert (x == CODE_decrypted_message || x == CODE_decrypted_message_service);
assert (M->id = fetch_long ());
int l = prefetch_strlen ();
l = prefetch_strlen ();
fetch_str (l); // random_bytes
M->from_id = MK_USER (fetch_int ());
M->date = fetch_int ();
if (x == CODE_decrypted_message) {
M->message = fetch_str_dup ();
fetch_encrypted_message_file (&M->media);
fetch_message_media_encrypted (&M->media);
} else {
assert (fetch_int () == (int)CODE_decrypted_message_action_set_message_t_t_l);
P->encr_chat.ttl = fetch_int ();
M->service = 1;
}
in_ptr = save_in_ptr;
in_end = save_in_end;
}
if (sx == CODE_encrypted_message) {
if (ok) {
fetch_encrypted_message_file (&M->media);
} else {
x = fetch_int ();
if (x == CODE_encrypted_file) {
fetch_skip (7);
} else {
assert (x == CODE_encrypted_file_empty);
}
M->media.type = CODE_message_media_empty;
}
}
}
@ -793,7 +891,8 @@ void fetch_encrypted_message_file (struct message_media *M) {
assert (M->type == CODE_decrypted_message_media_photo || M->type == CODE_decrypted_message_media_video);
M->encr_photo.id = fetch_long ();
M->encr_photo.access_hash = fetch_long ();
assert (M->encr_photo.size == fetch_int ());
//assert (M->encr_photo.size == fetch_int ());
M->encr_photo.size = fetch_int (); // Why it is not the same?
M->encr_photo.dc_id = fetch_int ();
M->encr_photo.key_fingerprint = fetch_int ();
@ -813,8 +912,6 @@ DEFINE_TREE(message,struct message *,id_cmp,0)
struct tree_peer *peer_tree;
struct tree_message *message_tree;
int chat_num;
int user_num;
int users_allocated;
int chats_allocated;
int messages_allocated;
@ -837,7 +934,7 @@ struct user *fetch_alloc_user (void) {
memset (U, 0, sizeof (*U));
fetch_user (&U->user);
peer_tree = tree_insert_peer (peer_tree, U, lrand48 ());
Peers[chat_num + (user_num ++)] = U;
Peers[peer_num ++] = U;
return &U->user;
}
}
@ -850,16 +947,22 @@ struct secret_chat *fetch_alloc_encrypted_chat (void) {
fetch_encrypted_chat (&U->encr_chat);
return &U->encr_chat;
} else {
chats_allocated ++;
encr_chats_allocated ++;
U = malloc (sizeof (*U));
memset (U, 0, sizeof (*U));
fetch_encrypted_chat (&U->encr_chat);
peer_tree = tree_insert_peer (peer_tree, U, lrand48 ());
Peers[(chat_num ++) + user_num] = U;
Peers[peer_num ++] = U;
return &U->encr_chat;
}
}
void insert_encrypted_chat (peer_t *P) {
encr_chats_allocated ++;
peer_tree = tree_insert_peer (peer_tree, P, lrand48 ());
Peers[peer_num ++] = P;
}
struct user *fetch_alloc_user_full (void) {
int data[3];
prefetch_data (data, 12);
@ -874,7 +977,7 @@ struct user *fetch_alloc_user_full (void) {
U->id = MK_USER (data[2]);
peer_tree = tree_insert_peer (peer_tree, U, lrand48 ());
fetch_user_full (&U->user);
Peers[chat_num + (user_num ++ )] = U;
Peers[peer_num ++] = U;
return &U->user;
}
}
@ -938,6 +1041,8 @@ void free_message_media (struct message_media *M) {
free (M->encr_video.key);
free (M->encr_video.iv);
return;
case 0:
break;
default:
logprintf ("%08x\n", M->type);
assert (0);
@ -964,6 +1069,8 @@ void free_message_action (struct message_action *M) {
break;
case CODE_message_action_chat_delete_user:
break;
case 0:
break;
default:
assert (0);
}
@ -990,6 +1097,61 @@ void message_add_use (struct message *M) {
M->prev_use->next_use = M;
}
void message_add_peer (struct message *M) {
peer_id_t id;
if (!cmp_peer_id (M->to_id, MK_USER (our_id))) {
id = M->from_id;
} else {
id = M->to_id;
}
peer_t *P = user_chat_get (id);
if (!P) {
P = malloc (sizeof (*P));
memset (P, 0, sizeof (*P));
P->id = id;
P->flags = FLAG_EMPTY;
switch (get_peer_type (id)) {
case PEER_USER:
users_allocated ++;
break;
case PEER_CHAT:
chats_allocated ++;
break;
case PEER_GEO_CHAT:
geo_chats_allocated ++;
break;
case PEER_ENCR_CHAT:
encr_chats_allocated ++;
break;
}
peer_tree = tree_insert_peer (peer_tree, P, lrand48 ());
Peers[peer_num ++] = P;
}
M->next = P->last;
if (M->next) { M->next->prev = M; }
M->prev = 0;
P->last = M;
}
void message_del_peer (struct message *M) {
peer_id_t id;
if (!cmp_peer_id (M->to_id, MK_USER (our_id))) {
id = M->from_id;
} else {
id = M->to_id;
}
peer_t *P = user_chat_get (id);
if (M->prev) {
M->prev->next = M->next;
}
if (M->next) {
M->next->prev = M->prev;
}
if (P && P->last == M) {
P->last = M->next;
}
}
struct message *fetch_alloc_message (void) {
struct message *M = malloc (sizeof (*M));
fetch_message (M);
@ -997,14 +1159,17 @@ struct message *fetch_alloc_message (void) {
messages_allocated ++;
if (M1) {
message_del_use (M1);
message_del_peer (M1);
free_message (M1);
memcpy (M1, M, sizeof (*M));
free (M);
message_add_use (M1);
message_add_peer (M1);
messages_allocated --;
return M1;
} else {
message_add_use (M);
message_add_peer (M);
message_tree = tree_insert_message (message_tree, M, lrand48 ());
return M;
}
@ -1017,14 +1182,17 @@ struct message *fetch_alloc_geo_message (void) {
messages_allocated ++;
if (M1) {
message_del_use (M1);
message_del_peer (M1);
free_message (M1);
memcpy (M1, M, sizeof (*M));
free (M);
message_add_use (M1);
message_add_peer (M1);
messages_allocated --;
return M1;
} else {
message_add_use (M);
message_add_peer (M);
message_tree = tree_insert_message (message_tree, M, lrand48 ());
return M;
}
@ -1037,14 +1205,17 @@ struct message *fetch_alloc_encrypted_message (void) {
messages_allocated ++;
if (M1) {
message_del_use (M1);
message_del_peer (M1);
free_message (M1);
memcpy (M1, M, sizeof (*M));
free (M);
message_add_use (M1);
message_add_peer (M1);
messages_allocated --;
return M1;
} else {
message_add_use (M);
message_add_peer (M);
message_tree = tree_insert_message (message_tree, M, lrand48 ());
return M;
}
@ -1057,14 +1228,17 @@ struct message *fetch_alloc_message_short (void) {
messages_allocated ++;
if (M1) {
message_del_use (M1);
message_del_peer (M1);
free_message (M1);
memcpy (M1, M, sizeof (*M));
free (M);
message_add_use (M1);
message_add_peer (M1);
messages_allocated --;
return M1;
} else {
message_add_use (M);
message_add_peer (M);
message_tree = tree_insert_message (message_tree, M, lrand48 ());
return M;
}
@ -1080,14 +1254,17 @@ struct message *fetch_alloc_message_short_chat (void) {
messages_allocated ++;
if (M1) {
message_del_use (M1);
message_del_peer (M1);
free_message (M1);
memcpy (M1, M, sizeof (*M));
free (M);
message_add_use (M1);
message_add_peer (M1);
messages_allocated --;
return M1;
} else {
message_add_use (M);
message_add_peer (M);
message_tree = tree_insert_message (message_tree, M, lrand48 ());
return M;
}
@ -1106,7 +1283,7 @@ struct chat *fetch_alloc_chat (void) {
memset (U, 0, sizeof (*U));
fetch_chat (&U->chat);
peer_tree = tree_insert_peer (peer_tree, U, lrand48 ());
Peers[(chat_num ++) + user_num] = U;
Peers[peer_num ++] = U;
return &U->chat;
}
}
@ -1125,7 +1302,7 @@ struct chat *fetch_alloc_chat_full (void) {
U->id = MK_CHAT (data[2]);
peer_tree = tree_insert_peer (peer_tree, U, lrand48 ());
fetch_chat_full (&U->chat);
Peers[(chat_num ++) + user_num] = U;
Peers[peer_num ++] = U;
return &U->chat;
}
}
@ -1139,9 +1316,13 @@ int print_stat (char *s, int len) {
return snprintf (s, len,
"users_allocated\t%d\n"
"chats_allocated\t%d\n"
"secret_chats_allocated\t%d\n"
"peer_num\t%d\n"
"messages_allocated\t%d\n",
users_allocated,
chats_allocated,
encr_chats_allocated,
peer_num,
messages_allocated
);
}
@ -1166,5 +1347,6 @@ void update_message_id (struct message *M, long long id) {
void message_insert (struct message *M) {
message_add_use (M);
message_add_peer (M);
message_tree = tree_insert_message (message_tree, M, lrand48 ());
}

View File

@ -20,7 +20,7 @@
#define __STRUCTURES_H__
#include <assert.h>
typedef struct { int id; } peer_id_t;
typedef struct { int type; int id; } peer_id_t;
#define FLAG_EMPTY 1
#define FLAG_DELETED 2
@ -111,6 +111,7 @@ struct user_status {
struct user {
peer_id_t id;
int flags;
struct message *last;
char *print_name;
struct file_location photo_big;
struct file_location photo_small;
@ -134,6 +135,7 @@ struct chat_user {
struct chat {
peer_id_t id;
int flags;
struct message *last;
char *print_title;
struct file_location photo_big;
struct file_location photo_small;
@ -157,6 +159,7 @@ enum secret_chat_state {
struct secret_chat {
peer_id_t id;
int flags;
struct message *last;
char *print_name;
struct file_location photo_big;
struct file_location photo_small;
@ -178,6 +181,7 @@ typedef union peer {
struct {
peer_id_t id;
int flags;
struct message *last;
char *print_name;
struct file_location photo_big;
struct file_location photo_small;
@ -237,6 +241,7 @@ struct message_media {
struct message {
struct message *next_use, *prev_use;
struct message *next, *prev;
long long id;
int flags;
peer_id_t fwd_from_id;
@ -283,6 +288,7 @@ void update_message_id (struct message *M, long long id);
void message_insert (struct message *M);
void free_photo (struct photo *P);
void fetch_photo (struct photo *P);
void insert_encrypted_chat (peer_t *P);
#define PEER_USER 1
#define PEER_CHAT 2
@ -296,55 +302,18 @@ void fetch_photo (struct photo *P);
#define MK_ENCR_CHAT(id) set_peer_id (PEER_ENCR_CHAT,id)
static inline int get_peer_type (peer_id_t id) {
if (id.id > 1000000000) {
return PEER_ENCR_CHAT;
}
if (id.id > 0) {
return PEER_USER;
}
if (id.id < -1000000000) {
return PEER_GEO_CHAT;
}
if (id.id < 0) {
return PEER_CHAT;
}
return PEER_UNKNOWN;
return id.type;
}
static inline int get_peer_id (peer_id_t id) {
switch (get_peer_type (id)) {
case PEER_USER:
return id.id;
case PEER_CHAT:
return -id.id;
case PEER_GEO_CHAT:
return -id.id - 1000000000;
case PEER_ENCR_CHAT:
return id.id - 1000000000;
default:
return 0;
}
}
static inline peer_id_t set_peer_id (int type, int id) {
peer_id_t ID;
switch (type) {
case PEER_USER:
ID.id = id;
ID.type = type;
return ID;
case PEER_CHAT:
ID.id = -id;
return ID;
case PEER_GEO_CHAT:
ID.id = -id - 1000000000;
return ID;
case PEER_ENCR_CHAT:
ID.id = id + 1000000000;
return ID;
default:
assert (0);
return ID;
}
}
static inline int cmp_peer_id (peer_id_t a, peer_id_t b) {