Commit 3243c29a authored by Vysheng's avatar Vysheng

Big commit

parent f773c0cf
CC=cc CC=cc
CFLAGS=-c -Wall -Wextra -fPIC CFLAGS=-c -Wall -Wextra -Werror -fPIC -ggdb -O2 -fno-omit-frame-pointer -fno-strict-aliasing -rdynamic
LDFLAGS=-lreadline LDFLAGS=-lreadline -lssl -lcrypto -lrt -lz -ggdb -rdynamic
LD=cc LD=cc
SRC=main.c loop.c interface.c SRC=main.c loop.c interface.c net.c mtproto-common.c mtproto-client.c queries.c structures.c
OBJ=$(SRC:.c=.o) OBJ=$(SRC:.c=.o)
EXE=telegram EXE=telegram
......
...@@ -4,10 +4,11 @@ ...@@ -4,10 +4,11 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "include.h" #include "include.h"
#include "queries.h"
char *default_prompt = ">"; char *default_prompt = ">";
char *get_default_prompt (void) { char *get_default_prompt (void) {
...@@ -21,11 +22,13 @@ char *complete_none (const char *text UU, int state UU) { ...@@ -21,11 +22,13 @@ char *complete_none (const char *text UU, int state UU) {
char *commands[] = { char *commands[] = {
"help", "help",
"msg", "msg",
"contact_list",
0 }; 0 };
int commands_flags[] = { int commands_flags[] = {
070, 070,
072, 072,
00,
}; };
char *a = 0; char *a = 0;
...@@ -151,5 +154,27 @@ char **complete_text (char *text, int start UU, int end UU) { ...@@ -151,5 +154,27 @@ char **complete_text (char *text, int start UU, int end UU) {
} }
void interpreter (char *line UU) { void interpreter (char *line UU) {
assert (0); if (!memcmp (line, "contact_list", 12)) {
do_update_contact_list ();
}
}
void rprintf (const char *format, ...) {
int saved_point = rl_point;
char *saved_line = rl_copy_text(0, rl_end);
rl_save_prompt();
rl_replace_line("", 0);
rl_redisplay();
va_list ap;
va_start (ap, format);
vfprintf (stdout, format, ap);
va_end (ap);
rl_restore_prompt();
rl_replace_line(saved_line, 0);
rl_point = saved_point;
rl_redisplay();
free(saved_line);
} }
...@@ -4,4 +4,6 @@ char *get_default_prompt (void); ...@@ -4,4 +4,6 @@ char *get_default_prompt (void);
char *complete_none (const char *text, int state); char *complete_none (const char *text, int state);
char **complete_text (char *text, int start, int end); char **complete_text (char *text, int start, int end);
void interpreter (char *line); void interpreter (char *line);
void rprintf (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
#endif #endif
...@@ -9,50 +9,178 @@ ...@@ -9,50 +9,178 @@
#include <readline/history.h> #include <readline/history.h>
#include <errno.h> #include <errno.h>
#include <poll.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "interface.h" #include "interface.h"
#include "net.h"
#include "mtproto-client.h"
#include "mtproto-common.h"
#include "queries.h"
#include "telegram.h"
extern char *default_username; extern char *default_username;
extern char *auth_token; extern char *auth_token;
void set_default_username (const char *s); void set_default_username (const char *s);
int default_dc_num;
void net_loop (int flags, int (*is_end)(void)) {
while (!is_end ()) {
struct pollfd fds[101];
int cc = 0;
if (flags & 1) {
fds[0].fd = 0;
fds[0].events = POLLIN;
cc ++;
}
int main_loop (void) { int x = connections_make_poll_array (fds + cc, 101 - cc) + cc;
fd_set inp, outp; double timer = next_timer_in ();
struct timeval tv; if (timer > 1000) { timer = 1000; }
while (1) { if (poll (fds, x, timer) < 0) {
FD_ZERO (&inp);
FD_ZERO (&outp);
FD_SET (0, &inp);
tv.tv_sec = 1;
tv.tv_usec = 0;
int lfd = 0;
if (select (lfd + 1, &inp, &outp, NULL, &tv) < 0) {
if (errno == EINTR) {
/* resuming from interrupt, so not an error situation, /* resuming from interrupt, so not an error situation,
this generally happens when you suspend your this generally happens when you suspend your
messenger with "C-z" and then "fg". This is allowed " messenger with "C-z" and then "fg". This is allowed "
*/ */
if (flags & 1) {
rl_reset_line_state (); rl_reset_line_state ();
rl_forced_update_display (); rl_forced_update_display ();
continue;
} }
perror ("select()"); work_timers ();
break; continue;
} }
work_timers ();
if (FD_ISSET (0, &inp)) { if ((flags & 1) && (fds[0].revents & POLLIN)) {
rl_callback_read_char (); rl_callback_read_char ();
} }
connections_poll_result (fds + cc, x - cc);
} }
}
int ret1 (void) { return 0; }
int main_loop (void) {
net_loop (1, ret1);
return 0; return 0;
} }
struct dc *DC_list[MAX_DC_ID + 1];
struct dc *DC_working;
int dc_working_num;
int auth_state;
char *get_auth_key_filename (void);
int zero[512];
void write_dc (int auth_file_fd, struct dc *DC) {
assert (write (auth_file_fd, &DC->port, 4) == 4);
int l = strlen (DC->ip);
assert (write (auth_file_fd, &l, 4) == 4);
assert (write (auth_file_fd, DC->ip, l) == l);
if (DC->flags & 1) {
assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8);
assert (write (auth_file_fd, DC->auth_key, 256) == 256);
} else {
assert (write (auth_file_fd, zero, 256 + 8) == 256 + 8);
}
assert (write (auth_file_fd, &DC->server_salt, 8) == 8);
}
void write_auth_file (void) {
int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, S_IRWXU);
assert (auth_file_fd >= 0);
int x = DC_SERIALIZED_MAGIC;
assert (write (auth_file_fd, &x, 4) == 4);
x = MAX_DC_ID;
assert (write (auth_file_fd, &x, 4) == 4);
assert (write (auth_file_fd, &dc_working_num, 4) == 4);
assert (write (auth_file_fd, &auth_state, 4) == 4);
int i;
for (i = 0; i <= MAX_DC_ID; i++) {
if (DC_list[i]) {
x = 1;
assert (write (auth_file_fd, &x, 4) == 4);
write_dc (auth_file_fd, DC_list[i]);
} else {
x = 0;
assert (write (auth_file_fd, &x, 4) == 4);
}
}
close (auth_file_fd);
}
void read_dc (int auth_file_fd, int id) {
int port = 0;
assert (read (auth_file_fd, &port, 4) == 4);
int l = 0;
assert (read (auth_file_fd, &l, 4) == 4);
assert (l >= 0);
char *ip = malloc (l + 1);
assert (read (auth_file_fd, ip, l) == l);
ip[l] = 0;
struct dc *DC = alloc_dc (id, ip, port);
assert (read (auth_file_fd, &DC->auth_key_id, 8) == 8);
assert (read (auth_file_fd, &DC->auth_key, 256) == 256);
assert (read (auth_file_fd, &DC->server_salt, 8) == 8);
if (DC->auth_key_id) {
DC->flags |= 1;
}
}
void empty_auth_file (void) {
struct dc *DC = alloc_dc (1, strdup (TG_SERVER), 443);
assert (DC);
dc_working_num = 1;
write_auth_file ();
}
void read_auth_file (void) {
int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, S_IRWXU);
if (auth_file_fd < 0) {
empty_auth_file ();
}
assert (auth_file_fd >= 0);
int x;
if (read (auth_file_fd, &x, 4) < 4 || x != DC_SERIALIZED_MAGIC) {
close (auth_file_fd);
empty_auth_file ();
return;
}
assert (read (auth_file_fd, &x, 4) == 4);
assert (x >= 0 && x <= MAX_DC_ID);
assert (read (auth_file_fd, &dc_working_num, 4) == 4);
assert (read (auth_file_fd, &auth_state, 4) == 4);
int i;
for (i = 0; i <= x; i++) {
int y;
assert (read (auth_file_fd, &y, 4) == 4);
if (y) {
read_dc (auth_file_fd, i);
}
}
close (auth_file_fd);
}
int loop (void) { int loop (void) {
on_start ();
read_auth_file ();
assert (DC_list[dc_working_num]);
DC_working = DC_list[dc_working_num];
if (!DC_working->auth_key_id) {
dc_authorize (DC_working);
} else {
dc_create_session (DC_working);
}
if (!auth_state) {
if (!default_username) {
size_t size = 0; size_t size = 0;
char *user = default_username; char *user = 0;
if (!user && !auth_token) { if (!user && !auth_token) {
printf ("Telephone number (with '+' sign): "); printf ("Telephone number (with '+' sign): ");
...@@ -60,11 +188,33 @@ int loop (void) { ...@@ -60,11 +188,33 @@ int loop (void) {
perror ("getline()"); perror ("getline()");
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
user[strlen (user) - 1] = '\0'; user[strlen (user) - 1] = 0;
set_default_username (user); set_default_username (user);
} }
}
do_send_code (default_username);
char *code = 0;
size_t size = 0;
printf ("Code from sms: ");
while (1) {
if (getline (&code, &size, stdin) == -1) {
perror ("getline()");
exit (EXIT_FAILURE);
}
code[strlen (code) - 1] = 0;
if (do_send_code_result (code) >= 0) {
break;
}
printf ("Invalid code. Try again: ");
}
auth_state = 1;
}
write_auth_file ();
fflush (stdin); fflush (stdin);
fflush (stdout);
fflush (stderr);
rl_callback_handler_install (get_default_prompt (), interpreter); rl_callback_handler_install (get_default_prompt (), interpreter);
rl_attempted_completion_function = (CPPFunction *) complete_text; rl_attempted_completion_function = (CPPFunction *) complete_text;
......
#ifndef __LOOP_H__ #ifndef __LOOP_H__
#define __LOOP_H__ #define __LOOP_H__
int loop (void); int loop (void);
void net_loop (int flags, int (*end)(void));
void write_auth_file (void);
#endif #endif
...@@ -27,14 +27,18 @@ ...@@ -27,14 +27,18 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <time.h> #include <time.h>
#include <fcntl.h> #include <fcntl.h>
#include <execinfo.h>
#include <signal.h>
#include "loop.h" #include "loop.h"
#include "mtproto-client.h"
#define PROGNAME "telegram-client" #define PROGNAME "telegram-client"
#define VERSION "0.01" #define VERSION "0.01"
#define CONFIG_DIRECTORY ".telegram/" #define CONFIG_DIRECTORY ".telegram/"
#define CONFIG_FILE CONFIG_DIRECTORY "config" #define CONFIG_FILE CONFIG_DIRECTORY "config"
#define AUTH_KEY_FILE CONFIG_DIRECTORY "auth"
#define DOWNLOADS_DIRECTORY "downloads/" #define DOWNLOADS_DIRECTORY "downloads/"
#define CONFIG_DIRECTORY_MODE 0700 #define CONFIG_DIRECTORY_MODE 0700
...@@ -72,6 +76,13 @@ void get_terminal_attributes (void) { ...@@ -72,6 +76,13 @@ void get_terminal_attributes (void) {
old_lflag = term.c_lflag; old_lflag = term.c_lflag;
old_vtime = term.c_cc[VTIME]; old_vtime = term.c_cc[VTIME];
} }
void set_terminal_attributes (void) {
if (tcsetattr (STDIN_FILENO, 0, &term) < 0) {
perror ("tcsetattr()");
exit (EXIT_FAILURE);
}
}
/* }}} */ /* }}} */
char *get_home_directory (void) { char *get_home_directory (void) {
...@@ -107,6 +118,15 @@ char *get_config_filename (void) { ...@@ -107,6 +118,15 @@ char *get_config_filename (void) {
return config_filename; return config_filename;
} }
char *get_auth_key_filename (void) {
char *auth_key_filename;
int length = strlen (get_home_directory ()) + strlen (AUTH_KEY_FILE) + 2;
auth_key_filename = (char *) calloc (length, sizeof (char));
sprintf (auth_key_filename, "%s/" AUTH_KEY_FILE, get_home_directory ());
return auth_key_filename;
}
char *get_downloads_directory (void) char *get_downloads_directory (void)
{ {
char *downloads_directory; char *downloads_directory;
...@@ -149,6 +169,11 @@ void running_for_first_time (void) { ...@@ -149,6 +169,11 @@ void running_for_first_time (void) {
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
close (config_file_fd); close (config_file_fd);
int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, S_IRWXU);
int x = -1;
assert (write (auth_file_fd, &x, 4) == 4);
close (auth_file_fd);
printf ("[%s] created\n", config_filename); printf ("[%s] created\n", config_filename);
/* create downloads directory */ /* create downloads directory */
...@@ -170,13 +195,26 @@ void usage (void) { ...@@ -170,13 +195,26 @@ void usage (void) {
exit (1); exit (1);
} }
extern char *rsa_public_key_name;
extern int verbosity;
extern int default_dc_num;
void args_parse (int argc, char **argv) { void args_parse (int argc, char **argv) {
int opt = 0; int opt = 0;
while ((opt = getopt (argc, argv, "u:h")) != -1) { while ((opt = getopt (argc, argv, "u:hk:vn:")) != -1) {
switch (opt) { switch (opt) {
case 'u': case 'u':
set_default_username (optarg); set_default_username (optarg);
break; break;
case 'k':
rsa_public_key_name = strdup (optarg);
break;
case 'v':
verbosity ++;
break;
case 'n':
default_dc_num = atoi (optarg);
break;
case 'h': case 'h':
default: default:
usage (); usage ();
...@@ -185,7 +223,23 @@ void args_parse (int argc, char **argv) { ...@@ -185,7 +223,23 @@ void args_parse (int argc, char **argv) {
} }
} }
void print_backtrace (void) {
void *buffer[255];
const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *));
backtrace_symbols_fd (buffer, calls, 1);
exit(EXIT_FAILURE);
}
void sig_handler (int signum) {
set_terminal_attributes ();
printf ("signal %d received\n", signum);
print_backtrace ();
}
int main (int argc, char **argv) { int main (int argc, char **argv) {
signal (SIGSEGV, sig_handler);
signal (SIGABRT, sig_handler);
running_for_first_time (); running_for_first_time ();
get_terminal_attributes (); get_terminal_attributes ();
......
This diff is collapsed.
#ifndef __MTPROTO_CLIENT_H__
#define __MTPROTO_CLIENT_H__
#include "net.h"
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);
#endif
#define _FILE_OFFSET_BITS 64
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <aio.h>
#include <netdb.h>
#include <openssl/bn.h>
#include <openssl/rand.h>
#include <openssl/pem.h>
#include <openssl/aes.h>
#include <openssl/sha.h>
#include "mtproto-common.h"
long long rsa_encrypted_chunks, rsa_decrypted_chunks;
BN_CTX *BN_ctx;
int verbosity;
int get_random_bytes (void *buf, int n) {
int r = 0, h = open ("/dev/random", O_RDONLY | O_NONBLOCK);
if (h >= 0) {
r = read (h, buf, n);
if (r > 0) {
if (verbosity >= 3) {
fprintf (stderr, "added %d bytes of real entropy to secure random numbers seed\n", r);
}
}
close (h);
}
if (r < n) {
h = open ("/dev/urandom", O_RDONLY);
if (h < 0) {
return r;
}
int s = read (h, buf + r, n - r);
close (h);
if (s < 0) {
return r;
}
r += s;
}
if (r >= (int)sizeof (long)) {
*(long *)buf ^= lrand48 ();
srand48 (*(long *)buf);
}
return r;
}
void prng_seed (const char *password_filename, int password_length) {
unsigned char *a = calloc (64 + password_length, 1);
assert (a != NULL);
long long r = rdtsc ();
struct timespec T;
assert (clock_gettime(CLOCK_REALTIME, &T) >= 0);
memcpy (a, &T.tv_sec, 4);
memcpy (a+4, &T.tv_nsec, 4);
memcpy (a+8, &r, 8);
unsigned short p = getpid ();
memcpy (a + 16, &p, 2);
int s = get_random_bytes (a + 18, 32) + 18;
if (password_filename) {
int fd = open (password_filename, O_RDONLY);
if (fd < 0) {
fprintf (stderr, "Warning: fail to open password file - \"%s\", %m.\n", password_filename);
} else {
int l = read (fd, a + s, password_length);
if (l < 0) {
fprintf (stderr, "Warning: fail to read password file - \"%s\", %m.\n", password_filename);
} else {
if (verbosity > 0) {
fprintf (stderr, "read %d bytes from password file.\n", l);
}
s += l;
}
close (fd);
}
}
RAND_seed (a, s);
BN_ctx = BN_CTX_new ();
memset (a, 0, s);
free (a);
}
int serialize_bignum (BIGNUM *b, char *buffer, int maxlen) {
int itslen = BN_num_bytes (b);
int reqlen;
if (itslen < 254) {
reqlen = itslen + 1;
} else {
reqlen = itslen + 4;
}
int newlen = (reqlen + 3) & -4;
int pad = newlen - reqlen;
reqlen = newlen;
if (reqlen > maxlen) {
return -reqlen;
}
if (itslen < 254) {
*buffer++ = itslen;
} else {
*(int *)buffer = (itslen << 8) + 0xfe;
buffer += 4;
}
int l = BN_bn2bin (b, (unsigned char *)buffer);
assert (l == itslen);
buffer += l;
while (pad --> 0) {
*buffer++ = 0;
}
return reqlen;
}
long long compute_rsa_key_fingerprint (RSA *key) {
static char tempbuff[4096];
static unsigned char sha[20];
assert (key->n && key->e);
int l1 = serialize_bignum (key->n, tempbuff, 4096);
assert (l1 > 0);
int l2 = serialize_bignum (key->e, tempbuff + l1, 4096 - l1);
assert (l2 > 0 && l1 + l2 <= 4096);
SHA1 ((unsigned char *)tempbuff, l1 + l2, sha);
return *(long long *)(sha + 12);
}
void out_cstring (const char *str, long len) {
assert (len >= 0 && len < (1 << 24));
assert ((char *) packet_ptr + len + 8 < (char *) (packet_buffer + PACKET_BUFFER_SIZE));
char *dest = (char *) packet_ptr;
if (len < 254) {
*dest++ = len;
} else {
*packet_ptr = (len << 8) + 0xfe;
dest += 4;
}
memcpy (dest, str, len);
dest += len;
while ((long) dest & 3) {
*dest++ = 0;
}
packet_ptr = (int *) dest;
}
void out_cstring_careful (const char *str, long len) {
assert (len >= 0 && len < (1 << 24));
assert ((char *) packet_ptr + len + 8 < (char *) (packet_buffer + PACKET_BUFFER_SIZE));
char *dest = (char *) packet_ptr;
if (len < 254) {
dest++;
if (dest != str) {
memmove (dest, str, len);
}
dest[-1] = len;
} else {
dest += 4;
if (dest != str) {
memmove (dest, str, len);
}
*packet_ptr = (len << 8) + 0xfe;
}
dest += len;
while ((long) dest & 3) {
*dest++ = 0;
}
packet_ptr = (int *) dest;
}
void out_data (const char *data, long len) {
assert (len >= 0 && len < (1 << 24) && !(len & 3));
assert ((char *) packet_ptr + len + 8 < (char *) (packet_buffer + PACKET_BUFFER_SIZE));
memcpy (packet_ptr, data, len);
packet_ptr += len >> 2;
}
int *in_ptr, *in_end;
int fetch_bignum (BIGNUM *x) {
int l = prefetch_strlen ();
if (l < 0) {
return l;
}
char *str = fetch_str (l);
assert (BN_bin2bn ((unsigned char *) str, l, x) == x);
return l;
}
int pad_rsa_encrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *E) {
int pad = (255000 - from_len - 32) % 255 + 32;
int chunks = (from_len + pad) / 255;
int bits = BN_num_bits (N);
assert (bits >= 2041 && bits <= 2048);
assert (from_len > 0 && from_len <= 2550);
assert (size >= chunks * 256);
assert (RAND_pseudo_bytes ((unsigned char *) from + from_len, pad) >= 0);
int i;
BIGNUM x, y;
BN_init (&x);
BN_init (&y);
rsa_encrypted_chunks += chunks;
for (i = 0; i < chunks; i++) {
BN_bin2bn ((unsigned char *) from, 255, &x);
assert (BN_mod_exp (&y, &x, E, N, BN_ctx) == 1);
unsigned l = 256 - BN_num_bytes (&y);
assert (l <= 256);
memset (to, 0, l);
BN_bn2bin (&y, (unsigned char *) to + l);
to += 256;
}
BN_free (&x);
BN_free (&y);
return chunks * 256;
}
int pad_rsa_decrypt (char *from, int from_len, char *to, int size, BIGNUM *N, BIGNUM *D) {
if (from_len < 0 || from_len > 0x1000 || (from_len & 0xff)) {
return -1;
}
int chunks = (from_len >> 8);
int bits = BN_num_bits (N);
assert (bits >= 2041 && bits <= 2048);
assert (size >= chunks * 255);
int i;
BIGNUM x, y;
BN_init (&x);
BN_init (&y);
for (i = 0; i < chunks; i++) {
++rsa_decrypted_chunks;
BN_bin2bn ((unsigned char *) from, 256, &x);
assert (BN_mod_exp (&y, &x, D, N, BN_ctx) == 1);
int l = BN_num_bytes (&y);
if (l > 255) {
BN_free (&x);
BN_free (&y);
return -1;
}
assert (l >= 0 && l <= 255);
memset (to, 0, 255 - l);
BN_bn2bin (&y, (unsigned char *) to + 255 - l);
to += 255;
}
BN_free (&x);
BN_free (&y);
return chunks * 255;
}
unsigned char aes_key_raw[32], aes_iv[32];
AES_KEY aes_key;
void init_aes_unauth (const char server_nonce[16], const char hidden_client_nonce[32], int encrypt) {
static unsigned char buffer[64], hash[20];
memcpy (buffer, hidden_client_nonce, 32);
memcpy (buffer + 32, server_nonce, 16);
SHA1 (buffer, 48, aes_key_raw);
memcpy (buffer + 32, hidden_client_nonce, 32);
SHA1 (buffer, 64, aes_iv + 8);
memcpy (buffer, server_nonce, 16);
memcpy (buffer + 16, hidden_client_nonce, 32);
SHA1 (buffer, 48, hash);
memcpy (aes_key_raw + 20, hash, 12);
memcpy (aes_iv, hash + 12, 8);
memcpy (aes_iv + 28, hidden_client_nonce, 4);
if (encrypt == AES_ENCRYPT) {
AES_set_encrypt_key (aes_key_raw, 32*8, &aes_key);
} else {
AES_set_decrypt_key (aes_key_raw, 32*8, &aes_key);
}
}
void init_aes_auth (char auth_key[192], char msg_key[16], int encrypt) {
static unsigned char buffer[48], hash[20];
// sha1_a = SHA1 (msg_key + substr (auth_key, 0, 32));
// sha1_b = SHA1 (substr (auth_key, 32, 16) + msg_key + substr (auth_key, 48, 16));
// sha1_с = SHA1 (substr (auth_key, 64, 32) + msg_key);
// sha1_d = SHA1 (msg_key + substr (auth_key, 96, 32));
// aes_key = substr (sha1_a, 0, 8) + substr (sha1_b, 8, 12) + substr (sha1_c, 4, 12);
// aes_iv = substr (sha1_a, 8, 12) + substr (sha1_b, 0, 8) + substr (sha1_c, 16, 4) + substr (sha1_d, 0, 8);
memcpy (buffer, msg_key, 16);
memcpy (buffer + 16, auth_key, 32);
SHA1 (buffer, 48, hash);
memcpy (aes_key_raw, hash, 8);
memcpy (aes_iv, hash + 8, 12);
memcpy (buffer, auth_key + 32, 16);
memcpy (buffer + 16, msg_key, 16);
memcpy (buffer + 32, auth_key + 48, 16);
SHA1 (buffer, 48, hash);
memcpy (aes_key_raw + 8, hash + 8, 12);
memcpy (aes_iv + 12, hash, 8);
memcpy (buffer, auth_key + 64, 32);
memcpy (buffer + 32, msg_key, 16);
SHA1 (buffer, 48, hash);
memcpy (aes_key_raw + 20, hash + 4, 12);
memcpy (aes_iv + 20, hash + 16, 4);
memcpy (buffer, msg_key, 16);
memcpy (buffer + 16, auth_key + 96, 32);
SHA1 (buffer, 48, hash);
memcpy (aes_iv + 24, hash, 8);
if (encrypt == AES_ENCRYPT) {
AES_set_encrypt_key (aes_key_raw, 32*8, &aes_key);
} else {
AES_set_decrypt_key (aes_key_raw, 32*8, &aes_key);
}
}
int pad_aes_encrypt (char *from, int from_len, char *to, int size) {
int padded_size = (from_len + 15) & -16;
assert (from_len > 0 && padded_size <= size);
if (from_len < padded_size) {
assert (RAND_pseudo_bytes ((unsigned char *) from + from_len, padded_size - from_len) >= 0);
}
AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, padded_size, &aes_key, aes_iv, AES_ENCRYPT);
return padded_size;
}
int pad_aes_decrypt (char *from, int from_len, char *to, int size) {
if (from_len <= 0 || from_len > size || (from_len & 15)) {
return -1;
}
AES_ige_encrypt ((unsigned char *) from, (unsigned char *) to, from_len, &aes_key, aes_iv, AES_DECRYPT);
return from_len;
}
This diff is collapsed.
This diff is collapsed.
#ifndef __NET_H__
#define __NET_H__
#include <poll.h>
struct dc;
#include "queries.h"
#define TG_SERVER "173.240.5.1"
//#define TG_SERVER "95.142.192.66"
#define TG_APP_HASH "3bc14c6455ef1595ec86a125762c3aad"
#define TG_APP_ID 51
#define ACK_TIMEOUT 60
#define MAX_DC_ID 10
enum dc_state{
st_init,
st_reqpq_sent,
st_reqdh_sent,
st_client_dh_sent,
st_authorized,
st_error
} ;
struct connection;
struct connection_methods {
int (*ready) (struct connection *c);
int (*close) (struct connection *c);
int (*execute) (struct connection *c, int op, int len);
};
#define MAX_DC_SESSIONS 3
struct session {
struct dc *dc;
long long session_id;
int seq_no;
struct connection *c;
struct tree_int *ack_tree;
struct event_timer ev;
};
struct dc {
int id;
int port;
int flags;
char *ip;
char *user;
struct session *sessions[MAX_DC_SESSIONS];
char auth_key[256];
long long auth_key_id;
long long server_salt;
int server_time_delta;
double server_time_udelta;
};
#define DC_SERIALIZED_MAGIC 0x64582faa
struct dc_serialized {
int magic;
int port;
char ip[64];
char user[64];
char auth_key[256];
long long auth_key_id, server_salt;
int authorized;
};
struct connection_buffer {
void *start;
void *end;
void *rptr;
void *wptr;
struct connection_buffer *next;
};
enum conn_state {
conn_none,
conn_connecting,
conn_ready,
conn_failed,
conn_stopped
};
struct connection {
int fd;
int ip;
int port;
int flags;
enum conn_state state;
int ipv6[4];
struct connection_buffer *in_head;
struct connection_buffer *in_tail;
struct connection_buffer *out_head;
struct connection_buffer *out_tail;
int in_bytes;
int out_bytes;
int packet_num;
int out_packet_num;
struct connection_methods *methods;
struct session *session;
void *extra;
};
extern struct connection *Connections[];
int write_out (struct connection *c, const void *data, int len);
void flush_out (struct connection *c);
int read_in (struct connection *c, void *data, int len);
void create_all_outbound_connections (void);
struct connection *create_connection (const char *host, int port, struct session *session, struct connection_methods *methods);
int connections_make_poll_array (struct pollfd *fds, int max);
void connections_poll_result (struct pollfd *fds, int max);
void dc_create_session (struct dc *DC);
void insert_seqno (struct session *S, int seqno);
struct dc *alloc_dc (int id, char *ip, int port);
#define GET_DC(c) (c->session->dc)
#endif
This diff is collapsed.
#include "net.h"
#ifndef __QUERIES_H__
#define __QUERIES_H__
#define QUERY_ACK_RECEIVED 1
struct query;
struct query_methods {
int (*on_answer)(struct query *q);
int (*on_error)(struct query *q, int error_code, int len, char *error);
int (*on_timeout)(struct query *q);
};
struct event_timer {
double timeout;
int (*alarm)(void *self);
void *self;
};
struct query {
long long msg_id;
int data_len;
int flags;
void *data;
struct query_methods *methods;
struct event_timer ev;
};
struct query *send_query (struct dc *DC, int len, void *data, struct query_methods *methods);
void query_ack (long long id);
void query_error (long long id);
void query_result (long long id);
void insert_event_timer (struct event_timer *ev);
void remove_event_timer (struct event_timer *ev);
double next_timer_in (void);
void work_timers (void);
extern struct query_methods help_get_config_methods;
void do_send_code (const char *user);
int do_send_code_result (const char *code);
double get_double_time (void);
void do_update_contact_list (void);
#endif
#include <assert.h>
#include "structures.h"
#include "mtproto-common.h"
void fetch_file_location (struct file_location *loc) {
int x = fetch_int ();
if (x == CODE_file_location_unavailable) {
loc->dc = -1;
loc->volume = fetch_long ();
loc->local_id = fetch_int ();
loc->secret = fetch_long ();
} else {
assert (x == CODE_file_location);
loc->dc = fetch_int ();;
loc->volume = fetch_long ();
loc->local_id = fetch_int ();
loc->secret = fetch_long ();
}
}
void fetch_user_status (struct user_status *S) {
int x = fetch_int ();
switch (x) {
case CODE_user_status_empty:
S->online = 0;
break;
case CODE_user_status_online:
S->online = 1;
S->when = fetch_int ();
break;
case CODE_user_status_offline:
S->online = -1;
S->when = fetch_int ();
break;
default:
assert (0);
}
}
void fetch_user (struct user *U) {
memset (U, 0, sizeof (*U));
unsigned x = fetch_int ();
assert (x == CODE_user_empty || x == CODE_user_self || x == CODE_user_contact || x == CODE_user_request || x == CODE_user_foreign || x == CODE_user_deleted);
U->id = fetch_int ();
if (x == CODE_user_empty) {
U->flags = 1;
return;
}
U->first_name = fetch_str_dup ();
U->last_name = fetch_str_dup ();
if (x == CODE_user_deleted) {
U->flags = 2;
return;
}
if (x == CODE_user_self) {
U->flags = 4;
} else {
U->access_hash = fetch_long ();
}
if (x == CODE_user_foreign) {
U->flags |= 8;
} else {
U->phone = fetch_str_dup ();
}
unsigned y = fetch_int ();
if (y == CODE_user_profile_photo_empty) {
U->photo_small.dc = -2;
U->photo_big.dc = -2;
} else {
assert (y == CODE_user_profile_photo);
fetch_file_location (&U->photo_small);
fetch_file_location (&U->photo_big);
}
fetch_user_status (&U->status);
if (x == CODE_user_self) {
assert (fetch_int () == (int)CODE_bool_false);
}
if (x == CODE_user_contact) {
U->flags |= 16;
}
}
#ifndef __STRUCTURES_H__
#define __STRUCTURES_H__
struct file_location {
int dc;
long long volume;
int local_id;
long long secret;
};
struct user_status {
int online;
int when;
};
struct user {
int id;
int flags;
char *first_name;
char *last_name;
char *phone;
long long access_hash;
struct file_location photo_big;
struct file_location photo_small;
struct user_status status;
};
void fetch_file_location (struct file_location *loc);
void fetch_user (struct user *U);
#endif
#ifndef __TREE_H__
#define __TREE_H__
#include <stdio.h>
#include <memory.h>
#include <malloc.h>
#include <assert.h>
#define DEFINE_TREE(X_NAME, X_TYPE, X_CMP, X_UNSET) \
struct tree_ ## X_NAME { \
struct tree_ ## X_NAME *left, *right;\
X_TYPE x;\
int y;\
};\
\
struct tree_ ## X_NAME *new_tree_node_ ## X_NAME (X_TYPE x, int y) {\
struct tree_ ## X_NAME *T = malloc (sizeof (*T));\
T->x = x;\
T->y = y;\
T->left = T->right = 0;\
return T;\
}\
\
void delete_tree_node_ ## X_NAME (struct tree_ ## X_NAME *T) {\
free (T);\
}\
\
void tree_split_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, struct tree_ ## X_NAME **L, struct tree_ ## X_NAME **R) {\
if (!T) {\
*L = *R = 0;\
} else {\
int c = X_CMP (x, T->x);\
if (c < 0) {\
tree_split_ ## X_NAME (T->left, x, L, &T->left);\
*R = T;\
} else {\
tree_split_ ## X_NAME (T->right, x, &T->right, R);\
*L = T;\
}\
}\
}\
\
struct tree_ ## X_NAME *tree_insert_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x, int y) {\
if (!T) {\
return new_tree_node_ ## X_NAME (x, y);\
} else {\
if (y > T->y) {\
struct tree_ ## X_NAME *N = new_tree_node_ ## X_NAME (x, y);\
tree_split_ ## X_NAME (T, x, &N->left, &N->right);\
return N;\
} else {\
int c = X_CMP (x, T->x);\
assert (c);\
return tree_insert_ ## X_NAME (c < 0 ? T->left : T->right, x, y);\
}\
}\
}\
\
struct tree_ ## X_NAME *tree_merge_ ## X_NAME (struct tree_ ## X_NAME *L, struct tree_ ## X_NAME *R) {\
if (!L || !R) {\
return L ? L : R;\
} else {\
if (L->y > R->y) {\
L->right = tree_merge_ ## X_NAME (L->right, R);\
return L;\
} else {\
R->left = tree_merge_ ## X_NAME (L, R->left);\
return R;\
}\
}\
}\
\
struct tree_ ## X_NAME *tree_delete_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\
assert (T);\
int c = X_CMP (x, T->x);\
if (!c) {\
struct tree_ ## X_NAME *N = tree_merge_ ## X_NAME (T->left, T->right);\
delete_tree_node_ ## X_NAME (T);\
return N;\
} else {\
return tree_delete_ ## X_NAME (c < 0 ? T->left : T->right, x);\
}\
}\
\
X_TYPE tree_get_min_ ## X_NAME (struct tree_ ## X_NAME *T) {\
if (!T) { return X_UNSET; } \
while (T->left) { T = T->left; }\
return T->x; \
} \
\
X_TYPE tree_lookup_ ## X_NAME (struct tree_ ## X_NAME *T, X_TYPE x) {\
int c;\
while (T && (c = X_CMP (x, T->x))) {\
T = (c < 0 ? T->left : T->right);\
}\
return T ? T->x : X_UNSET;\
}\
\
int tree_count_ ## X_NAME (struct tree_ ## X_NAME *T) { \
if (!T) { return 0; }\
return 1 + tree_count_ ## X_NAME (T->left) + tree_count_ ## X_NAME (T->right); \
}\
void tree_check_ ## X_NAME (struct tree_ ## X_NAME *T) { \
if (!T) { return; }\
if (T->left) { \
assert (T->left->y <= T->y);\
assert (X_CMP (T->left->x, T->x) < 0); \
}\
if (T->right) { \
assert (T->right->y <= T->y);\
assert (X_CMP (T->right->x, T->x) > 0); \
}\
}\
#define int_cmp(a,b) ((a) - (b))
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment