Skip to main content

EncryptedSession

Struct EncryptedSession 

Source
pub struct EncryptedSession {
    pub salt: i64,
    pub time_offset: i32,
    /* private fields */
}
Expand description

MTProto 2.0 encrypted session state.

Fields§

§salt: i64

Current server salt to include in outgoing messages.

§time_offset: i32

Clock skew in seconds vs. server.

Implementations§

Source§

impl EncryptedSession

Source

pub fn new(auth_key: [u8; 256], first_salt: i64, time_offset: i32) -> Self

Create a new encrypted session from the output of authentication::finish.

seen_msg_ids should be the persistent ring owned by the DcConnection (or any other owner that outlives individual sessions). Pass new_seen_msg_ids() for the very first connection on a slot.

Source

pub fn with_seen( auth_key: [u8; 256], first_salt: i64, time_offset: i32, seen_msg_ids: SeenMsgIds, ) -> Self

Like new but reuses an existing seen-msg_id ring (reconnect path).

Source

pub fn seen_msg_ids(&self) -> SeenMsgIds

Return a clone of the shared seen-msg_id ring for passing to a replacement session on reconnect.

Source

pub fn next_seq_no_ncr(&self) -> i32

Return the current even seq_no WITHOUT advancing the counter.

Service messages (MsgsAck, containers, etc.) MUST use an even seqno per the MTProto spec so the server does not expect a reply.

Source

pub fn correct_seq_no(&mut self, _code: u32)

Handle bad_msg_notification codes 32/33 (seq_no too low / too high).

The previous implementation used magic offsets (+64 / -16) that have no basis in the MTProto spec. These caused ping-pong loops: +64 triggered code 33 (now too high), -16 triggered code 32 (now too low), repeating until the connection was dropped, which then hit the session_id reset bug.

The spec-correct recovery is a full session reset (new session_id, seq_no=0). This is what TDesktop does. The caller (dc_pool::rpc_call) must then resend using the new session context.

Source

pub fn undo_seq_no(&mut self)

Undo the last next_seq_no increment.

Called before retrying a request after bad_server_salt so the resent message uses the same seq_no slot rather than advancing the counter a second time (which would produce seq_no too high → bad_msg_notification code 33 → server closes TCP → early eof).

Source

pub fn correct_time_offset(&mut self, server_msg_id: i64)

Re-derive the clock skew from a server-provided msg_id.

Called on bad_msg_notification error codes 16 (msg_id too low) and 17 (msg_id too high) so clock drift is corrected at any point in the session, not only at connect time.

Source

pub fn alloc_msg_seqno(&mut self, content_related: bool) -> (i64, i32)

Allocate a fresh (msg_id, seqno) pair for an inner container message WITHOUT encrypting anything.

content_related = true → odd seqno, advances counter (regular RPCs) content_related = false → even seqno, no advance (MsgsAck, container)

Source

pub fn pack_body_with_msg_id( &mut self, body: &[u8], content_related: bool, ) -> (Vec<u8>, i64)

Encrypt a pre-serialized TL body into a wire-ready MTProto frame.

content_related controls whether the seqno is odd (content, advances the counter) or even (service, no advance).

Returns (encrypted_wire_bytes, msg_id). Used for (bad_msg re-send) and (container inner messages).

Source

pub fn pack_container(&mut self, container_body: &[u8]) -> (Vec<u8>, i64)

Encrypt a pre-built msg_container body (the container itself is a non-content-related message with an even seqno).

Returns (encrypted_wire_bytes, container_msg_id). The container_msg_id is needed so callers can map it back to inner requests when a bad_msg_notification or bad_server_salt arrives for the container rather than the individual inner message.

Source

pub fn pack_body_at_msg_id(&mut self, body: &[u8], msg_id: i64) -> Vec<u8>

Encrypt body using a caller-supplied msg_id instead of generating one.

Required by auth.bindTempAuthKey, which must use the same msg_id in both the outer MTProto envelope and the inner bind_auth_key_inner.

Source

pub fn pack_serializable<S: Serializable>(&mut self, call: &S) -> Vec<u8>

Serialize and encrypt a TL function into a wire-ready byte vector.

Source

pub fn pack_serializable_with_msg_id<S: Serializable>( &mut self, call: &S, ) -> (Vec<u8>, i64)

Like pack_serializable but also returns the msg_id.

Source

pub fn pack_with_msg_id<R: RemoteCall>(&mut self, call: &R) -> (Vec<u8>, i64)

Like [pack] but also returns the msg_id allocated for this message.

Source

pub fn pack<R: RemoteCall>(&mut self, call: &R) -> Vec<u8>

Encrypt and frame a RemoteCall into a ready-to-send MTProto message.

Source

pub fn unpack(&self, frame: &mut [u8]) -> Result<DecryptedMessage, DecryptError>

Decrypt an encrypted server frame.

Source

pub fn auth_key_bytes(&self) -> [u8; 256]

Return the auth_key bytes (for persistence).

Source

pub fn session_id(&self) -> i64

Return the current session_id.

Source

pub fn reset_session(&mut self)

Reset session state: new random session_id, zeroed seq_no and last_msg_id.

Use this for genuine new-session creation (e.g. reconnect after auth loss, or bad_msg_notification codes 32/33 seq_no desync). For new_session_created server notifications received mid-session, use reset_seq_no_only() which preserves the client session_id so that in-flight server responses still decrypt correctly.

Source

pub fn reset_seq_no_only(&mut self)

Reset only the sequence counter and last_msg_id, keeping session_id intact.

§Protocol basis

When the server sends new_session_created, it has created fresh server-side state for the client’s existing session_id. The client must reset seq_no to 0 (server expectation is now 0) but MUST NOT change session_id. Doing so would cause the server’s pending response (encrypted with the old session_id) to fail decryption with SessionMismatch.

Replaces the previous reset_session() call in the new_session_created handler.

Source§

impl EncryptedSession

Source

pub fn decrypt_frame_dedup( auth_key: &[u8; 256], session_id: i64, frame: &mut [u8], seen: &SeenMsgIds, ) -> Result<DecryptedMessage, DecryptError>

Like [decrypt_frame] but also performs seen-msg_id deduplication using the supplied ring. Pass &self.inner.seen_msg_ids from the client.

Hard-codes time_offset = 0. On systems where the local clock differs from the server by more than 30 seconds, valid server messages are rejected with MsgIdTimeWindow. Prefer decrypt_frame_dedup_with_offset when the session’s clock skew is known.

Source

pub fn decrypt_frame_dedup_with_offset( auth_key: &[u8; 256], session_id: i64, frame: &mut [u8], seen: &SeenMsgIds, time_offset: i32, ) -> Result<DecryptedMessage, DecryptError>

Like [decrypt_frame_dedup] but applies the time-window check with the given time_offset (seconds, server_time − local_time).

Callers that track the session’s clock skew (from correct_time_offset) should use this variant to avoid falsely rejecting valid server frames on clock-skewed systems. Pass enc.time_offset() from the owning EncryptedSession.

Source

pub fn decrypt_frame( auth_key: &[u8; 256], session_id: i64, frame: &mut [u8], ) -> Result<DecryptedMessage, DecryptError>

Decrypt a frame using explicit key + session_id: no mutable state needed. Used by the split-reader task so it can decrypt without locking the writer. time_offset is the session’s current clock skew (seconds); pass 0 if unknown.

Source

pub fn decrypt_frame_with_offset( auth_key: &[u8; 256], session_id: i64, frame: &mut [u8], time_offset: i32, ) -> Result<DecryptedMessage, DecryptError>

Like [decrypt_frame] but applies the time-window check with the given time_offset (seconds, server_time − local_time).

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.