Telegram Passport Encryption Details

Telegram Passport data is stored encrypred End-to-End which means that the Telegram server does not have access to the data and only functions as a storage for encrypted data it can't decipher. Encryption and decryption are handled exclusively by the Telegram clients, which are open source.

Overview

To encrypt each particular element of Telegram Passport, the client generates a random secret. The secret is a 32-byte number with the modulo 255 sum of bytes equal to 239. This secret is in turn encrypted with the passport_secret that is generated when the user creates their Telegram Passport. passport_secret is encrypted with the user's password and is stored encrypted in the Telegram Cloud.

Passport Secret

When Telegram Passport is first used, the client generates a passport_secret (a 32-byte number with the modulo 255 sum of bytes equal to 239), using a part of server-generated random passport_secret_random as an additional source of entropy for OpenSSL. Then passport_secret is encrypted using the following scheme:

  • A fingerprint of the secret is calculated ( passport_secret_fingerprint ):

    passport_secret_fingerprint = long( slice( SHA256( passport_secret ), 0, 8 ) )
  • The encryption key secret_key is calculated using 8 bytes of the server salt server_passport_salt and 32 bytes of the client salt client_passport_salt. To make the password hashes stored on the server more resilient to brute-force attacks while maintaining practical speeds on the range of devices popular among Telegram users, PBKDF2-HMAC-SHA512 with 100000 iterations is used:

    client_passport_salt = random_bytes(32)
    passport_secret_salt = server_passport_salt + client_passport_salt
    password_hash = PBKDF2( password, passport_secret_salt, HMACSHA512, 100000)
    secret_key = slice( password_hash, 0, 32 )
    iv = slice( password_hash, 32, 16 )
  • The passport_secret generated previously is encrypted using AES256-CBC with the key secret_key and iv

  • The encrypted passport_secret is stored on the server together with the passport_secret_salt and the fingerprint of the secret passport_secret_fingerprint.

Subsequently, the client receives the encrtypted passport_secret from the server and decrypts it after the user enters their password.

In case the password is changed, the client re-encrypted the passport_secret using the new password. If the password is disabled, all Telegram Passport data is lost.

Data and File Encryption

To encrypt Telegram Passport data, the client generates a data_secret (a 32-byte number with the modulo 255 sum of bytes equal to 239). The the data is encrypted according to the following scheme:

  • Data is padded to a length that is divisible by 16 bytes. To achieve this, 32 to 255 bytes are added at the beginning, where the first byte always holds the number of added bytes and the rest are random.
  • We calculate the hash from this data data_hash:

    data_hash = SHA256( data_bytes )
  • The encrytion key data_key is calculated:

    data_secret_hash = SHA512( data_secret + data_hash )
    data_key = slice( data_secret_hash, 0, 32 )
    iv = slice( data_secret_hash, 32, 16 )
  • Data is encrypted using AES256-CBC with the key data_key and iv.

  • secret_key, the key for encrypting the secret, is calculated:

    secret_hash = SHA512( passport_secret + data_hash )
    secret_key = slice( secret_hash, 0, 32 )
    iv = slice( secret_hash, 32, 16 )
  • data_secret is encrypted using AES256-CBC with the key secret_key and iv

  • Encrypted data together with the encrypted data_secret and data_hash are saved on the server.

Passport Credentials

When a service requests data, it passes a nonce to the client. The nonce is a cryptographically secure unique identifier which allows the service to identify a request when receiving data as well as confirm the integrity of the data. The Telegram server doesn't have access to this nonce.

Once the user authorizes the Telegram Passport data transfer, the client forms the credentials. Credentials contain the data_hash and data_secret from each element of Telegram Passport to which the user has allowed access. In addition to this, the credentials will always contain the nonce that the client received from the service at the initiation of the request.

Credentials are then passed to the service through the Bot API in encrypted form. To encrypt the credentials, the client generates a credentials_secret (a 32-byte number with the modulo 255 sum of bytes equal to 239). Then the credentials are encrypted according to the following scheme:

  • Credentials are padded to a length which is divisible by 16 bytes. To achieve this, 32 to 255 bytes are added at the beginning, where the first byte always holds the number of added bytes and the rest are random.
  • A hash of the padded credentials credentials_hash is calculated:

    credentials_hash = SHA256( credentials )
  • The encryption key credentials_key is calculated:

    credentials_secret_hash = SHA512( credentials_secret + credentials_hash )
    credentials_key = slice( credentials_secret_hash, 0, 32 )
    iv = slice( credentials_secret_hash, 32, 16 )
  • Credentials are encrypted using AES256-CBC with the key credentials_key and iv.

  • credentials_secret is encrypted with the public RSA-key of the service with OPENSSL_PKCS1_OAEP_PADDING.
  • The encrypted credentials are passed to the service via the Bot API together with the encrypred credentials_secret and credentials_hash. Along with the credentials, the service receives from the Telegram Cloud the data it requested in encrypted form. See PassportData.

Then the service decrypts the data as described here.