telegram-crawler/data/web/blogfork.telegram.org/api/end-to-end/seq_no.html
2023-10-22 15:31:15 +00:00

176 lines
15 KiB
HTML

<!DOCTYPE html>
<html class="">
<head>
<meta charset="utf-8">
<title>Sequence numbers in Secret Chats</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="description" content="It is necessary to interpret all messages in their original order to protect against reordering, reflection, replay, omission…">
<meta property="og:title" content="Sequence numbers in Secret Chats">
<meta property="og:image" content="">
<meta property="og:description" content="It is necessary to interpret all messages in their original order to protect against reordering, reflection, replay, omission…">
<link rel="icon" type="image/svg+xml" href="/img/website_icon.svg?4">
<link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png">
<link rel="alternate icon" href="/img/favicon.ico" type="image/x-icon" />
<link href="/css/bootstrap.min.css?3" rel="stylesheet">
<link href="/css/telegram.css?236" rel="stylesheet" media="screen">
<style>
</style>
</head>
<body class="preload">
<div class="dev_page_wrap">
<div class="dev_page_head navbar navbar-static-top navbar-tg">
<div class="navbar-inner">
<div class="container clearfix">
<ul class="nav navbar-nav navbar-right hidden-xs"><li class="navbar-twitter"><a href="https://twitter.com/telegram" target="_blank" data-track="Follow/Twitter" onclick="trackDlClick(this, event)"><i class="icon icon-twitter"></i><span> Twitter</span></a></li></ul>
<ul class="nav navbar-nav">
<li><a href="//telegram.org/">Home</a></li>
<li class="hidden-xs"><a href="//telegram.org/faq">FAQ</a></li>
<li class="hidden-xs"><a href="//telegram.org/apps">Apps</a></li>
<li class="active"><a href="/api">API</a></li>
<li class=""><a href="/mtproto">Protocol</a></li>
<li class=""><a href="/schema">Schema</a></li>
</ul>
</div>
</div>
</div>
<div class="container clearfix">
<div class="dev_page">
<div id="dev_page_content_wrap" class=" ">
<div class="dev_page_bread_crumbs"><ul class="breadcrumb clearfix"><li><a href="/api" >API</a></li><i class="icon icon-breadcrumb-divider"></i><li><a href="/api/end-to-end" >Secret Chats</a></li><i class="icon icon-breadcrumb-divider"></i><li><a href="/api/end-to-end%2Fseq_no" >Sequence numbers in Secret Chats</a></li></ul></div>
<h1 id="dev_page_title">Sequence numbers in Secret Chats</h1>
<div id="dev_page_content"><p>It is necessary to interpret <strong>all</strong> messages in their original order to protect against reordering, reflection, replay, omission and other manipulations (<a href="/constructor/decryptedMessageActionResend">decryptedMessageActionResend</a> messages are the only exception to this rule, see <a href="#avoiding-concurrent-gaps">avoiding concurrent gaps</a>). Secret chats support a special mechanism for handling <strong>seq_no</strong> counters independently from the server. Note that any <em>service messages</em> in secret chats must also increment the <strong>seq_no</strong>.</p>
<p>All Secret Chats messages in clients using Layer 17 or higher are wrapped in <a href="/constructor/decryptedMessageLayer">decryptedMessageLayer</a> and have <strong>seq_no</strong> (sequence number) counters attached to them. The <strong>seq_no</strong> counters in their raw form are initialized with <strong>(out_seq_no, in_seq_no) := (0,0)</strong>, and incremented strictly by 1 after any message (service or not) is sent/received and processed. They must be protected from mirroring before being sent to the remote client by transformation according to formula <strong>2*raw_seq_no+x</strong>, where <strong>x</strong> is 0 or 1, determined by the following rule:</p>
<table class="table">
<tbody>
<tr>
<td><strong>in_seq_no</strong></td>
<td><strong>out_seq_no</strong></td>
</tr>
<tr>
<td>secret chat initiated by sender</td>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>secret chat initiated by recipient</td>
<td>1</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>In this way the least significant bit of each <strong>seq_no</strong> field included in the message is different for incoming and outgoing messages. This is done to prevent a possible attacker from mirroring the messages. If any of the received <strong>in_seq_no</strong> or <strong>out_seq_no</strong> are not consistent in terms of parity (see table above), the client is required to immediately abort the secret chat.</p>
<blockquote>
<p>E.g., the first message the local client sends to any secret chat will have <strong>out_seq_no</strong> of <strong>0+x_out</strong>, the second one will have <strong>out_seq_no</strong> of <strong>2*1+x_out</strong>, and so on, where <strong>x_out</strong> is 0 if the chat was initiated by the remote client, 1 otherwise; similarly for the received messages, but there <strong>x_in</strong> is used instead of <strong>x_out</strong> and is equal to 0 if the chat was initiated by the local client, 1 otherwise. </p>
</blockquote>
<p>Raw sequence numbers will be used in the remaining part of this text, unless otherwise specified.</p>
<h4><a class="anchor" href="#preventing-gaps" id="preventing-gaps" name="preventing-gaps"><i class="anchor-icon"></i></a>Preventing gaps</h4>
<p>Your client must ensure that all outgoing secret chat messages are queued on the server in the correct order. This is achieved by correctly placing them into the <a href="/method/invokeAfterMsgs">invokeAfterMsgs</a> chain. Failure to do this may result in gaps on the remote client, which may in turn lead to aborted secret chats. The local client must maintain the correct sequence of <strong>in_seq_no</strong> for the remote client. To achieve this, assign <strong>in_seq_no</strong> and <strong>out_seq_no</strong> to each message at the <em>exact</em> moment when the message is created, and never change them in the future.</p>
<h2><a class="anchor" href="#security-checks" id="security-checks" name="security-checks"><i class="anchor-icon"></i></a>Security checks</h2>
<h4><a class="anchor" href="#checking-out-seq-no" id="checking-out-seq-no" name="checking-out-seq-no"><i class="anchor-icon"></i></a>Checking out_seq_no</h4>
<p>Your client must check that it has received <em>each</em> message with the sequence number <strong>out_seq_no</strong> starting from 0 to some current point <strong>C</strong>. It should then expect the next message to have the sequence number <strong>out_seq_no=C+1</strong>. If the <strong>out_seq_no</strong> in the received message does not match this, the following needs to be done:</p>
<ul>
<li>If the received <strong>out_seq_no&lt;=C</strong>, the local client must drop the message (repeated message). The client should not check the contents of the message because the original message could have been deleted (see <a href="#deleting-unacknowledged-messages">Deleting unacknowledged messages</a>).</li>
<li>If the received <strong>out_seq_no&gt;C+1</strong>, it most likely means that the server left out some messages due to a technical failure or due to the messages becoming obsolete. A temporary solution to this is to simply abort the secret chat. But since this may cause some existing older secret chats to be aborted, it is strongly recommended for the client to properly handle such <strong>seq_no</strong> gaps. Note that <strong>in_seq_no</strong> is not increased upon receipt of such a message; it is advanced only after all preceding gaps are filled.</li>
</ul>
<h4><a class="anchor" href="#proper-handling-of-gaps" id="proper-handling-of-gaps" name="proper-handling-of-gaps"><i class="anchor-icon"></i></a>Proper handling of gaps</h4>
<p>In order to correctly handle incoming messages after a hole has been identified (when received <strong>out_seq_no&gt;C+1</strong>), it is necessary to put received messages with the wrong <strong>seq_no</strong> into a "waiting queue" on the local client, and to re-request the missing messages using the special constructor <a href="/constructor/decryptedMessageActionResend">decryptedMessageActionResend</a> <code>start_seq_no:<a href='/type/int'>int</a> end_seq_no:<a href='/type/int'>int</a> = <a href='/type/DecryptedMessageAction'>DecryptedMessageAction</a>;</code>. The sequence numbers used in this constructor must be ready for interpretation by the remote client and therefore <em>cannot</em> be in their raw form: you can easily get the necessary <strong>start_seq_no</strong> by adding 2 to the <strong>out_seq_no</strong> of the last message before the hole and the <strong>end_seq_no</strong> by subtracting 2 from the <strong>out_seq_no</strong> of the received message with the wrong sequence number.</p>
<p>Each hole normally requires only one request to resend messages — if the remote client keeps sending out of sync messages, they should be put into the queue without sending a new request. Having received the missing messages, the local client must first interpret these messages in the right order by their <strong>seq_no</strong>. Once this is done, the client can proceed to interpret messages from the queue (again, in the right <strong>seq_no</strong> order).</p>
<p>Special cases:</p>
<ul>
<li>Note that having <em>two</em> gaps simultaneously is very rare (provided that the remote client and server are operating normally) and it is acceptable to abort the secret chat in this situation.</li>
<li>If a local client receives <a href="/constructor/decryptedMessageActionResend">decryptedMessageActionResend</a> but is unable to satisfy the request, it must abort the secret chat.</li>
</ul>
<h4><a class="anchor" href="#avoiding-concurrent-gaps" id="avoiding-concurrent-gaps" name="avoiding-concurrent-gaps"><i class="anchor-icon"></i></a>Avoiding concurrent gaps</h4>
<p>In order to avoid getting stuck with concurrent gaps on both sides, <a href="/constructor/decryptedMessageActionResend">decryptedMessageActionResend</a> must always be interpreted <em>immediately upon receipt</em> in all cases, even if its <strong>out_seq_no&gt;=C+1</strong>. Note that each <a href="/constructor/decryptedMessageActionResend">decryptedMessageActionResend</a> must only be handled once, it must not be interpreted again when we interpret messages in the queue.</p>
<h4><a class="anchor" href="#checking-and-handling-in-seq-no" id="checking-and-handling-in-seq-no" name="checking-and-handling-in-seq-no"><i class="anchor-icon"></i></a>Checking and handling in_seq_no</h4>
<p><strong>in_seq_no</strong> of all received messages must be <em>valid</em>. To ensure this, perform the following checks:</p>
<ul>
<li><strong>in_seq_no</strong> must form a non-decreasing sequence of non-negative integer numbers.</li>
<li><strong>in_seq_no</strong> must be valid at the moment of receiving the message, that is, if <strong>D</strong> is the <strong>out_seq_no</strong> of last message we sent, the received <strong>in_seq_no</strong> should not be greater than <strong>D + 1</strong>. This also allows us to insert the received message into its correct place in the secret chat. For example, imagine that the local client has sent 5 secret chat messages, and then receives a secret chat message with the text "Yes" and <strong>in_seq_no=2</strong>. In this situation the local client <em>must</em> place that message after the second message it sent. This makes manipulations with delayed messages impossible.</li>
</ul>
<p>If <code>in_seq_no</code> contradicts these criteria, the local client is required to immediately abort the secret chat. This could happen only in case of malicious or buggy behaviour on either server or remote client side.</p>
<h4><a class="anchor" href="#deleting-unacknowledged-messages" id="deleting-unacknowledged-messages" name="deleting-unacknowledged-messages"><i class="anchor-icon"></i></a>Deleting unacknowledged messages</h4>
<p>In case the user on the local client has deleted a message <em>before</em> the server (or the remote client, if <a href="/constructor/decryptedMessageActionResend">decryptedMessageActionResend</a> is handled correctly) could acknowledge the message, for security reasons, you must:</p>
<ul>
<li>securely destroy the contents of the message (as in case of any other deleted Secret Chat message);</li>
<li>change the local copy of the original message to <code>decryptedMessageActionDeleteMessages</code> with <strong>random_id</strong> equal to its own <strong>random_id</strong>;</li>
<li>create a new outgoing message deleting the original message.</li>
</ul>
<p>This must be done because your client doesn't know whether the remote client really received the message or not. In the case the message was already received, it will be deleted by the second message; otherwise it must arrive as a "self-delete" message to maintain the correct sequence of seq_no.</p></div>
</div>
</div>
</div>
<div class="footer_wrap">
<div class="footer_columns_wrap footer_desktop">
<div class="footer_column footer_column_telegram">
<h5>Telegram</h5>
<div class="footer_telegram_description"></div>
Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed.
</div>
<div class="footer_column">
<h5><a href="//telegram.org/faq">About</a></h5>
<ul>
<li><a href="//telegram.org/faq">FAQ</a></li>
<li><a href="//telegram.org/privacy">Privacy</a></li>
<li><a href="//telegram.org/press">Press</a></li>
</ul>
</div>
<div class="footer_column">
<h5><a href="//telegram.org/apps#mobile-apps">Mobile Apps</a></h5>
<ul>
<li><a href="//telegram.org/dl/ios">iPhone/iPad</a></li>
<li><a href="//telegram.org/android">Android</a></li>
<li><a href="//telegram.org/dl/web">Mobile Web</a></li>
</ul>
</div>
<div class="footer_column">
<h5><a href="//telegram.org/apps#desktop-apps">Desktop Apps</a></h5>
<ul>
<li><a href="//desktop.telegram.org/">PC/Mac/Linux</a></li>
<li><a href="//macos.telegram.org/">macOS</a></li>
<li><a href="//telegram.org/dl/web">Web-browser</a></li>
</ul>
</div>
<div class="footer_column footer_column_platform">
<h5><a href="/">Platform</a></h5>
<ul>
<li><a href="/api">API</a></li>
<li><a href="//translations.telegram.org/">Translations</a></li>
<li><a href="//instantview.telegram.org/">Instant View</a></li>
</ul>
</div>
</div>
<div class="footer_columns_wrap footer_mobile">
<div class="footer_column">
<h5><a href="//telegram.org/faq">About</a></h5>
</div>
<div class="footer_column">
<h5><a href="//telegram.org/blog">Blog</a></h5>
</div>
<div class="footer_column">
<h5><a href="//telegram.org/apps">Apps</a></h5>
</div>
<div class="footer_column">
<h5><a href="/">Platform</a></h5>
</div>
<div class="footer_column">
<h5><a href="//telegram.org/press">Press</a></h5>
</div>
</div>
</div>
</div>
<script src="/js/main.js?47"></script>
<script>backToTopInit("Go up");
removePreloadInit();
</script>
</body>
</html>