From 5b8a4fdc60d715328ecb29b6b286d4dda229079d Mon Sep 17 00:00:00 2001 From: vysheng Date: Sat, 2 Nov 2013 14:14:30 +0400 Subject: [PATCH] Some changes to add encrypted chat in nearest future --- interface.c | 8 ++-- structures.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++-- structures.h | 37 +++++++++++++-- 3 files changed, 161 insertions(+), 11 deletions(-) diff --git a/interface.c b/interface.c index 4ee41d6..5d1fb53 100644 --- a/interface.c +++ b/interface.c @@ -942,7 +942,7 @@ void print_service_message (struct message *M) { push_color (COLOR_MAGENTA); if (msg_num_mode) { - printf ("%d ", M->id); + printf ("%lld ", M->id); } print_date (M->date); pop_color (); @@ -1002,7 +1002,7 @@ void print_message (struct message *M) { if (M->out) { push_color (COLOR_GREEN); if (msg_num_mode) { - printf ("%d ", M->id); + printf ("%lld ", M->id); } print_date (M->date); pop_color (); @@ -1017,7 +1017,7 @@ void print_message (struct message *M) { } else { push_color (COLOR_BLUE); if (msg_num_mode) { - printf ("%d ", M->id); + printf ("%lld ", M->id); } print_date (M->date); pop_color (); @@ -1033,7 +1033,7 @@ void print_message (struct message *M) { } else { push_color (COLOR_MAGENTA); if (msg_num_mode) { - printf ("%d ", M->id); + printf ("%lld ", M->id); } print_date (M->date); pop_color (); diff --git a/structures.c b/structures.c index ade8162..e821658 100644 --- a/structures.c +++ b/structures.c @@ -23,6 +23,12 @@ #include "telegram.h" #include "tree.h" #include "loop.h" +#include +#include +#include + +#define sha1 SHA1 + int verbosity; peer_t *Peers[MAX_USER_NUM]; @@ -553,7 +559,100 @@ void fetch_geo_message (struct message *M) { } } -#define id_cmp(a,b) ((a)->id - (b)->id) +int *decr_ptr; +int *decr_end; + +int decrypt_encrypted_message (struct secret_chat *E) { + int *msg_key = decr_ptr; + decr_ptr += 4; + assert (decr_ptr < decr_end); + static unsigned char sha1a_buffer[20]; + static unsigned char sha1b_buffer[20]; + static unsigned char sha1c_buffer[20]; + static unsigned char sha1d_buffer[20]; + + 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 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); + + 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); + + if (memcmp (sha1a_buffer, msg_key, 16)) { + logprintf ("Sha1 mismatch\n"); + return -1; + } + return 0; +} + +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 ()); + M->id = fetch_long (); + peer_t *P = user_chat_get (chat); + if (!P) { + logprintf ("Encrypted message to unknown chat. Dropping\n"); + } + M->date = fetch_int (); + + int len = prefetch_strlen (); + assert (!(len & 15)); + decr_ptr = (void *)fetch_str (len); + decr_end = in_ptr; + if (P && decrypt_encrypted_message (&P->encr_chat) >= 0) { + in_ptr = decr_ptr; + 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 (M->id = fetch_long ()); + int l = prefetch_strlen (); + fetch_str (l); // random_bytes + M->from_id = MK_USER (fetch_int ()); + M->date = fetch_int (); + M->message = fetch_str_dup (); + } +} + +static int id_cmp (struct message *M1, struct message *M2) { + if (M1->id < M2->id) { return -1; } + else if (M1->id > M2->id) { return 1; } + else { return 0; } +} + #define peer_cmp(a,b) (cmp_peer_id (a->id, b->id)) DEFINE_TREE(peer,peer_t *,peer_cmp,0) @@ -752,6 +851,26 @@ struct message *fetch_alloc_geo_message (void) { } } +struct message *fetch_alloc_encrypted_message (void) { + struct message *M = malloc (sizeof (*M)); + fetch_encrypted_message (M); + struct message *M1 = tree_lookup_message (message_tree, M); + messages_allocated ++; + if (M1) { + message_del_use (M1); + free_message (M1); + memcpy (M1, M, sizeof (*M)); + free (M); + message_add_use (M1); + messages_allocated --; + return M1; + } else { + message_add_use (M); + message_tree = tree_insert_message (message_tree, M, lrand48 ()); + return M; + } +} + struct message *fetch_alloc_message_short (void) { struct message *M = malloc (sizeof (*M)); fetch_message_short (M); @@ -776,7 +895,7 @@ struct message *fetch_alloc_message_short_chat (void) { struct message *M = malloc (sizeof (*M)); fetch_message_short_chat (M); if (verbosity >= 2) { - logprintf ("Read message with id %d\n", M->id); + logprintf ("Read message with id %lld\n", M->id); } struct message *M1 = tree_lookup_message (message_tree, M); messages_allocated ++; @@ -854,13 +973,13 @@ peer_t *user_chat_get (peer_id_t id) { return tree_lookup_peer (peer_tree, &U); } -struct message *message_get (int id) { +struct message *message_get (long long id) { struct message M; M.id = id; return tree_lookup_message (message_tree, &M); } -void update_message_id (struct message *M, int id) { +void update_message_id (struct message *M, long long id) { message_tree = tree_delete_message (message_tree, M); M->id = id; message_tree = tree_insert_message (message_tree, M, lrand48 ()); diff --git a/structures.h b/structures.h index 462e4d8..8e5f5e1 100644 --- a/structures.h +++ b/structures.h @@ -111,6 +111,26 @@ struct chat { int admin_id; }; +enum secret_chat_state { + sc_none, + sc_sent_request, + sc_ok, + sc_bad +}; + +struct secret_chat { + peer_id_t id; + int flags; + char *print_name; + struct file_location photo_big; + struct file_location photo_small; + struct photo photo; + + enum secret_chat_state state; + int key[64]; + long long key_fingerprint; +}; + typedef union peer { struct { peer_id_t id; @@ -122,6 +142,7 @@ typedef union peer { }; struct user user; struct chat chat; + struct secret_chat encr_chat; } peer_t; struct video { @@ -170,7 +191,7 @@ struct message_media { struct message { struct message *next_use, *prev_use; - int id; + long long id; int flags; peer_id_t fwd_from_id; int fwd_date; @@ -208,8 +229,8 @@ void free_chat (struct chat *U); int print_stat (char *s, int len); peer_t *user_chat_get (peer_id_t id); -struct message *message_get (int id); -void update_message_id (struct message *M, int id); +struct message *message_get (long long id); +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); @@ -217,13 +238,18 @@ void fetch_photo (struct photo *P); #define PEER_USER 1 #define PEER_CHAT 2 #define PEER_GEO_CHAT 3 +#define PEER_ENCR_CHAT 4 #define PEER_UNKNOWN 0 #define MK_USER(id) set_peer_id (PEER_USER,id) #define MK_CHAT(id) set_peer_id (PEER_CHAT,id) #define MK_GEO_CHAT(id) set_peer_id (PEER_GEO_CHAT,id) +#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; } @@ -244,6 +270,8 @@ static inline int get_peer_id (peer_id_t id) { return -id.id; case PEER_GEO_CHAT: return -id.id - 1000000000; + case PEER_ENCR_CHAT: + return id.id - 1000000000; default: return 0; } @@ -261,6 +289,9 @@ static inline peer_id_t set_peer_id (int type, int 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;