Criticism of the Telegram protocol and organizational approaches. Part 1, technical: experience writing a client from scratch - TL, MT

Recently, posts have started appearing on HabrΓ© about how good Telegram is, how brilliant and experienced the Durov brothers are in building network systems, etc. At the same time, very few people really plunged into the technical device - at maximum, they use a fairly simple (and very different from MTProto) Bot API based on JSON, and usually they just take all the praises and public relations that revolve around the messenger. Almost a year and a half ago, my colleague at the Echelon NGO Vasily (unfortunately, his account on Habr erased along with a draft) began writing his own Telegram client from scratch on Perl, and the author of these lines later joined. Why at Perl, some will ask immediately? Because in other languages ​​such projects already exist In fact, this is not the point, there could be any other language where there is no ready-made library , and accordingly, the author must go all the way from scratch . Moreover, cryptography is such a thing - trust, but verify. With a product aimed at security, you can’t just take and rely on the finished library from the manufacturer, blindly believing it (however, this is a topic more for the second part). At the moment, the library works quite well at the "middle" level (it allows you to make any API requests).







However, in this series of posts there will be not much cryptography and mathematics. But there will be many other technical details and architectural crutches (useful to those who will not write from scratch, but will use the library in any language). So, the main goal was to try to implement the client from scratch according to official documentation . That is, suppose that the source code of official clients is closed (again, in the second part, we will expand on the topic of how this really happens ), but, as in the old days, for example, there is a standard like RFC - is it possible to write a client using just one specification, "not peeping" at the source, at least official (Telegram Desktop, mobile), at least unofficial Telethon?







Table of contents:









Documentation ... does it exist? True?..



Fragments of notes for this article began to be collected last summer. All this time on the official site https://core.telegram.org the documentation was as of Layer 23, i.e. stuck somewhere in 2014 (remember, then there weren’t even any channels yet?). Of course, in theory, this should have allowed us to implement a client with functionality at that time in 2014. But even in this state, the documentation was, firstly, incomplete, and secondly, sometimes contradicted itself. A little more than a month ago, in September 2019, it was accidentally discovered that the site had a large update of the documentation, on the completely fresh Layer 105, with the note that now everything needs to be read again. Indeed, many articles were revised, but many remained unchanged. Therefore, reading the criticisms below regarding documentation, it should be borne in mind that some of these things are no longer relevant, but some are still quite. In the end, 5 years in the modern world is not just a lot, but a lot. Since then (especially if you do not take into account the ejected and re-resumed since then geochats), the number of API methods in the scheme has grown from a hundred to more than two hundred and fifty!







Where to start a young author?



, Telethon Python Madeline PHP, β€” api_id



api_hash



( API ), . , , , . , , β€” , , .







, , , Telegram , , .. , "" , , .. . , , .







, . https://core.telegram.org/ Getting Started , MTProto β€” OSI , .







, MTProto, , ( , layer violation) , ...







: TL (Type Language) , ,



, , Telegram β€” . , , .







, . , , JSON Schema, . : . , , . MTProto, , - , :







int ? = Int;
long ? = Long;
double ? = Double;
string ? = String;

vector#1cb5c415 {t:Type} # [ t ] = Vector t;

rpc_error#2144ca19 error_code:int error_message:string = RpcError;

rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
rpc_answer_dropped_running#cd78e586 = RpcDropAnswer;
rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer;

msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;

---functions---

set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:bytes = Set_client_DH_params_answer;

ping#7abe77ec ping_id:long = Pong;
ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;

invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
invokeAfterMsgs#3dc4b4f0 msg_ids:Vector<long> query:!X = X;

account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User;
account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;
      
      





, , β€” , ( , ?), , … . ++ ( , ). , , , , ( ), - , - , β€” , ( ) ? (, JSON- β€” ).







Binary Data Serialization 4 . , , , , , , , … ! TL Language, , , , !







, , , , , , , - . :









LeoNerd #perl



IRC- FreeNode, Telegram Matrix ( ):







, - , , , .

, bare- (int, long ..) - β€” β€” . , , , .













TL , …



constructor = Type;
myVec ids:Vector<long> = Type;

fixed#abcdef34 id:int = Type2;

fixedVec set:Vector<Type2> = FixedVec;

constructorOne#crc32 field1:int = PolymorType;
constructorTwo#2crc32 field_a:long field_b:Type3 field_c:int = PolymorType;
constructorThree#deadcrc bit_flags_of_what_really_present:# optional_field4:bit_flags_of_what_really_present.1?Type = PolymorType;

an_id#12abcd34 id:int = Type3;
a_null#6789cdef = Type3;
      
      





, ( β€” ) #



CRC32 . , β€” . , β€” , , β€” . , , β€” .







---functions---



, , : RPC-, β€” ( , , ), " " β€” . , , β€” ---types---



, " ". , .. , , C++, TL - .







"" "", ? , , - β€” , β€” -, final



. , , - . β€” , ( , , ) β€” , .







? , 4 , 0xcrc32



β€” , field1



int



, .. 4 , PolymorType



. 0x2crc32



, , long



, 8 . , . , Type3



, , 0x12abcd34



, 4 int



, 0x6789cdef



, . β€” . 4 int



field_c



constructorTwo



PolymorType



.







, 0xdeadcrc



constructorThree



, . bit_flags_of_what_really_present



#



β€” , nat



, " ". , , unsigned int β€” , , , . , , , β€” on the wire, , ( ). , , , , Type



, 2 . ( ), ids



ids:Vector<long>



.







, generic' Java. . , . , Vector. 4 CRC32 Vector, , 4 β€” , .







, 4 , β€” bytes



string



4 β€” , ? TL , , , 4 , JSON ? , , , , ?..







, , , . -, CRC32 ( whitespace ..) β€” , , CRC32 , , . , , , ?..







-, CRC32, - , (). β€” , 232, . , CRC32 ( ) , ? , : CRC32 , 4 4 β€” . ( ), , .







, , CRC32? ( ) -, 239, -!

, , , Vector<int>



Vector<PolymorType>



CRC32. ? , ? , , Vector<int>



, 40000 . Vector<Type2>



, int



β€” 10000 0xabcdef34 4 int



, fixedVec



80000 40000 ?







β€” , , id, , β€” . Telegram .







...







Vector,



, , ( ) tuples . , , , . ? , , β€” lazy evaluation . : , .. β€” , β€” ( (cons)



Lisp). , , 4 (CRC32 TL) . , β€” .







, TL , . :







Serialization always uses the same constructor β€œvector” (const 0x1cb5c415 = crc32("vector t:Type # [ t ] = Vector t”) that is not dependent on the specific value of the variable of type t.



The value of the optional parameter t is not involved in the serialization since it is derived from the result type (always known prior to deserialization).

: vector {t:Type} # [ t ] = Vector t



β€” , ! . , . , :







The Vector t polymorphic pseudotype is a β€œtype” whose value is a sequence of values of any type t, either boxed or bare.

… . , ( ), , : , ( - ACM), . β€” β€” .







, . , #



nat



, :



There are type expressions (type-expr) and numeric expressions (nat-expr). However, they are defined the same way.

type-expr ::= expr
nat-expr ::= expr
      
      







, .. .

, (vector<int>



, vector<User>



) (#1cb5c415



), .. ,







users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
      
      





, . , β€” , bare-, , - β€” ? - PHP, ?







β€” TL? , , protobuf, ? , .







TL



TL (), Telegram. . , Telegram. , ( ( ) ).







Templates are not used now. Instead, the same universal constructors (for example, vector {t:Type} [t] = Vector t) are used w
      
      





, , , .







#define ZHUKOV_BYTES_HACK

#ifdef ZHUKOV_BYTES_HACK

/* dirty hack for Zhukov request */
      
      





, :







    static const char *reserved_words_polymorhic[] = {

      "alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", NULL

      };
      
      





β€” , :







intHash {alpha:Type} vector<coupleInt<alpha>> = IntHash<alpha>;
      
      





, int β€” Type. C++ :







    template <T> class IntHash {
      vector<pair<int,T>> _map;
    }
      
      





, alpha



β€” ! C++ T, alpha, beta… 8 , . , - :







--    TL 
-- ...     , ,...     ... , !
-- ?   

-- ,        !
--  ,     ?
--   ,     ,  --  
      
      





TL "". Telegram-.







:







Vasily, [09.10.18 17:07]

, , ,

, .jpg

.webp

, , , , - DSL, ?..







telegram-cli , TLO (cli) , β€” TL , TL?..







16.12 04:18 Vasily: -, - lex+yacc

16.12 04:18 Vasily:

16.12 04:18 Vasily:

16.12 04:19 Vasily: 3+ <censored>



, ? , β€” Telegram Desktop:







    nametype = re.match(r'([a-zA-Z\.0-9_]+)(#[0-9a-f]+)?([^=]*)=\s*([a-zA-Z\.<>0-9_]+);', line);
    if (not nametype):
      if (not re.match(r'vector#1cb5c415 \{t:Type\} # \[ t \] = Vector t;', line)):
         print('Bad line found: ' + line);
      
      





1100+ , + , , , TL, , … , , ?!







… , CRC32? , Telegram Desktop , CRC32 !







Vasily, [18.12 22:49]

, TL

, ,

tdesktop, ,

, .







, telegram-cli β€” , Telegram Desktop β€” , ? ?.. Android- ( , ), , .







? , , , :







Vasily: flags.0? true





, true,



Vasily: flags.1? int





, ,



Vasily: , , !

Vasily: - , true β€” , -

Vasily: ,

, , Telethon? MTProto, β€” , %



" bare-", .. , :







Vasily, [22.06.18 18:38]

:

msg_container#73f1f8dc messages:vector message = MessageContainer;
      
      







:

msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;
      
      







, -



bare



telethon



msg_container







, %. .



Vadim Goncharov, [22.06.18 19:22]

tdesktop?



Vasily, [22.06.18 19:23]

TL



// parsed manually







TL ,



%



,



,



TL,

" ", , "- , , ".







: " ,







    args: /* empty */ { $$ = NULL; }
        | args arg { $$ = g_list_append( $1, $2 ); }
        ;

    arg: LC_ID ':' type-term { $$ = tl_arg_new( $1, $3 ); }
            | LC_ID ':' condition '?' type-term { $$ = tl_arg_new_cond( $1, $5, $3 ); free($3); }
            | UC_ID ':' type-term { $$ = tl_arg_new( $1, $3 ); }
            | type-term { $$ = tl_arg_new( "", $1 ); }
            | '[' LC_ID ']' { $$ = tl_arg_new_mult( "", tl_type_new( $2, TYPE_MOD_NONE ) ); }
            ;
      
      





- ,







struct tree *parse_args4 (void) {
  PARSE_INIT (type_args4);
  struct parse so = save_parse ();
  PARSE_TRY (parse_optional_arg_def);
  if (S) {
    tree_add_child (T, S);
  } else {
    load_parse (so);
  }
  if (LEX_CHAR ('!')) {
    PARSE_ADD (type_exclam);
    EXPECT ("!");
  }
  PARSE_TRY_PES (parse_type_term);
  PARSE_OK;
}
      
      











        # Regex to match the whole line
        match = re.match(r'''
            ^                  # We want to match from the beginning to the end
            ([\w.]+)           # The .tl object can contain alpha_name or namespace.alpha_name
            (?:
                \#             # After the name, comes the ID of the object
                ([0-9a-f]+)    # The constructor ID is in hexadecimal form
            )?                 # If no constructor ID was given, CRC32 the 'tl' to determine it

            (?:\s              # After that, we want to match its arguments (name:type)
                {?             # For handling the start of the '{X:Type}' case
                \w+            # The argument name will always be an alpha-only name
                :              # Then comes the separator between name:type
                [\w\d<>#.?!]+  # The type is slightly more complex, since it's alphanumeric and it can
                               # also have Vector<type>, flags:# and flags.0?default, plus :!X as type
                }?             # For handling the end of the '{X:Type}' case
            )*                 # Match 0 or more arguments
            \s                 # Leave a space between the arguments and the equal
            =
            \s                 # Leave another space between the equal and the result
            ([\w\d<>#.?]+)     # The result can again be as complex as any argument type
            ;$                 # Finally, the line should always end with ;
            ''', tl, re.IGNORECASE | re.VERBOSE)
      
      





:







    ---functions---         return FUNCTIONS;
    ---types---             return TYPES;
    [a-z][a-zA-Z0-9_]*      yylval.string = strdup(yytext); return LC_ID;
    [A-Z][a-zA-Z0-9_]*      yylval.string = strdup(yytext); return UC_ID;
    [0-9]+                  yylval.number = atoi(yytext); return NUM;
    #[0-9a-fA-F]{1,8}       yylval.number = strtol(yytext+1, NULL, 16); return ID_HASH;

    \n                      /* skip new line */
    [ \t]+                  /* skip spaces */
    \/\/.*$                 /* skip comments */
    \/\*.*\*\/              /* skip comments */
    .                       return (int)yytext[0];
      
      





.. β€” ".







, TL 100 ~300 ( print



' ), . , β€” .









β€” , ? , ( ), TL. , . , , , . ?







, constraints. :







The file’s binary content is then split into parts. All parts must have the same size ( part_size ) and the following conditions must be met:

  • part_size % 1024 = 0



    (divisible by 1KB)
  • 524288 % part_size = 0



    (512KB must be evenly divisible by part_size)




The last part does not have to satisfy these conditions, provided its size is less than part_size.



Each part should have a sequence number, file_part, with a value ranging from 0 to 2,999.



After the file has been partitioned you need to choose a method for saving it on the server. Use upload.saveBigFilePart in case the full size of the file is more than 10 MB and upload.saveFilePart for smaller files.

[...] one of the following data input errors may be returned:

  • FILE_PARTS_INVALID β€” Invalid number of parts. The value is not between 1..3000





- ? - TL? . , Turbo Pascal , . , enum



β€” , () . β€” , , . , … , , , ?







TL . , , JSON Schema. 512 - , , , 1..3000



( ) , ?..







, . , TL β€” , TL , . TL . , ( , RPC -, ) β€” ?.. β€” .







, ? , , description ( JSON- ), , β€” ? :







-channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;





+channelFull#1c87a71a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;















-message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;





+message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;









, GitHub, , . " 10 ", , , - … , , .







, . ? , ? . , , . :







storage.fileUnknown#aa963b05 = storage.FileType;
storage.filePartial#40bc6f52 = storage.FileType;
storage.fileJpeg#7efe0e = storage.FileType;
storage.fileGif#cae1aadf = storage.FileType;
storage.filePng#a4f63c0 = storage.FileType;
storage.filePdf#ae1e508d = storage.FileType;
storage.fileMp3#528a0677 = storage.FileType;
storage.fileMov#4b09ebbc = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;
      
      





, 5 , 32 . . TL .







, . , MTProto ( ) Gzip, β€” , . , RpcResult, . ?.. , .







, β€” InputPeerUser



InputUser



. . ! . ? , , telegram-cli:







  if (tgl_get_peer_type (E->id) != TGL_PEER_CHANNEL || (C && (C->flags & TGLCHF_MEGAGROUP))) {
    out_int (CODE_messages_get_history);
    out_peer_id (TLS, E->id);
  } else {    
    out_int (CODE_channels_get_important_history);

    out_int (CODE_input_channel);
    out_int (tgl_get_peer_id (E->id));
    out_long (E->id.access_hash);
  }
  out_int (E->max_id);
  out_int (E->offset);
  out_int (E->limit);
  out_int (0);
  out_int (0);
      
      





, , ! , ?.. , , , ? ? .







. (layers)



, , . , , , , , , . , β€” "", . , . , β€” , . 2. TL:







If a client supports Layer 2, then the following constructor must be used:

invokeWithLayer2#289dd1f6 {X:Type} query:!X = X;
      
      







In practice, this means that before every API call, an int with the value 0x289dd1f6



must be added before the method number.

. ?







invokeWithLayer3#b7475268 query:!X = X;
      
      





? ,







invokeWithLayer4#dea0d430 query:!X = X;
      
      





? , , , β€” , -? 4 β€” . So,







invokeWithLayer5#417a57ae query:!X = X;
      
      





, . :







Update: Starting with Layer 9, helper methods invokeWithLayerN



can be used only together with initConnection



! 9 , , , Internet- 80- β€” !







?..







invokeWithLayer10#39620c41 query:!X = X;
...
invokeWithLayer18#1c900537 query:!X = X;
      
      





. 9 , , , , , , . .







?..







Vasily, [16.07.18 14:01]

:

. InvokeWithLayer. , .



.. ,



Vadim Goncharov, [16.07.18 14:02]

InvokeWithLayer ?



Vasily, [16.07.18 14:02]





Vadim Goncharov, [16.07.18 14:02]





, ,

, .. Updates



β€” , API-, . , , , Updates .







, , :









, , , ( , )? ! !







. 14 , Telegram - … :







2019-08-15 09:28:35.880640 MSK warn  main: ANON:87: unknown object type: 0x80d182d1 at TL/Object.pm line 213.
2019-08-15 09:28:35.751899 MSK warn  main: ANON:87: unknown object type: 0xb5223b0f at TL/Object.pm line 213.
      
      





(, ). TL - β€” , , . ?







, β€” . . CRC32 β€” 73 , 82. β€” !







, ? , Telegram Desktop 1.2.17 (, Linux), Exception: MTP Unexpected type id #b5223b0f read in MTPMessageMedia...













, - , ...







-? : 91, 73. , , , , .







: , , , , , β€” , . .







? , . , , "", , , , . "", .







… ?!.. , , . Android TL-, ( ) (). :







public static class TL_message_layer68 extends TL_message {
    public static int constructor = 0xc09be45f;
//...
//  
//...
    public static class TL_message_layer47 extends TL_message {
        public static int constructor = 0xc992e15c;
        public static Message TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) {
            Message result = null;
            switch (constructor) {
                case 0x1d86f70e:
                    result = new TL_messageService_old2();
                    break;
                case 0xa7ab1991:
                    result = new TL_message_old3();
                    break;
                case 0xc3060325:
                    result = new TL_message_old4();
                    break;
                case 0x555555fa:
                    result = new TL_message_secret();
                    break;
                case 0x555555f9:
                    result = new TL_message_secret_layer72();
                    break;
                case 0x90dddc11:
                    result = new TL_message_layer72();
                    break;
                case 0xc09be45f:
                    result = new TL_message_layer68();
                    break;
                case 0xc992e15c:
                    result = new TL_message_layer47();
                    break;
                case 0x5ba66c13:
                    result = new TL_message_old7();
                    break;
                case 0xc06b9607:
                    result = new TL_messageService_layer48();
                    break;
                case 0x83e5de54:
                    result = new TL_messageEmpty();
                    break;
                case 0x2bebfa86:
                    result = new TL_message_old6();
                    break;
                case 0x44f9b43d:
                    result = new TL_message_layer104();
                    break;
                case 0x1c9b1027:
                    result = new TL_message_layer104_2();
                    break;
                case 0xa367e716:
                    result = new TL_messageForwarded_old2(); //custom
                    break;
                case 0x5f46804:
                    result = new TL_messageForwarded_old(); //custom
                    break;
                case 0x567699b3:
                    result = new TL_message_old2(); //custom
                    break;
                case 0x9f8d60bb:
                    result = new TL_messageService_old(); //custom
                    break;
                case 0x22eb6aba:
                    result = new TL_message_old(); //custom
                    break;
                case 0x555555F8:
                    result = new TL_message_secret_old(); //custom
                    break;
                case 0x9789dac4:
                    result = new TL_message_layer104_3();
                    break;
      
      











    boolean fixCaption = !TextUtils.isEmpty(message) &&
    (media instanceof TLRPC.TL_messageMediaPhoto_old ||
     media instanceof TLRPC.TL_messageMediaPhoto_layer68 ||
     media instanceof TLRPC.TL_messageMediaPhoto_layer74 ||
     media instanceof TLRPC.TL_messageMediaDocument_old ||
     media instanceof TLRPC.TL_messageMediaDocument_layer68 ||
     media instanceof TLRPC.TL_messageMediaDocument_layer74)
    && message.startsWith("-1");
      
      





… . , , , ?.. ! , , , , _old7



- … ,







TL_message_layer104
TL_message_layer104_2
TL_message_layer104_3
      
      





, , ?! , , "", , , , ?.. ? , ?..







Telegram Desktop, , β€” , , - . , , , ? , , , .







? , -, .







, :







public static class TL_folders_deleteFolder extends TLObject {
    public static int constructor = 0x1c295881;

    public int folder_id;

    public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) {
        return Updates.TLdeserialize(stream, constructor, exception);
    }

    public void serializeToStream(AbstractSerializedData stream) {
        stream.writeInt32(constructor);
        stream.writeInt32(folder_id);
    }
}

//manually created

//RichText start
public static abstract class RichText extends TLObject {
    public String url;
    public long webpage_id;
    public String email;
    public ArrayList<RichText> texts = new ArrayList<>();
    public RichText parentRichText;

    public static RichText TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) {
        RichText result = null;
        switch (constructor) {
            case 0x1ccb966a:
                result = new TL_textPhone();
                break;
            case 0xc7fb5e01:
                result = new TL_textSuperscript();
                break;
      
      





"manually created" , ( maintenance?), . , β€” , (- GPL Linux), .







. , .







MTProto



, . . , Telegram β€” -, , (, API sticker pack β€” , ).







, "" (message) "" (session) β€” , Telegram-. , , , "" β€” , , , , . … .









β€” . 5 :









Vasily, [15.06.18 15:04]

UDP ,



TCP



UDP TCP, sequence number crc

?

, TCP 4 :









, Padded intermediate MTProxy, - . ( ), ? , payload MTProto, :









Abridged, , Intermediate, "In case 4-byte data alignment is needed", - . , , Telegram , ? , ( -...). , Abridged, padding' 16 β€” 3 ?







, , , .







, .. Web MTProxy, , , , . MTProxy , 2018, , , ! , ( ) MTProxy , ( ), Go, Node.js .







, . 5- OSI, β€” MTProto session.







, , , Diffie-Hellman



… β€” , Active sessions. .









. , plaintext β€” . "" ? Telegram ( 4 , ):







session β€” UI "current sessions", / OS.

β€” MTProto session, sequence number ( ) , TCP-. MTProto-, .



sessions authorization. , , UI- , authorization, , . :

  • auth_key bounds it to account, SMS β€” authorization
  • MTProto session, session_id



    .
  • , authorization session_id



    instance β€”
  • , MTProto sessions auth_key β€” DC.
  • , DC β€” DC auth_key !
  • , , authorization (UI-), API auth.exportAuthorization



    DC auth.importAuthorization



    DC.
  • , MTProto sessions ( session_id



    ) DC, auth_key.
  • , Perfect Forward Secrecy. auth_key permanent key β€” per DC β€” auth.bindTempAuthKey



    temporary auth_key β€” , temp_auth_key per DC, MTProto sessions DC.




, salt ( future salts) auth_key .. shared MTProto sessions DC.

" TCP-"? , - β€” () TCP- , . HTTP, MTProto , , β€” , TCP-.







, . β€” ? β€” .







, auth_key



- Telegram. ...







Vasily, [19.06.18 20:05]

data_with_hash := SHA1(data) + data + (any random bytes); such that the length equal 255 bytes;

encrypted_data := RSA (data_with_hash, server_public_key); a 255-byte long number (big endian) is raised to the requisite power over the requisite modulus, and the result is stored as a 256-byte number.



- DH



DH

β€” proof of work , . DoS-. RSA- , , new_nonce



. , ?







Vasily, [20.06.18 00:26]

appid



DH



, , 4 .



-404, ?



: " -, DH", 404

? ? - ( ).











, -



32 .



, BE



Vadim Goncharov, [20.06.18 15:49]

- 404?



Vasily, [20.06.18 15:49]

!



Vadim Goncharov, [20.06.18 15:50]

, " "



Vasily, [20.06.18 15:50]





%)



error reporting



Vasily, [20.06.18 20:18]

, MD5.



The key fingerprint is computed as follows:

digest = md5(key + iv)
fingerprint = substr(digest, 0, 4) XOR substr(digest, 4, 4)
      
      







SHA1 sha2

, , auth_key



2048 - . ? , 1024 … . . TLS-, . , ! , , . .. "-", - ICQ, "-", SSH ( - gitlab/github). . " DC"? " "? , β€” , .







, "" . , ? ? :







Vasily, [21.06.18 17:53]

2 %)



,



Vasily, [21.06.18 18:02]

, ,

. , ? ( , ) β€” , :







278     static const char *goodPrime = "c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b";
279   if (!strcasecmp(prime, goodPrime)) {
      
      





, - , .







, . , .. , , AES.







The message key is defined as the 128 middle bits of the SHA256 of the message body (including session, message ID, etc.), including the padding bytes, prepended by 32 bytes taken from the authorization key.



Vasily, [22.06.18 14:08]

, ,



auth_key



. . … . Feel free to study the open source code.



Note that MTProto 2.0 requires from 12 to 1024 bytes of padding, still subject to the condition that the resulting message length be divisible by 16 bytes.



?



, 404

, , MAC . AES , IGE. , , FAQ… , , SHA- , β€” - silently ignore ( , ?).







, , . , Telegram Desktop. ( D877F783D5D3EF8C) , MTProto ( 1.0), .. , ( - auth_key



256 , msg_key



). , . , β€” . , , ?.. MAC , . MTProto , . Telegram Desktop user_data



β€” AES CTR.







Vasily, [21.06.18 01:27]

, , IGE: IGE was the first attempt at an "authenticating encryption mode," originally for Kerberos. It was a failed attempt (it does not provide integrity protection), and had to be removed. That was the beginning of a 20 year quest for an authenticating encryption mode that works, which recently culminated in modes like OCB and GCM.



:



The team behind Telegram, led by Nikolai Durov, consists of six ACM champions, half of them Ph.Ds in math. It took them about two years to roll out the current version of MTProto.



.



tls

, , . , , TL ? ? , , initConnection, ?







Vasily, [25.06.18 18:46]

Initializes connection and save information on the user's device and application.



app_id, device_model, system_version, app_version lang_code.



query



. Feel free to study the open source

invokeWithLayer , - ? , β€” , β€” , :







Vasily, [25.06.18 19:13]

, , invokewithlayer

initConnection , ? , , , , . ! ! , β€” , ...







Only a small portion of the API methods are available to unauthorized users:




, auth.sendCode



, , api_id api_hash, SMS . DC ( , ), DC. , IP- DC , help.getConfig



. - 5 , 2018 .







, . , IP-? , , MTProto? : " , ?". , - RSA-, .. . , , (, MTProto, , ).







, . . , , . ...







Vasily, [10.07.18 14:45]

https://core.telegram.org/method/help.getConfig

config#7dae33e0 [...] = Config;
help.getConfig#c4f9186b = Config;
      
      







https://core.telegram.org/api/datacenter

config#232d5905 [...] = Config;
help.getConfig#c4f9186b = Config;
      
      







,



tdesktop

, , , . . ? , , ? , β€” (, ).







… , - API, .. , - MTProto? :







Vasily, [28.06.18 02:04]

, e2e



Mtproto ,



, , mtproto

? PFS, (, Telegram Desktop ). API auth.bindTempAuthKey



, .. . β€” , , initConnection



.., . , DC, auth_key_id



, "" β€” , … , future salts, ?..







MTProto .







, msg_id, msg_seqno, ,



? "" , , API. , msg_key , . ( , , padding, ):









, β€” DC. ? , get_future_salts



, , , , "", () β€” . , , , new_session_created



β€” - , . .







. , MTProto ? , session_id



seq_no



. , TCP-, . , , , . β€” TCP- , seq_no



. β€” , , .







seq_no



? , . , :







Content-related Message



A message requiring an explicit acknowledgment. These include all the user and many service messages, virtually all with the exception of containers and acknowledgments.



Message Sequence Number (msg_seqno)



A 32-bit number equal to twice the number of β€œcontent-related” messages (those requiring acknowledgment, and in particular those that are not containers) created by the sender prior to this message and subsequently incremented by one if the current message is a content-related message. A container is always generated after its entire contents; therefore, its sequence number is greater than or equal to the sequence numbers of the messages contained in it.

1, 2?.. , " ACK, ", β€” , , , seq_no



! ? - , , , . . TCP , - , , TCP seq_no



, seq_no



β€” . MTProto seq_no



, TCP, msg_id



!







msg_id



, ? , . 64- , "- ", β€” Unix timestamp, , 32 . .. ( ). , - , . , β€” session_id



β€” : Under no circumstances can a message meant for one session be sent into a different session. , , β€” , , id . , .







, msg_id



...







RPC: , , . .



, , , " RPC-", . content-related ! , ! . msg_id



. β€” :







rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult;
      
      





, . , API, , β€” , , , , ? , , no workers, : TCP- β€” -, message_id



. , .







?.. ? RPC- msg_id



! " !"? , ? ,







msgs_ack#62d6b459 msg_ids:Vector long = MsgsAck;
      
      





. ! RpcResult, . , MsgsAck β€” , " ". RpcResult. .







, ! . . . , , . .







.







rpc_error#2144ca19 error_code:int error_message:string = RpcError;
      
      





, -, β€” ! . , , , . , β€” HTTP- ( , , ), ___. , PHONE_NUMBER_OCCUPIED FILE_PART__MISSING. , . , FLOOD_WAIT_3600



, , PHONE_MIGRATE_5



, 5- DC. , ? , , .







, , , , . . -, , / β€” RpcError



RpcResult



. ? ?.. , , RpcError



RpcResult



, ?.. , , .. req_msg_id



?..







. , , :







rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;
      
      





, , , ( , ), (: Telegram Desktop ).







:



, TL, MTProto Telegram , , soft skills , . , , .







, .







bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification;
bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification;
      
      





, MTProto, " β€” β€” " β€” . :







  1. , . - , .
  2. ? 16, 17, 18, 19, 20, 32, 33, 34, 35, 48, 64… , ?


:







The intention is that error_code values are grouped (error_code >> 4): for example, the codes 0x40 β€” 0x4f correspond to errors in container decomposition.

, -, , -, , ? ?.. , .







:









, msgs_state_info



TL ( , enum, ). . - , ?.. , - , , β€” , . .







, , , , . , . , ! , -, . , , , TL β€” () , , , .. .







. .



, ( ), β€” TCP ( , , ), MTProto β€” . , , .







β€” . , - β€” . ? . , - , , Telegram Desktop 4 , ( , , ; , , MTProto ).







? , , -, . , , TCP β€” RTT "" ( ) . , β€” .







, , ? TCP TCP β€” .







, , , , API? , , , . ? msg_id



, , β€” - (, , , β€” , - ). , , :







  1. .
  2. msg_id



    β€” ; .
  3. ) MsgsAck β€” , " ".

    ) , - , badmsg β€” " "

    ) , β€” , .
  4. RpcResult



    β€” ( ) β€” , .


, . , , msg_id



. , - , .







. , , , β€” , ? (, ).







? " " " , !" ( , , rationale , ), / β€” , . ?







A server usually acknowledges the receipt of a message from a client (normally, an RPC query) using an RPC response. If a response is a long time coming, a server may first send a receipt acknowledgment, and somewhat later, the RPC response itself.



A client normally acknowledges the receipt of a message from a server (usually, an RPC response) by adding an acknowledgment to the next RPC query if it is not transmitted too late (if it is generated, say, 60-120 seconds following the receipt of a message from the server). However, if for a long period of time there is no reason to send messages to the server or if there is a large number of unacknowledged messages from the server (say, over 16), the client transmits a stand-alone acknowledgment.

… : , , , .







:







Ping Messages (PING/PONG)

ping#7abe77ec ping_id:long = Pong;
      
      







A response is usually returned to the same connection:

pong#347773c5 msg_id:long ping_id:long = Pong;
      
      







These messages do not require acknowledgments. A pong is transmitted only in response to a ping while a ping can be initiated by either side.



Deferred Connection Closure + PING

ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;
      
      







Works like ping. In addition, after this is received, the server starts a timer which will close the current connection disconnect_delay seconds later unless it receives a new message of the same type which automatically resets all previous timers. If the client sends these pings once every 60 seconds, for example, it may set disconnect_delay equal to 75 seconds.

?! 60 , - , . 120 , , , . , β€” " , ", TCP_NODELAY, . , , β€” 200 . β€” , , 5 , "User is typing...". .







, . , TCP-. , 10 β€” , . 3 , β€” , ?..







. TCP-, , . , , . , SSH- , - , , β€” ( , ), . , , (, !), , , β€” .







/ IM , β€” -. "", . , Jabber ( 20 ) β€” , , , online ( ). , TCP_KEEPALIVE, , TCP, ( ), β€” , , , , (, ? Telegram Desktop Ubuntu 18.04 ).







, β€” , , .







Telegram? ! .. , , . β€” ping_delay_disconnect



, . , , . , , . , , , , ...







?



, Telegram/ ( ) .







, Telegram ? , , TCP-, , . β€” . , UDP-, ( β€” ). - , TCP , , ( ), " " β€” .







? , msg_id



, replay-, . , ( Updates, API ), :







  1. , TCP- , β€” , , , . id', " seq_no" β€” , TCP ( β€” seq ). , ?
  2. replay- , - nonce. , . uint32



    β€” , 16 , β€” ( ).
  3. msg_id



    β€” , -, id , -, id , . , seq_no



    .


, β€” API , . , , .







API ?



-! , , , , ( , , PUSH, - ).







, Perl! ( , , bless β€” , β€” ):







2019.10.24 12:00:51 $1 = {
  'cb' => 'TeleUpd::__ANON__',
  'out' => bless( {
    'filter' => bless( {}, 'Telegram::ChannelMessagesFilterEmpty' ),
    'channel' => bless( {
      'access_hash' => '-6698103710539760874',
      'channel_id' => '1380524958'
    }, 'Telegram::InputPeerChannel' ),
    'pts' => '158503',
    'flags' => 0,
    'limit' => 0
  }, 'Telegram::Updates::GetChannelDifference' ),
  'req_id' => '6751291954012037292'
};

2019.10.24 12:00:51 $1 = {
  'in' => bless( {
    'req_msg_id' => '6751291954012037292',
    'result' => bless( {
      'pts' => 158508,
      'flags' => 3,
      'final' => 1,
      'new_messages' => [],
      'users' => [],
      'chats' => [
        bless( {
          'title' => '',
          'username' => 'hoolinomics',
          'flags' => 8288,
          'id' => 1380524958,
          'access_hash' => '-6698103710539760874',
          'broadcast' => 1,
          'version' => 0,
          'photo' => bless( {
            'photo_small' => bless( {
              'volume_id' => 246933270,
              'file_reference' => '
              'secret' => '1854156056801727328',
              'local_id' => 228648,
              'dc_id' => 2
            }, 'Telegram::FileLocation' ),
            'photo_big' => bless( {
              'dc_id' => 2,
              'local_id' => 228650,
              'file_reference' => '
              'secret' => '1275570353387113110',
              'volume_id' => 246933270
            }, 'Telegram::FileLocation' )
          }, 'Telegram::ChatPhoto' ),
          'date' => 1531221081
        }, 'Telegram::Channel' )
      ],
      'timeout' => 300,
      'other_updates' => [
        bless( {
          'pts_count' => 0,
          'message' => bless( {
            'post' => 1,
            'id' => 852,
            'flags' => 50368,
            'views' => 8013,
            'entities' => [
              bless( {
                'length' => 20,
                'offset' => 0
              }, 'Telegram::MessageEntityBold' ),
              bless( {
                'length' => 18,
                'offset' => 480,
                'url' => 'https://alexeymarkov.livejournal.com/[url_].html'
              }, 'Telegram::MessageEntityTextUrl' )
            ],
            'reply_markup' => bless( {
              'rows' => [
                bless( {
                  'buttons' => [
                    bless( {
                      'text' => '???? 165',
                      'data' => 'send_reaction_0'
                    }, 'Telegram::KeyboardButtonCallback' ),
                    bless( {
                      'data' => 'send_reaction_1',
                      'text' => '???? 9'
                    }, 'Telegram::KeyboardButtonCallback' )
                  ]
                }, 'Telegram::KeyboardButtonRow' )
              ]
            }, 'Telegram::ReplyInlineMarkup' ),
            'message' => '    ! 
// [         ]
 .',
            'to_id' => bless( {
              'channel_id' => 1380524958
            }, 'Telegram::PeerChannel' ),
            'date' => 1571724559,
            'edit_date' => 1571907562
          }, 'Telegram::Message' ),
          'pts' => 158508
        }, 'Telegram::UpdateEditChannelMessage' ),
        bless( {
          'pts' => 158508,
          'message' => bless( {
            'edit_date' => 1571907589,
            'to_id' => bless( {
              'channel_id' => 1380524958
            }, 'Telegram::PeerChannel' ),
            'date' => 1571807301,
            'message' => '   Facebook  ?  ? -,   .  ,   ,     ,      .

    :   Facebook     . ,      ,     .      . -       .  ,             ,     -      .    .

,     :     Whatsapp,  Instagram.     ,    !

    .     . - -   ,    .

# #facebook # #',
            'reply_markup' => bless( {
              'rows' => [
                bless( {
                  'buttons' => [
                    bless( {
                      'data' => 'send_reaction_0',
                      'text' => '???? 452'
                    }, 'Telegram::KeyboardButtonCallback' ),
                    bless( {
                      'text' => '???? 21',
                      'data' => 'send_reaction_1'
                    }, 'Telegram::KeyboardButtonCallback' )
                  ]
                }, 'Telegram::KeyboardButtonRow' )
              ]
            }, 'Telegram::ReplyInlineMarkup' ),
            'entities' => [
              bless( {
                'length' => 199,
                'offset' => 0
              }, 'Telegram::MessageEntityBold' ),
              bless( {
                'length' => 8,
                'offset' => 919
              }, 'Telegram::MessageEntityHashtag' ),
              bless( {
                'offset' => 928,
                'length' => 9
              }, 'Telegram::MessageEntityHashtag' ),
              bless( {
                'length' => 6,
                'offset' => 938
              }, 'Telegram::MessageEntityHashtag' ),
              bless( {
                'length' => 11,
                'offset' => 945
              }, 'Telegram::MessageEntityHashtag' )
            ],
            'views' => 6964,
            'flags' => 50368,
            'id' => 854,
            'post' => 1
          }, 'Telegram::Message' ),
          'pts_count' => 0
        }, 'Telegram::UpdateEditChannelMessage' ),
        bless( {
          'message' => bless( {
            'reply_markup' => bless( {
              'rows' => [
                bless( {
                  'buttons' => [
                    bless( {
                      'data' => 'send_reaction_0',
                      'text' => '???? 213'
                    }, 'Telegram::KeyboardButtonCallback' ),
                    bless( {
                      'data' => 'send_reaction_1',
                      'text' => '???? 8'
                    }, 'Telegram::KeyboardButtonCallback' )
                  ]
                }, 'Telegram::KeyboardButtonRow' )
              ]
            }, 'Telegram::ReplyInlineMarkup' ),
            'views' => 2940,
            'entities' => [
              bless( {
                'length' => 609,
                'offset' => 348
              }, 'Telegram::MessageEntityItalic' )
            ],
            'flags' => 50368,
            'post' => 1,
            'id' => 857,
            'edit_date' => 1571907636,
            'date' => 1571902479,
            'to_id' => bless( {
              'channel_id' => 1380524958
            }, 'Telegram::PeerChannel' ),
            'message' => '  1   .  10 (, 1-)  :
// [         ]

  ,    1 ,  ... , .'
          }, 'Telegram::Message' ),
          'pts_count' => 0,
          'pts' => 158508
        }, 'Telegram::UpdateEditChannelMessage' ),
        bless( {
          'pts' => 158508,
          'pts_count' => 0,
          'message' => bless( {
            'message' => ', , ,    1?

// [         ]
# #it #',
            'edit_date' => 1571907650,
            'date' => 1571893707,
            'to_id' => bless( {
              'channel_id' => 1380524958
            }, 'Telegram::PeerChannel' ),
            'flags' => 50368,
            'post' => 1,
            'id' => 856,
            'reply_markup' => bless( {
              'rows' => [
                bless( {
                  'buttons' => [
                    bless( {
                      'data' => 'send_reaction_0',
                      'text' => '???? 360'
                    }, 'Telegram::KeyboardButtonCallback' ),
                    bless( {
                      'data' => 'send_reaction_1',
                      'text' => '???? 32'
                    }, 'Telegram::KeyboardButtonCallback' )
                  ]
                }, 'Telegram::KeyboardButtonRow' )
              ]
            }, 'Telegram::ReplyInlineMarkup' ),
            'views' => 4416,
            'entities' => [
              bless( {
                'offset' => 0,
                'length' => 64
              }, 'Telegram::MessageEntityBold' ),
              bless( {
                'offset' => 1551,
                'length' => 5
              }, 'Telegram::MessageEntityHashtag' ),
              bless( {
                'length' => 3,
                'offset' => 1557
              }, 'Telegram::MessageEntityHashtag' ),
              bless( {
                'offset' => 1561,
                'length' => 10
              }, 'Telegram::MessageEntityHashtag' )
            ]
          }, 'Telegram::Message' )
        }, 'Telegram::UpdateEditChannelMessage' )
      ]
    }, 'Telegram::Updates::ChannelDifference' )
  }, 'MTProto::RpcResult' )
};

2019.10.24 12:00:51 $1 = {
  'in' => bless( {
    'update' => bless( {
      'user_id' => 2507460,
      'status' => bless( {
        'was_online' => 1571907651
      }, 'Telegram::UserStatusOffline' )
    }, 'Telegram::UpdateUserStatus' ),
    'date' => 1571907650
  }, 'Telegram::UpdateShort' )
};

2019.10.24 12:05:46 $1 = {
  'in' => bless( {
    'chats' => [],
    'date' => 1571907946,
    'seq' => 0,
    'updates' => [
      bless( {
        'max_id' => 141719,
        'channel_id' => 1295963795
      }, 'Telegram::UpdateReadChannelInbox' )
    ],
    'users' => []
  }, 'Telegram::Updates' )
};

2019.10.24 13:01:23 $1 = {
  'in' => bless( {
    'server_salt' => '4914425622822907323',
    'unique_id' => '5297282355827493819',
    'first_msg_id' => '6751307555044380692'
  }, 'MTProto::NewSessionCreated' )
};

2019.10.24 13:24:21 $1 = {
  'in' => bless( {
    'chats' => [
      bless( {
        'username' => 'freebsd_ru',
        'version' => 0,
        'flags' => 5440,
        'title' => 'freebsd_ru',
        'min' => 1,
        'photo' => bless( {
          'photo_small' => bless( {
            'local_id' => 328733,
            'volume_id' => 235140688,
            'dc_id' => 2,
            'file_reference' => '
            'secret' => '4426006807282303416'
          }, 'Telegram::FileLocation' ),
          'photo_big' => bless( {
            'dc_id' => 2,
            'file_reference' => '
            'volume_id' => 235140688,
            'local_id' => 328735,
            'secret' => '71251192991540083'
          }, 'Telegram::FileLocation' )
        }, 'Telegram::ChatPhoto' ),
        'date' => 1461248502,
        'id' => 1038300508,
        'democracy' => 1,
        'megagroup' => 1
      }, 'Telegram::Channel' )
    ],
    'users' => [
      bless( {
        'last_name' => 'Panov',
        'flags' => 1048646,
        'min' => 1,
        'id' => 82234609,
        'status' => bless( {}, 'Telegram::UserStatusRecently' ),
        'first_name' => 'Dima'
      }, 'Telegram::User' )
    ],
    'seq' => 0,
    'date' => 1571912647,
    'updates' => [
      bless( {
        'pts' => 137596,
        'message' => bless( {
          'flags' => 256,
          'message' => '     ??',
          'to_id' => bless( {
            'channel_id' => 1038300508
          }, 'Telegram::PeerChannel' ),
          'id' => 119634,
          'date' => 1571912647,
          'from_id' => 82234609
        }, 'Telegram::Message' ),
        'pts_count' => 1
      }, 'Telegram::UpdateNewChannelMessage' )
    ]
  }, 'Telegram::Updates' )
};
      
      





, β€” , !







Oh, wai~~… ? - … , Web API JSON, ?..







… , ?.. β€” , Web- ?.. JSON HTTPS ?! ? ?







, TL+MTProto, . , HTTP, "-", , - TLS ?







. , JSON, , . MsgPack , , , CBOR β€” , , RFC 7049. , , , :









, TL CBOR . CBOR - :







cborlen=1039673 tl_len=1095092
      
      





, : , , .







. RTT ( ) β€” MTProto, β€” , , etc. TLS? :







PFS TLS TLS session tickets (RFC 5077) . , ( session ticket). , session ticket, , . ticket (session ticket key), frontend-, SSL .[10]. , session ticket PFS , , (OpenSSL, nginx, Apache ; , ).

RTT , ClientHello ServerHello, Finished . , Web, , , - , Web- β€” . , , .







- ? .







To be continued!



, β€” , , , .. , , , .







/ . , :









! Stay tuned!








All Articles