diff --git a/interface.c b/interface.c index 536d3bc..e708db6 100644 --- a/interface.c +++ b/interface.c @@ -78,12 +78,12 @@ char *next_token (int *l) { #define NOT_FOUND (int)0x80000000 peer_id_t PEER_NOT_FOUND = {.id = NOT_FOUND}; -int next_token_int (void) { +long long next_token_int (void) { int l; char *s = next_token (&l); if (!s) { return NOT_FOUND; } char *r; - int x = strtod (s, &r); + long long x = strtoll (s, &r, 10); if (r == s + l) { return x; } else { @@ -139,6 +139,22 @@ peer_id_t next_token_chat (void) { } } +peer_id_t next_token_encr_chat (void) { + int l; + char *s = next_token (&l); + if (!s) { return PEER_NOT_FOUND; } + + int index = 0; + while (index < peer_num && (!is_same_word (s, l, Peers[index]->print_name) || get_peer_type (Peers[index]->id) != PEER_ENCR_CHAT)) { + index ++; + } + if (index < peer_num) { + return Peers[index]->id; + } else { + return PEER_NOT_FOUND; + } +} + peer_id_t next_token_peer (void) { int l; char *s = next_token (&l); @@ -232,6 +248,7 @@ char *commands[] = { "show_license", "search", "mark_read", + "visualize_key", 0 }; int commands_flags[] = { @@ -259,6 +276,7 @@ int commands_flags[] = { 07, 072, 072, + 075, }; int get_complete_mode (void) { @@ -322,6 +340,19 @@ int complete_chat_list (int index, const char *text, int len, char **R) { } } +int complete_encr_chat_list (int index, const char *text, int len, char **R) { + index ++; + while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len) || get_peer_type (Peers[index]->id) != PEER_ENCR_CHAT)) { + index ++; + } + if (index < peer_num) { + *R = strdup (Peers[index]->print_name); + return index; + } else { + return -1; + } +} + int complete_user_chat_list (int index, const char *text, int len, char **R) { index ++; while (index < peer_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { @@ -390,6 +421,10 @@ char *command_generator (const char *text, int state) { index = complete_chat_list (index, text, len, &R); if (c) { rl_line_buffer[rl_point] = c; } return R; + case 5: + index = complete_encr_chat_list (index, text, len, &R); + if (c) { rl_line_buffer[rl_point] = c; } + return R; default: if (c) { rl_line_buffer[rl_point] = c; } return 0; @@ -446,7 +481,13 @@ void interpreter (char *line UU) { #define GET_PEER_CHAT \ id = next_token_chat (); \ if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ - printf ("Bad char id\n"); \ + printf ("Bad chat id\n"); \ + RET; \ + } +#define GET_PEER_ENCR_CHAT \ + id = next_token_encr_chat (); \ + if (!cmp_peer_id (id, PEER_NOT_FOUND)) { \ + printf ("Bad encr_chat id\n"); \ RET; \ } @@ -512,34 +553,38 @@ void interpreter (char *line UU) { } do_forward_message (id, num); } else if (IS_WORD ("load_photo")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { do_load_photo (&M->media.photo, 1); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_photo) { + do_load_encr_video (&M->media.encr_video, 1); // this is not a bug. } else { printf ("Bad msg id\n"); RET; } } else if (IS_WORD ("view_photo")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { do_load_photo (&M->media.photo, 2); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_photo) { + do_load_encr_video (&M->media.encr_video, 2); // this is not a bug. } else { printf ("Bad msg id\n"); RET; } } else if (IS_WORD ("load_video_thumb")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } @@ -551,8 +596,8 @@ void interpreter (char *line UU) { RET; } } else if (IS_WORD ("view_video_thumb")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } @@ -564,27 +609,31 @@ void interpreter (char *line UU) { RET; } } else if (IS_WORD ("load_video")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_video) { do_load_video (&M->media.video, 1); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_video) { + do_load_encr_video (&M->media.encr_video, 1); } else { printf ("Bad msg id\n"); RET; } } else if (IS_WORD ("view_video")) { - int num = next_token_int (); - if (num == NOT_FOUND || num <= 0) { + long long num = next_token_int (); + if (num == NOT_FOUND) { printf ("Bad msg id\n"); RET; } struct message *M = message_get (num); if (M && !M->service && M->media.type == (int)CODE_message_media_video) { do_load_video (&M->media.video, 2); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_video) { + do_load_encr_video (&M->media.encr_video, 2); } else { printf ("Bad msg id\n"); RET; @@ -691,6 +740,9 @@ void interpreter (char *line UU) { } else if (IS_WORD ("mark_read")) { GET_PEER; do_mark_read (id); + } else if (IS_WORD ("visualize_key")) { + GET_PEER_ENCR_CHAT; + do_visualize_key (id); } #undef IS_WORD #undef RET diff --git a/interface.h b/interface.h index 1a4bd32..c9529a6 100644 --- a/interface.h +++ b/interface.h @@ -29,6 +29,9 @@ #define COLOR_BLUE "\033[34;1m" #define COLOR_MAGENTA "\033[35;1m" #define COLOR_CYAN "\033[36;1m" +#define COLOR_LCYAN "\033[0;36m" + +#define COLOR_INVERSE "\033[7m" char *get_default_prompt (void); char *complete_none (const char *text, int state); diff --git a/mtproto-client.c b/mtproto-client.c index 467d4a8..d4da57f 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -1050,11 +1050,24 @@ void work_update (struct connection *c UU, long long msg_id UU) { peer_id_t id = MK_ENCR_CHAT (fetch_int ()); // chat_id fetch_int (); // max_date fetch_int (); // date + peer_t *P = user_chat_get (id); + int x = -1; + if (P && P->last) { + x = 0; + struct message *M = P->last; + while (M && (!M->out || M->unread)) { + if (M->out) { + M->unread = 0; + x ++; + } + M = M->next; + } + } print_start (); push_color (COLOR_YELLOW); - printf ("Messages in encrypted chat "); + printf ("Encrypted chat "); print_encr_chat_name_full (id, user_chat_get (id)); - printf (" marked read \n"); + printf (": %d messages marked read \n", x); pop_color (); print_end (); } diff --git a/no-preview.h b/no-preview.h new file mode 100644 index 0000000..a15eb18 --- /dev/null +++ b/no-preview.h @@ -0,0 +1,84 @@ +int thumb_file_size = (82 * 6 - 2) * 4; +int thumb_file [] = { +0xe0ffd8ff, 0x464a1000, 0x01004649, 0x64000101, 0x00006400, 0xa002e2ff, +0x5f434349, 0x464f5250, 0x00454c49, 0x00000101, 0x636c9002, 0x3004736d, +0x6e6d0000, 0x47527274, 0x59582042, 0xdd07205a, 0x04000b00, 0x1b001600, +0x63612400, 0x50417073, 0x00004c50, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x0100d6f6, 0x00000000, 0x636c2dd3, +0x0000736d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x65640b00, 0x00006373, 0x00000801, 0x70633800, 0x00007472, 0x00004001, +0x74774e00, 0x00007470, 0x00009001, 0x68631400, 0x00006461, 0x0000a401, +0x58722c00, 0x00005a59, 0x0000d001, 0x58621400, 0x00005a59, 0x0000e401, +0x58671400, 0x00005a59, 0x0000f801, 0x54721400, 0x00004352, 0x00000c02, +0x54672000, 0x00004352, 0x00002c02, 0x54622000, 0x00004352, 0x00004c02, +0x68632000, 0x00006d72, 0x00006c02, 0x6c6d2400, 0x00006375, 0x00000000, +0x00000100, 0x6e650c00, 0x00005355, 0x00001c00, 0x73001c00, 0x47005200, +0x20004200, 0x75006200, 0x6c006900, 0x2d007400, 0x6e006900, 0x6c6d0000, +0x00006375, 0x00000000, 0x00000100, 0x6e650c00, 0x00005355, 0x00003200, +0x4e001c00, 0x20006f00, 0x6f006300, 0x79007000, 0x69007200, 0x68006700, +0x2c007400, 0x75002000, 0x65007300, 0x66002000, 0x65007200, 0x6c006500, +0x00007900, 0x59580000, 0x0000205a, 0x00000000, 0x0100d6f6, 0x00000000, +0x66732dd3, 0x00003233, 0x01000000, 0x00004a0c, 0xffffe305, 0x00002af3, +0x00009b07, 0xffff87fd, 0xffffa2fb, 0x0000a3fd, 0x0000d803, 0x595894c0, +0x0000205a, 0x00000000, 0x0000946f, 0x0000ee38, 0x59589003, 0x0000205a, +0x00000000, 0x00009d24, 0x0000830f, 0x5958beb6, 0x0000205a, 0x00000000, +0x0000a562, 0x000090b7, 0x6170de18, 0x00006172, 0x03000000, 0x02000000, +0x00006666, 0x0000a7f2, 0x0000590d, 0x0000d013, 0x61705b0a, 0x00006172, +0x03000000, 0x02000000, 0x00006666, 0x0000a7f2, 0x0000590d, 0x0000d013, +0x61705b0a, 0x00006172, 0x03000000, 0x02000000, 0x00006666, 0x0000a7f2, +0x0000590d, 0x0000d013, 0x68635b0a, 0x00006d72, 0x03000000, 0x00000000, +0x0000d7a3, 0x00007b54, 0x0000cd4c, 0x00009a99, 0x00006626, 0xdbff5c0f, +0x14004300, 0x0f120f0e, 0x1112140d, 0x14161712, 0x21331f18, 0x1f1c1c1f, +0x252f2d3f, 0x4e414a33, 0x4841494d, 0x765c5246, 0x6f575264, 0x66484658, +0x7a6f688c, 0x8485847d, 0x9b91634f, 0x769a808f, 0xff7f8481, 0x014300db, +0x1f171716, 0x213c1f1b, 0x547f3c21, 0x7f7f5448, 0x7f7f7f7f, 0x7f7f7f7f, +0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, +0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x1100c0ff, 0x005a0008, +0x2201035a, 0x01110200, 0xff011103, 0x001900c4, 0x01010101, 0x00000101, +0x00000000, 0x00000000, 0x02030400, 0xc4ff0605, 0x00103600, 0x02010401, +0x06050304, 0x00000306, 0x01000000, 0x11030200, 0x05211204, 0x13514131, +0x32146122, 0x23918171, 0x72423424, 0x432515a1, 0xa2827444, 0xc4fff0b3, +0x01011400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1400c4ff, +0x00000111, 0x00000000, 0x00000000, 0x00000000, 0xdaff0000, 0x01030c00, +0x03110200, 0x003f0011, 0x404434fb, 0xbcb4875c, 0x006b38b0, 0x03dcdb12, +0xf4637f74, 0xe519f153, 0x09d7c5c7, 0x47d29160, 0x20692f18, 0xd06d786a, +0x53f7f922, 0x17b3e260, 0x2fe8668c, 0x1786a473, 0x9775efbd, 0xe917e43a, +0x1d0a1bb0, 0x114d0f82, 0x14651110, 0x35f299ed, 0xe9b09680, 0xf5a4fc2f, +0xe975bd03, 0xb506737b, 0x04444440, 0x5c444044, 0x8e8dedbd, 0xc61adc7b, +0x689c738b, 0x92a0dc01, 0x58e2b77f, 0x7bfb37d1, 0xb5b5e79d, 0xdbf968cc, +0xead3f48d, 0x38ed1313, 0xdea77c86, 0xae089963, 0xc743435a, 0x403fe4ce, +0x392ee1b9, 0xed39e718, 0xd6517e2d, 0x7fc4aa03, 0xb7ad7590, 0x77e7e6ab, +0x34bf705d, 0x7c77ca53, 0x3dea1299, 0x7fb0bcf4, 0x241fadc5, 0x95a7a816, +0x13fbe6f3, 0x3182b135, 0xd1b4b224, 0x1b0d48a2, 0xbf9d26d8, 0x82dc3640, +0x63569a2a, 0xbbd224c3, 0xb9b4714c, 0x1680aec6, 0x3d311856, 0x9b59be91, +0x09876ca6, 0x61d86564, 0x5a9f06d2, 0x36f51b0d, 0x8682e476, 0xacb1b131, +0xd1584363, 0x00456b4d, 0x22d2053b, 0x22202202, 0xf3f30222, 0xe3e513e5, +0xf1e6e1f0, 0x2380496e, 0x5fdcdb68, 0x549b3a27, 0x825e6a6c, 0x6522028b, +0xaf91ccc8, 0x341cf26b, 0x58dbc4b5, 0xf2289add, 0x0854ddbd, 0x0b9247d5, +0xf02b5c54, 0x3f917f92, 0xaf56affd, 0xe3760637, 0x05cebde0, 0xed4c76ce, +0x3cef1b63, 0x7fd8aff8, 0xa0c902ea, 0x7e730d0a, 0x435834f3, 0x26edbb76, +0xd3ec00fd, 0x76d48efa, 0xa8560f2d, 0x0e766331, 0xd319993c, 0x20243209, +0x61b7e6c8, 0x998331d0, 0x640ee802, 0x47a3d493, 0xfab99413, 0x4fd871f1, +0xe9443792, 0x627e051c, 0xd8f3051c, 0x2f28f558, 0x64b51745, 0x1b2bfee3, +0xb8783953, 0x9900fff6, 0xd8176a65, 0x5a3bf56a, 0x1b331fdb, 0x64b3572f, +0xd59a3643, 0xaf3abce1, 0x11dd20bd, 0x01111110, 0x5c141011, 0xb3e3083f, +0xd9b19cc4, 0x17edb20e, 0xa78e9aa1, 0x4ef4de06, 0x00c0bfe7, 0x7e1e442d, +0x9221fe38, 0xedb5c7dc, 0x6338078a, 0x62495b8d, 0xc11d9b8c, 0x49e81b16, +0x51d02bea, 0x3eb86d70, 0xc8bc4f13, 0xa10ec758, 0xd40751c0, 0x5ac94710, +0xc4c8b080, 0x95492b83, 0x975ee696, 0xb7bd96b4, 0x17379cce, 0x82e856e8, +0xe4c2c82a, 0x398e935f, 0x632437ea, 0x7c9c87d2, 0xdc1ddb7c, 0x65a80a48, +0x2309f164, 0x51fab475, 0x081dc11d, 0xda45573b, 0x6622f3f3, 0x48f1b214, +0x676c4edb, 0x243468c7, 0x00ffde60, 0xf1630350, 0xa0076c1d, 0x8f2c0c8b, +0x2383c26b, 0x361a8f4e, 0xaceea6c9, 0x01dd5a5d, 0x11111011, 0xc3780c04, +0xbf093ee2, 0xc7972c0b, 0x00d99040, 0xc0c20eb7, 0x659d3bd4, 0x269ab85e, +0x468e114f, 0x11ad4fdb, 0x83d083d8, 0x8c52f4bd, 0x3c9664bf, 0xa4f9c77c, +0x22a68876, 0xadb18784, 0xf480be83, 0x885a00ea, 0x220e0a88, 0xc303e4f6, +0xc866e058, 0xdddbd661, 0xdf395db1, 0xbad64343, 0xe6e65b03, 0x668e81c3, +0xad619e98, 0xeeb94563, 0xd4d19a3c, 0x3316ce95, 0x9d65f1e1, 0x3bf324fe, +0x0e468f53, 0xc386068c, 0xa89e24f7, 0xf0c7c73b, 0xb60e391f, 0x1b8827cb, +0x58601954, 0xc54f90f9, 0x80886ec5, 0x88088888, 0x1b7bb980, 0xb4c71c23, +0xe6148e39, 0xb12358b8, 0xbd08225d, 0x0ffef085, 0x72b4f025, 0x635ce389, +0xb90277e4, 0x0d05e000, 0x9bf9dbb9, 0x8e749fbc, 0x7ee6abbf, 0x4ddbf4af, +0x728df7f3, 0x10b59adf, 0xe3c38f49, 0xb23c638a, 0xdb3d9349, 0x66899a64, +0x00004dd5, 0xf51b5adf, 0x2220a255, 0xd9ff0f22}; diff --git a/queries.c b/queries.c index b014aef..422818c 100644 --- a/queries.c +++ b/queries.c @@ -41,6 +41,9 @@ #include #include #include +#include + +#include "no-preview.h" #define sha1 SHA1 @@ -282,6 +285,16 @@ int new_dc_num; extern struct dc *DC_list[]; extern struct dc *DC_working; +void out_random (int n) { + assert (n <= 16); + static char buf[16]; + int i; + for (i = 0; i < n; i++) { + buf[i] = lrand48 () & 255; + } + out_cstring (buf, n); +} + /* {{{ Get config */ int help_get_config_on_answer (struct query *q UU) { @@ -780,6 +793,7 @@ void do_send_encr_message (peer_id_t id, const char *msg, int len) { struct message *M = malloc (sizeof (*M)); memset (M, 0, sizeof (*M)); + M->flags = FLAG_ENCRYPTED; M->from_id = MK_USER (our_id); M->to_id = id; M->unread = 1; @@ -991,6 +1005,7 @@ void do_get_history (peer_id_t id, int limit) { } /* }}} */ +/* {{{ Get dialogs */ int get_dialogs_on_answer (struct query *q UU) { unsigned x = fetch_int (); assert (x == CODE_messages_dialogs || x == CODE_messages_dialogs_slice); @@ -1067,35 +1082,11 @@ void do_get_dialog_list (void) { out_int (1000); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, 0); } +/* }}} */ int allow_send_linux_version = 1; -void do_get_dialog_list_ex (void) { - 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"); - } - out_int (CODE_messages_get_dialogs); - out_int (0); - out_int (0); - out_int (100); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, 0); -} +/* {{{ Send photo/video file */ struct send_file { int fd; long long size; @@ -1106,6 +1097,10 @@ struct send_file { peer_id_t to_id; int media_type; char *file_name; + int encr; + unsigned char *iv; + unsigned char *init_iv; + unsigned char *key; }; void out_peer_id (peer_id_t id) { @@ -1158,6 +1153,21 @@ int send_file_on_answer (struct query *q UU) { return 0; } +int send_encr_file_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_messages_sent_encrypted_file); + struct message *M = q->extra; + M->date = fetch_int (); + assert (fetch_int () == CODE_encrypted_file); + M->media.encr_photo.id = fetch_long (); + M->media.encr_photo.access_hash = fetch_long (); + M->media.encr_photo.size = fetch_int (); + M->media.encr_photo.dc_id = fetch_int (); + assert (fetch_int () == M->media.encr_photo.key_fingerprint); + print_message (M); + message_insert (M); + return 0; +} + struct query_methods send_file_part_methods = { .on_answer = send_file_part_on_answer }; @@ -1166,6 +1176,10 @@ struct query_methods send_file_methods = { .on_answer = send_file_on_answer }; +struct query_methods send_encr_file_methods = { + .on_answer = send_encr_file_on_answer +}; + void send_part (struct send_file *f) { if (f->fd >= 0) { if (!f->part_num) { @@ -1178,9 +1192,22 @@ void send_part (struct send_file *f) { static char buf[512 << 10]; int x = read (f->fd, buf, f->part_size); assert (x > 0); - out_cstring (buf, x); f->offset += x; cur_uploaded_bytes += x; + + if (f->encr) { + if (x & 15) { + assert (f->offset == f->size); + while (x & 15) { + buf[x ++] = lrand48 () & 255; + } + } + + AES_KEY aes_key; + AES_set_encrypt_key (f->key, 256, &aes_key); + AES_ige_encrypt ((void *)buf, (void *)buf, x, &aes_key, f->iv, 1); + } + out_cstring (buf, x); if (verbosity >= 2) { logprintf ("offset=%lld size=%lld\n", f->offset, f->size); } @@ -1193,24 +1220,92 @@ void send_part (struct send_file *f) { cur_uploaded_bytes -= f->size; cur_uploading_bytes -= f->size; clear_packet (); - out_int (CODE_messages_send_media); - out_peer_id (f->to_id); assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video); - out_int (f->media_type); - out_int (CODE_input_file); - out_long (f->id); - out_int (f->part_num); - char *s = f->file_name + strlen (f->file_name); - while (s >= f->file_name && *s != '/') { s --;} - out_string (s + 1); - out_string (""); - if (f->media_type == CODE_input_media_uploaded_video) { - out_int (100); + if (!f->encr) { + out_int (CODE_messages_send_media); + out_peer_id (f->to_id); + out_int (f->media_type); + out_int (CODE_input_file); + out_long (f->id); + out_int (f->part_num); + char *s = f->file_name + strlen (f->file_name); + while (s >= f->file_name && *s != '/') { s --;} + out_string (s + 1); + out_string (""); + if (f->media_type == CODE_input_media_uploaded_video) { + out_int (100); + out_int (100); + out_int (100); + } + out_long (-lrand48 () * (1ll << 32) - lrand48 ()); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, 0); + } else { + struct message *M = malloc (sizeof (*M)); + memset (M, 0, sizeof (*M)); + + out_int (CODE_messages_send_encrypted_file); + out_int (CODE_input_encrypted_chat); + out_int (get_peer_id (f->to_id)); + peer_t *P = user_chat_get (f->to_id); + assert (P); + out_long (P->encr_chat.access_hash); + long long r = -lrand48 () * (1ll << 32) - lrand48 (); + out_long (r); + encr_start (); + out_int (CODE_decrypted_message); + out_long (r); + out_random (16); + out_string (""); + if (f->media_type == CODE_input_media_uploaded_photo) { + out_int (CODE_decrypted_message_media_photo); + M->media.type = CODE_decrypted_message_media_photo; + } else { + out_int (CODE_decrypted_message_media_video); + M->media.type = CODE_decrypted_message_media_video; + } + out_cstring ((void *)thumb_file, thumb_file_size); + out_int (90); + out_int (90); + if (f->media_type == CODE_input_media_uploaded_video) { + out_int (0); + } out_int (100); out_int (100); + out_int (f->size); + out_cstring ((void *)f->key, 32); + out_cstring ((void *)f->init_iv, 32); + encr_finish (&P->encr_chat); + out_int (CODE_input_encrypted_file_uploaded); + out_long (f->id); + out_int (f->part_num); + out_string (""); + + unsigned char md5[16]; + unsigned char str[64]; + memcpy (str, f->key, 32); + memcpy (str + 32, f->init_iv, 32); + MD5 (str, 64, md5); + out_int ((*(int *)md5) ^ (*(int *)(md5 + 4))); + + free (f->iv); + + M->media.encr_photo.key = f->key; + M->media.encr_photo.iv = f->init_iv; + M->media.encr_photo.key_fingerprint = (*(int *)md5) ^ (*(int *)(md5 + 4)); + + + M->flags = FLAG_ENCRYPTED; + M->from_id = MK_USER (our_id); + M->to_id = f->to_id; + M->unread = 1; + M->message = strdup (""); + M->out = 1; + M->id = r; + M->date = time (0); + + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_file_methods, M); + } - out_long (-lrand48 () * (1ll << 32) - lrand48 ()); - send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, 0); free (f->file_name); free (f); } @@ -1231,6 +1326,7 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { return; } struct send_file *f = malloc (sizeof (*f)); + memset (f, 0, sizeof (*f)); f->fd = fd; f->size = size; f->offset = 0; @@ -1240,6 +1336,20 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { f->to_id = to_id; f->media_type = type; f->file_name = file_name; + if (get_peer_type (f->to_id) == PEER_ENCR_CHAT) { + f->encr = 1; + f->iv = malloc (32); + int i; + for (i = 0; i < 8; i++) { + ((int *)f->iv)[i] = mrand48 (); + } + f->init_iv = malloc (32); + memcpy (f->init_iv, f->iv, 32); + f->key = malloc (32); + for (i = 0; i < 8; i++) { + ((int *)f->key)[i] = mrand48 (); + } + } if (f->part_size > (512 << 10)) { close (fd); rprintf ("Too big file. Maximal supported size is %d", (512 << 10) * 1000); @@ -1247,7 +1357,9 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { } send_part (f); } +/* }}} */ +/* {{{ Forward */ int fwd_msg_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_messages_stated_message); struct message *M = fetch_alloc_message (); @@ -1273,6 +1385,10 @@ struct query_methods fwd_msg_methods = { }; void do_forward_message (peer_id_t id, int n) { + if (get_peer_type (id) == PEER_ENCR_CHAT) { + rprintf ("Can not forward messages from secret chat\n"); + return; + } clear_packet (); out_int (CODE_invoke_with_layer9); out_int (CODE_messages_forward_message); @@ -1281,7 +1397,9 @@ void do_forward_message (peer_id_t id, int n) { out_long (lrand48 () * (1ll << 32) + lrand48 ()); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &fwd_msg_methods, 0); } +/* }}} */ +/* {{{ Rename chat */ int rename_chat_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_messages_stated_message); struct message *M = fetch_alloc_message (); @@ -1314,7 +1432,9 @@ void do_rename_chat (peer_id_t id, char *name) { out_string (name); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &rename_chat_methods, 0); } +/* }}} */ +/* {{{ Chat info */ int chat_info_on_answer (struct query *q UU) { struct chat *C = fetch_alloc_chat_full (); peer_t *U = (void *)C; @@ -1352,7 +1472,9 @@ void do_get_chat_info (peer_id_t id) { out_int (get_peer_id (id)); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &chat_info_methods, 0); } +/* }}} */ +/* {{{ User info */ int user_info_on_answer (struct query *q UU) { struct user *U = fetch_alloc_user_full (); peer_t *C = (void *)U; @@ -1394,7 +1516,9 @@ void do_get_user_info (peer_id_t id) { } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_info_methods, 0); } +/* }}} */ +/* {{{ Get user info silently */ int user_list_info_silent_on_answer (struct query *q UU) { assert (fetch_int () == CODE_vector); int n = fetch_int (); @@ -1422,7 +1546,9 @@ void do_get_user_list_info_silent (int num, int *list) { } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_list_info_silent_methods, 0); } +/* }}} */ +/* {{{ Load photo/video */ struct download { int offset; int size; @@ -1435,6 +1561,8 @@ struct download { int fd; char *name; long long id; + unsigned char *iv; + unsigned char *key; }; @@ -1454,6 +1582,9 @@ void end_load (struct download *D) { logprintf ("Image is at %s\n", D->name); } } + if (D->iv) { + free (D->iv); + } free (D->name); free (D); } @@ -1503,7 +1634,16 @@ int download_on_answer (struct query *q) { assert (len >= 0); cur_downloaded_bytes += len; update_prompt (); - assert (write (D->fd, fetch_str (len), len) == len); + if (D->iv) { + unsigned char *ptr = (void *)fetch_str (len); + assert (!(len & 15)); + AES_KEY aes_key; + AES_set_decrypt_key (D->key, 256, &aes_key); + AES_ige_encrypt (ptr, ptr, len, &aes_key, D->iv, 0); + assert (write (D->fd, ptr, len) == len); + } else { + assert (write (D->fd, fetch_str (len), len) == len); + } D->offset += len; if (D->offset < D->size) { load_next_part (D); @@ -1531,7 +1671,11 @@ void load_next_part (struct download *D) { out_int (D->local_id); out_long (D->secret); } else { - out_int (CODE_input_video_file_location); + if (D->iv) { + out_int (CODE_input_encrypted_file_location); + } else { + out_int (CODE_input_video_file_location); + } out_long (D->id); out_long (D->access_hash); } @@ -1545,6 +1689,7 @@ void do_load_photo_size (struct photo_size *P, int next) { assert (P); assert (next); struct download *D = malloc (sizeof (*D)); + memset (D, 0, sizeof (*D)); D->id = 0; D->offset = 0; D->size = P->size; @@ -1580,6 +1725,7 @@ void do_load_video (struct video *V, int next) { assert (V); assert (next); struct download *D = malloc (sizeof (*D)); + memset (D, 0, sizeof (*D)); D->offset = 0; D->size = V->size; D->id = V->id; @@ -1591,6 +1737,34 @@ void do_load_video (struct video *V, int next) { load_next_part (D); } +void do_load_encr_video (struct encr_video *V, int next) { + assert (V); + assert (next); + struct download *D = malloc (sizeof (*D)); + memset (D, 0, sizeof (*D)); + D->offset = 0; + D->size = V->size; + D->id = V->id; + D->access_hash = V->access_hash; + D->dc = V->dc_id; + D->next = next; + D->name = 0; + D->fd = -1; + D->key = V->key; + D->iv = malloc (32); + memcpy (D->iv, V->iv, 32); + load_next_part (D); + + unsigned char md5[16]; + unsigned char str[64]; + memcpy (str, V->key, 32); + memcpy (str + 32, V->iv, 32); + MD5 (str, 64, md5); + assert (V->key_fingerprint == ((*(int *)md5) ^ (*(int *)(md5 + 4)))); +} +/* }}} */ + +/* {{{ Export auth */ char *export_auth_str; int export_auth_str_len; int is_export_auth_str (void) { @@ -1629,7 +1803,9 @@ void do_export_auth (int num) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &export_auth_methods, 0); net_loop (0, is_export_auth_str); } +/* }}} */ +/* {{{ Import auth */ int import_auth_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_auth_authorization); fetch_int (); // expires @@ -1652,7 +1828,9 @@ void do_import_auth (int num) { send_query (DC_list[num], packet_ptr - packet_buffer, packet_buffer, &import_auth_methods, 0); net_loop (0, isn_export_auth_str); } +/* }}} */ +/* {{{ Add contact */ int add_contact_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_contacts_imported_contacts); assert (fetch_int () == CODE_vector); @@ -1720,7 +1898,9 @@ void do_add_contact (const char *phone, int phone_len, const char *first_name, i out_int (force ? CODE_bool_true : CODE_bool_false); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &add_contact_methods, 0); } +/* }}} */ +/* {{{ Msg search */ int msg_search_on_answer (struct query *q UU) { return get_history_on_answer (q); } @@ -1742,7 +1922,9 @@ 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); } +/* }}} */ +/* {{{ Encr accept */ int send_encr_accept_on_answer (struct query *q UU) { struct secret_chat *E = fetch_alloc_encrypted_chat (); @@ -1860,7 +2042,9 @@ void do_accept_encr_chat_request (struct secret_chat *E) { out_int (256); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dh_config_methods, E); } +/* }}} */ +/* {{{ Get difference */ int unread_messages; int difference_got; int seq, pts, qts, last_date; @@ -1980,3 +2164,36 @@ void do_get_difference (void) { send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_state_methods, 0); } } +/* }}} */ + +/* {{{ Visualize key */ +char *colors[4] = {COLOR_GREY, COLOR_GREEN, COLOR_CYAN, COLOR_BLUE}; + +void do_visualize_key (peer_id_t id) { + assert (get_peer_type (id) == PEER_ENCR_CHAT); + peer_t *P = user_chat_get (id); + assert (P); + if (P->encr_chat.state != sc_ok) { + rprintf ("Chat is not initialized yet\n"); + return; + } + unsigned char buf[20]; + SHA1 ((void *)P->encr_chat.key, 256, buf); + print_start (); + int i; + for (i = 0; i < 16; i++) { + int x = buf[i]; + int j; + for (j = 0; j < 4; j ++) { + push_color (colors[x & 3]); + push_color (COLOR_INVERSE); + printf (" "); + pop_color (); + pop_color (); + x = x >> 2; + } + if (i & 1) { printf ("\n"); } + } + print_end (); +} +/* }}} */ diff --git a/queries.h b/queries.h index beff3a8..f34f3de 100644 --- a/queries.h +++ b/queries.h @@ -80,6 +80,7 @@ void do_get_user_list_info_silent (int num, int *list); void do_get_user_info (peer_id_t id); void do_forward_message (peer_id_t id, int n); void do_rename_chat (peer_id_t id, char *name); +void do_load_encr_video (struct encr_video *V, int next); struct photo; struct video; @@ -97,5 +98,6 @@ 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); +void do_visualize_key (peer_id_t id); #endif diff --git a/structures.c b/structures.c index c5a1035..e6ef4ec 100644 --- a/structures.c +++ b/structures.c @@ -818,6 +818,8 @@ void fetch_encrypted_message (struct message *M) { peer_id_t chat = MK_ENCR_CHAT (fetch_int ()); M->to_id = chat; peer_t *P = user_chat_get (chat); + M->flags &= ~(FLAG_EMPTY | FLAG_DELETED); + M->flags |= FLAG_ENCRYPTED; if (!P) { logprintf ("Encrypted message to unknown chat. Dropping\n"); M->flags |= FLAG_EMPTY; diff --git a/structures.h b/structures.h index 5fdd8b7..fe34654 100644 --- a/structures.h +++ b/structures.h @@ -91,9 +91,9 @@ struct encr_video { int w; int h; - int duration; unsigned char *key; unsigned char *iv; + int duration; }; struct encr_file {