From 9dd3627afad1af2dca6fee90c0e163a370631f53 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Sat, 2 Nov 2013 21:01:22 +0400 Subject: [PATCH] Some code related to encrypted chat. Nothing works yet, but I believe it would work in the nearest future --- interface.c | 20 ++++++ interface.h | 2 + mtproto-client.c | 62 ++++++++++++++-- structures.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++- structures.h | 53 +++++++++++++- 5 files changed, 310 insertions(+), 8 deletions(-) diff --git a/interface.c b/interface.c index 5d1fb53..95f1558 100644 --- a/interface.c +++ b/interface.c @@ -919,6 +919,26 @@ void print_chat_name (peer_id_t id, peer_t *C) { pop_color (); } +void print_encr_chat_name (peer_id_t id, peer_t *C) { + push_color (COLOR_MAGENTA); + if (!C) { + printf ("encr_chat#%d", get_peer_id (id)); + } else { + printf ("%s", C->print_name); + } + pop_color (); +} + +void print_encr_chat_name_full (peer_id_t id, peer_t *C) { + push_color (COLOR_MAGENTA); + if (!C) { + printf ("encr_chat#%d", get_peer_id (id)); + } else { + printf ("%s", C->print_name); + } + pop_color (); +} + static char *monthes[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; void print_date (long t) { struct tm *tm = localtime (&t); diff --git a/interface.h b/interface.h index 6a59bbc..b529762 100644 --- a/interface.h +++ b/interface.h @@ -45,6 +45,8 @@ union peer; void print_message (struct message *M); void print_chat_name (peer_id_t id, union peer *C); void print_user_name (peer_id_t id, union peer *U); +void print_encr_chat_name_full (peer_id_t id, peer_t *C); +void print_encr_chat_name (peer_id_t id, peer_t *C); //void print_media (struct message_media *M); void pop_color (void); void push_color (const char *color); diff --git a/mtproto-client.c b/mtproto-client.c index 3fb5380..7152a40 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -956,27 +956,79 @@ void work_update (struct connection *c UU, long long msg_id UU) { break; case CODE_update_new_encrypted_message: { - logprintf ("New encrypted message. Unsupported yet\n"); + struct message *M = fetch_alloc_encrypted_message (); + unread_messages ++; + print_message (M); + update_prompt (); + fetch_qts (); } break; case CODE_update_encryption: { - logprintf ("New encrypted chat. Unsupported yet\n"); + struct secret_chat *E = fetch_alloc_encrypted_chat (); + print_start (); + push_color (COLOR_YELLOW); + switch (E->state) { + case sc_none: + assert (0); + break; + case sc_waiting: + printf ("Encrypted chat "); + print_encr_chat_name (E->id, (void *)E); + printf (" is now in wait state\n"); + break; + case sc_request: + printf ("Encrypted chat "); + print_encr_chat_name (E->id, (void *)E); + printf (" is now in request state. Sending request ok\n"); + break; + case sc_ok: + printf ("Encrypted chat "); + print_encr_chat_name (E->id, (void *)E); + printf (" is now in ok state\n"); + break; + case sc_deleted: + printf ("Encrypted chat "); + print_encr_chat_name (E->id, (void *)E); + printf (" is now in deleted state\n"); + break; + } + /*if (E->state == state_requested) { + do_accept_encr_chat_request (E); + }*/ + fetch_int (); // date } break; case CODE_update_encrypted_chat_typing: { - logprintf ("Typing in encrypted chat. Unsupported yet\n"); + peer_id_t id = MK_ENCR_CHAT (fetch_int ()); + peer_t *P = user_chat_get (id); + print_start (); + push_color (COLOR_YELLOW); + if (P) { + printf ("User "); + peer_id_t user_id = MK_USER (P->encr_chat.user_id); + print_user_name (user_id, user_chat_get (user_id)); + printf (" typing in secret chat "); + print_encr_chat_name (id, P); + printf ("\n"); + } else { + printf ("Some user is typing in unknown secret chat\n"); + } + pop_color (); + print_end (); } break; case CODE_update_encrypted_messages_read: { - fetch_int (); // chat_id + peer_id_t id = MK_ENCR_CHAT (fetch_int ()); // chat_id fetch_int (); // max_date fetch_int (); // date print_start (); push_color (COLOR_YELLOW); - printf ("Messages in encrypted chat mark read \n"); + printf ("Messages in encrypted chat "); + print_encr_chat_name_full (id, user_chat_get (id)); + printf (" marked read \n"); pop_color (); print_end (); } diff --git a/structures.c b/structures.c index e821658..89055e6 100644 --- a/structures.c +++ b/structures.c @@ -192,6 +192,55 @@ void fetch_user (struct user *U) { } } +void fetch_encrypted_chat (struct secret_chat *U) { + unsigned x = fetch_int (); + 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); + if (x == CODE_encrypted_chat_empty) { + U->state = sc_none; + U->flags |= FLAG_EMPTY; + return; + } + if (x == CODE_encrypted_chat_discarded) { + U->state = sc_deleted; + U->flags |= FLAG_DELETED; + 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 (x == CODE_encrypted_chat_waiting) { + U->state = sc_waiting; + } else if (x == CODE_encrypted_chat_requested) { + U->state = sc_request; + if (!U->g_key) { + U->g_key = malloc (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); + } else { + U->state = sc_ok; + if (!U->g_key) { + U->g_key = malloc (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); + U->key_fingerprint = fetch_long (); + } +} + void fetch_notify_settings (void); void fetch_user_full (struct user *U) { assert (fetch_int () == CODE_user_full); @@ -501,6 +550,87 @@ void fetch_message_media (struct message_media *M) { } } +void fetch_message_media_encrypted (struct message_media *M) { + memset (M, 0, sizeof (*M)); + unsigned x = fetch_int (); + int l; + switch (M->type) { + case CODE_decrypted_message_media_empty: + M->type = CODE_message_media_empty; + break; + case CODE_decrypted_message_media_photo: + M->type = x; + l = prefetch_strlen (); + fetch_str (l); // thumb + fetch_int (); // thumb_w + fetch_int (); // thumb_h + 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 (); + assert (l > 0); + M->encr_photo.iv = malloc (l); + memcpy (M->encr_photo.iv, fetch_str (l), l); + break; + case CODE_decrypted_message_media_video: + M->type = x; + l = prefetch_strlen (); + fetch_str (l); // thumb + fetch_int (); // thumb_w + fetch_int (); // thumb_h + M->encr_video.w = fetch_int (); + 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 (); + assert (l > 0); + M->encr_video.iv = malloc (l); + memcpy (M->encr_video.iv, fetch_str (l), l); + break; +/* case CODE_decrypted_message_media_file: + M->type = x; + M->encr_file.filename = fetch_str_dup (); + l = prefetch_strlen (); + fetch_str (l); // thumb + l = fetch_int (); + assert (l > 0); + M->encr_file.key = malloc (l); + memcpy (M->encr_file.key, fetch_str (l), l); + + l = fetch_int (); + assert (l > 0); + M->encr_file.iv = malloc (l); + memcpy (M->encr_file.iv, fetch_str (l), l); + break; + */ + case CODE_decrypted_message_media_geo_point: + M->geo.longitude = fetch_double (); + M->geo.latitude = fetch_double (); + M->type = CODE_message_media_geo; + break; + case CODE_decrypted_message_media_contact: + M->type = CODE_message_media_contact; + M->phone = fetch_str_dup (); + M->first_name = fetch_str_dup (); + M->last_name = fetch_str_dup (); + M->user_id = fetch_int (); + break; + default: + logprintf ("type = 0x%08x\n", M->type); + assert (0); + } +} + peer_id_t fetch_peer_id (void) { unsigned x =fetch_int (); if (x == CODE_peer_user) { @@ -629,6 +759,7 @@ void fetch_encrypted_message (struct message *M) { assert (!(len & 15)); decr_ptr = (void *)fetch_str (len); decr_end = in_ptr; + M->flags |= FLAG_ENCRYPTED; if (P && decrypt_encrypted_message (&P->encr_chat) >= 0) { in_ptr = decr_ptr; unsigned x = fetch_int (); @@ -643,7 +774,29 @@ void fetch_encrypted_message (struct message *M) { fetch_str (l); // random_bytes M->from_id = MK_USER (fetch_int ()); M->date = fetch_int (); - M->message = fetch_str_dup (); + if (x == CODE_decrypted_message) { + M->message = fetch_str_dup (); + fetch_encrypted_message_file (&M->media); + } else { + assert (fetch_int () == (int)CODE_decrypted_message_action_set_message_t_t_l); + P->encr_chat.ttl = fetch_int (); + } + } +} + +void fetch_encrypted_message_file (struct message_media *M) { + unsigned x = fetch_int (); + assert (x == CODE_encrypted_file || x == CODE_encrypted_file_empty); + if (x == CODE_encrypted_file_empty) { + assert (M->type != CODE_decrypted_message_media_photo && M->type != CODE_decrypted_message_media_video); + } else { + 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 ()); + M->encr_photo.dc_id = fetch_int (); + M->encr_photo.key_fingerprint = fetch_int (); + } } @@ -689,6 +842,24 @@ struct user *fetch_alloc_user (void) { } } +struct secret_chat *fetch_alloc_encrypted_chat (void) { + int data[2]; + prefetch_data (data, 8); + peer_t *U = user_chat_get (MK_ENCR_CHAT (data[1])); + if (U) { + fetch_encrypted_chat (&U->encr_chat); + return &U->encr_chat; + } else { + 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; + return &U->encr_chat; + } +} + struct user *fetch_alloc_user_full (void) { int data[3]; prefetch_data (data, 12); @@ -759,6 +930,14 @@ void free_message_media (struct message_media *M) { case CODE_message_media_unsupported: free (M->data); return; + case CODE_decrypted_message_media_photo: + free (M->encr_photo.key); + free (M->encr_photo.iv); + return; + case CODE_decrypted_message_media_video: + free (M->encr_video.key); + free (M->encr_video.iv); + return; default: logprintf ("%08x\n", M->type); assert (0); diff --git a/structures.h b/structures.h index 8e5f5e1..e703b69 100644 --- a/structures.h +++ b/structures.h @@ -35,6 +35,7 @@ typedef struct { int id; } peer_id_t; #define FLAG_CHAT_IN_CHAT 128 +#define FLAG_ENCRYPTED 4096 struct file_location { int dc; @@ -68,6 +69,40 @@ struct photo { struct photo_size *sizes; }; +struct encr_photo { + long long id; + long long access_hash; + int dc_id; + int size; + int key_fingerprint; + + int w; + int h; + unsigned char *key; + unsigned char *iv; +}; + +struct encr_video { + long long id; + long long access_hash; + int dc_id; + int size; + int key_fingerprint; + + int w; + int h; + int duration; + unsigned char *key; + unsigned char *iv; +}; + +struct encr_file { + char *filename; + unsigned char *key; + unsigned char *iv; +}; + + struct user_status { int online; int when; @@ -113,9 +148,10 @@ struct chat { enum secret_chat_state { sc_none, - sc_sent_request, + sc_waiting, + sc_request, sc_ok, - sc_bad + sc_deleted }; struct secret_chat { @@ -125,6 +161,13 @@ struct secret_chat { struct file_location photo_big; struct file_location photo_small; struct photo photo; + int user_id; + int admin_id; + int date; + int ttl; + long long access_hash; + unsigned char *g_key; + unsigned char *nonce; enum secret_chat_state state; int key[64]; @@ -185,6 +228,9 @@ struct message_media { char *last_name; int user_id; }; + struct encr_photo encr_photo; + struct encr_video encr_video; + struct encr_file encr_file; void *data; }; }; @@ -218,10 +264,13 @@ struct user *fetch_alloc_user (void); struct user *fetch_alloc_user_full (void); struct chat *fetch_alloc_chat (void); struct chat *fetch_alloc_chat_full (void); +struct secret_chat *fetch_alloc_encrypted_chat (void); struct message *fetch_alloc_message (void); struct message *fetch_alloc_geo_message (void); struct message *fetch_alloc_message_short (void); struct message *fetch_alloc_message_short_chat (void); +struct message *fetch_alloc_encrypted_message (void); +void fetch_encrypted_message_file (struct message_media *M); peer_id_t fetch_peer_id (void); void free_user (struct user *U);