<metaproperty="description"content="Telegram Passport data is stored encrypted End-to-End which means that the Telegram server does not have access to the…">
<metaproperty="og:description"content="Telegram Passport data is stored encrypted End-to-End which means that the Telegram server does not have access to the…">
<p>Telegram Passport data is stored encrypted <strong>End-to-End</strong> 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 <strong>open source</strong>.</p>
<p>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 <ahref="#passport-secret"><em>passport_secret</em></a> that is generated when the user creates their Telegram Passport. <em>passport_secret</em> is encrypted with the user's password and is stored encrypted in the Telegram Cloud.</p>
<p>The passport secret is <em>one of</em> the secret parameters used to <ahref="#data-and-file-encryption">encrypt the data</a> uploaded by the user to the Telegram Cloud.</p>
<p>When first setting up Telegram Passport it must be created, encrypted and uploaded as described in <ahref="#passport-secret-encryption">Passport Secret Encryption</a>.</p>
<p>When using Telegram Passport normally, it must be downloaded and decrypted for use as described in <ahref="#passport-secret-decryption">Passport Secret Decryption</a>.</p>
<p>The passport secret must also be downloaded, re-encrypted and re-uploaded as described in <ahref="#passport-secret-encryption">Passport Secret Encryption</a> if a new, more secure encryption algorithm is defined in a newer version of Telegram or the 2FA password is updated.</p>
<p>When Telegram Passport is first used, the client generates a <em>passport_secret</em> (a 32-byte number with the modulo 255 sum of bytes equal to 239), using a part of server-generated random <em>secure_random</em> from <ahref="/constructor/account.password">account.password</a> as an additional source of entropy for OpenSSL (when re-encrypting the <em>passport_secret</em> with a more secure algorithm or after a 2FA password change, the previous <em>passport_secret</em> is used, instead).
Then <em>passport_secret</em> is then encrypted using the user's password and hashed using the schema and parameters specified in the <em>new_algo</em> field of <ahref="/constructor/account.password">account.password</a>.</p>
<p>The server should <strong>always</strong> return a <code>securePasswordKdfAlgoPBKDF2HMACSHA512iter100000</code> constructor in the <code>new_algo</code> field.
If <code>securePasswordKdfAlgoUnknown</code> is returned, the remotely stored secret is encrypted using a new algorithm, not supported by the current client: the user should update their app.</p>
<p>The other constructors may be used <strong>only</strong> when <ahref="#passport-secret-decryption"><strong>decrypting</strong> old passport parameters</a> generated by a legacy client; in this case, the passport secret should be re-encrypted and updated using <code>new_algo</code>.</p>
<ul>
<li>
<p>First of all, a fingerprint of the secret is calculated ( <em>passport_secret_fingerprint</em> ):</p>
<li>The following parameters are extracted/generated:<ul>
<li>8 bytes of the server salt <em>server_passport_salt</em> from the <em>salt</em> field of <ahref="/constructor/securePasswordKdfAlgoPBKDF2HMACSHA512iter100000">securePasswordKdfAlgoPBKDF2HMACSHA512iter100000</a> constructor</li>
<li>32 random bytes of the client salt <em>client_passport_salt</em>.</li>
</ul>
</li>
</ul>
<p>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: </p>
<p>The <em>encrypted_passport_secret</em> is stored on the server together with the <em>passport_secret_salt</em> and the fingerprint of the secret <em>passport_secret_fingerprint</em>:
<li>The <code>password</code> parameter is generated using the user's 2FA password as per <ahref="/api/srp#setting-a-new-2fa-password">updating the 2FA password</a>.</li>
<li>The <ahref="/constructor/account.passwordInputSettings">account.passwordInputSettings</a> constructor in <code>new_settings</code> should contain <em>only</em> the <code>new_secure_setting</code> parameter with the <ahref="/constructor/secureSecretSettings">secureSecretSettings</a>.</li>
</ul>
<p>The <ahref="/constructor/secureSecretSettings">secureSecretSettings</a> constructor is generated thusly:</p>
<ul>
<li><code>secure_algo</code> is set to the <code>new_algo</code> field of <ahref="/constructor/account.password">account.password</a>, used to generate the encrypted passport secret: <code>salt</code> is substituted with <code>passport_secret_salt</code></li>
<li><code>secure_secret</code> is set to the new <code>encrypted_passport_secret</code></li>
<li><code>secure_secret_id</code> is set to the new <code>passport_secret_fingerprint</code></li>
</ul>
</li>
</ul>
<p>Subsequently, <ahref="#passport-secret-decryption">the client receives the encrypted <em>passport_secret</em> from the server and decrypts it after the user enters their password »</a>.</p>
<p>In case the password is changed or a more secure algorithm is introduced in an update of the API, the client re-encrypts the <em>passport_secret</em> using the new password.
If the password is disabled, all Telegram Passport data is lost.</p>
<p>The client requests the user's <ahref="/api/srp">2FA password and generates the SRP paramaters</a> to be passed to <ahref="/method/account.getPasswordSettings">account.getPasswordSettings</a>.</p>
<p>If the password is correct, an <ahref="/constructor/account.passwordSettings">account.passwordSettings</a> constructor with <ahref="/constructor/secureSecretSettings">secureSecretSettings</a> is returned.</p>
<p><code>encrypted_passport_secret</code>, <code>passport_secret_fingerprint</code> parameters are extracted from the <ahref="/constructor/secureSecretSettings">secureSecretSettings</a> constructor:</p>
<p>Similar to <ahref="#passport-secret-encryption">passport secret encryption</a>, the following process is used to decrypt and verify the <code>encrypted_passport_secret</code>:</p>
<ul>
<li>
<p>The user's 2FA plaintext <code>password</code> is hashed using the specified algorithm.</p>
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: </p>
This mode can only be found in hashes generated by legacy clients: hashes generated with this mode <strong>must</strong> be re-encrypted and updated using <ahref="/constructor/securePasswordKdfAlgoPBKDF2HMACSHA512iter100000">securePasswordKdfAlgoPBKDF2HMACSHA512iter100000</a> as described in <ahref="#passport-secret-encryption">Passport Secret Encryption</a>.</p>
<p>The client must verify that <em>passport_secret_fingerprint</em> is indeed equal to <em>my_passport_secret_fingerprint</em>.</p>
</li>
</ul>
<p>The <em>passport_secret</em> can now be used to decrypt encrypted passport data stored on telegram servers:</p>
<h3><aclass="anchor"href="#data-and-file-encryption"id="data-and-file-encryption"name="data-and-file-encryption"><iclass="anchor-icon"></i></a>Data and File Encryption</h3>
<p>To encrypt Telegram Passport data, the client generates a <em>data_secret</em> (a 32-byte number with the modulo 255 sum of bytes equal to 239). The data is encrypted according to the following scheme:</p>
<p>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.</p>
</li>
<li>
<p>We calculate the hash from this data <em>data_hash</em>:</p>
<p><ahref="/method/account.saveSecureValue">account.saveSecureValue</a> must be used to save an encrypted passport <ahref="/constructor/secureValue">value</a> of a certain <ahref="/type/SecureValueType">type</a>.
The <code>secure_secret_id</code> parameter must be set to the <code>passport_secret_fingerprint</code> of the <code>passport_secret</code> used to encrypt the <code>data_secret</code>.</p>
<p>The <ahref="/constructor/inputSecureValue">inputSecureValue</a> constructor contains info about passport data of a certain <code>type</code>, identified by the chosen <ahref="/type/SecureValueType">SecureValueType</a> constructor.</p>
<p>Depending on the chosen type, encrypted data will have to be stored into a <ahref="/constructor/secureData">secureData</a> constructor, uploaded as an <ahref="/type/InputSecureFile">InputSecureFile</a>, or in the case of email addresses and phone numbers, verified and provided in a <ahref="/type/SecurePlainData">SecurePlainData</a> constructor.
For more info on each mode, and when each one should be used, read on.</p>
<li><code>data</code> is an encrypted and padded (<ahref="#encryption">see Encryption</a>) JSON-serialized object of one of the following types: <ahref="/passport#personaldetails">PersonalDetails</a>, <ahref="/passport#iddocumentdata">IdDocumentData</a>, <ahref="/passport#residentialaddress">ResidentialAddress</a>, depending on the chosen <ahref="/type/SecureValueType">type</a>.
Data must be in JSON format and not TL, as it has to be passed directly to the service using E2E encryption, without the bot API middleman to convert TL objects.</li>
<li><code>data_hash</code> is the <em>data_hash</em></li>
<li><code>secret</code> is the <em>encrypted_data_secret</em></li>
</ul>
<p>Data is an encrypted and padded JSON-serialized object of one of the specified JSON types, depending on the chosen <ahref="/type/SecureValueType">type</a>.</p>
<p>Files (JPG format, max. 10 MB) are encrypted and padded (<ahref="#encryption">see Encryption</a>), and then uploaded chunk by chunk as described in <ahref="/api/files">files »</a>, except that instead of generating an <ahref="/constructor/inputFile">inputFile</a>, an <ahref="/constructor/inputSecureFile">inputSecureFile</a> should be generated, instead.</p>
<ul>
<li>As for secret chat files, the <code>md5_checksum</code> is to be set to the MD5 hash of the <em>encrypted</em> file, for a server-side integrity check.</li>
<li>The <code>file_hash</code> field should be set to the <em>data_hash</em> of the data.</li>
<li>The <code>secret</code> field is the <em>encrypted_data_secret</em>.</li>
<p>The email/phone is passed in plaintext using the respective <ahref="/type/SecurePlainData">SecurePlainData</a> constructor.
To verify a phone number or email and use it in Telegram Passport, use the appropriate methods:</p>
<ul>
<li><ahref="/method/account.sendVerifyEmailCode">account.sendVerifyEmailCode</a> - Send the verification email code for telegram <ahref="/passport">passport</a>.</li>
<li><ahref="/method/account.verifyEmail">account.verifyEmail</a> - Verify an email address for telegram <ahref="/passport">passport</a>.</li>
<li><ahref="/method/account.sendVerifyPhoneCode">account.sendVerifyPhoneCode</a> - Send the verification phone code for telegram <ahref="/passport">passport</a>.</li>
<li><ahref="/method/account.verifyPhone">account.verifyPhone</a> - Verify a phone number for telegram <ahref="/passport">passport</a>. </li>
<li><ahref="/method/auth.resendCode">auth.resendCode</a> - Only for phone code verification, resend the code using a different method</li>
<li><ahref="/method/auth.cancelCode">auth.cancelCode</a> - Only for phone code verification, cancel phone code verification</li>
</ul>
<p>The flow is similar to the one used for <ahref="/api/auth">logging in</a>:</p>
<li>Send email/phone code using the appropriate <code>account.sendVerify*Code</code> method<ul>
<li>Make sure to pass <ahref="/constructor/emailVerifyPurposePassport">emailVerifyPurposePassport</a> as verification purpose to <ahref="/method/account.sendVerifyEmailCode">account.sendVerifyEmailCode</a>.</li>
<li>Pass the received code to the appropriate <code>account.verify*</code> method</li>
<li>Only for phone code verification, you can also resend/cancel the phone code using <ahref="/method/auth.resendCode">auth.resendCode</a>/<ahref="/method/auth.cancelCode">auth.cancelCode</a>, as for <ahref="/api/auth">logging in</a>.</li>
</ul>
<p>For more info, see the <ahref="/api/auth">authorization docs</a>.</p>
<h4><aclass="anchor"href="#when-to-use-each-constructor"id="when-to-use-each-constructor"name="when-to-use-each-constructor"><iclass="anchor-icon"></i></a>When to use each constructor.</h4>
<p>Here's a list of possible <ahref="/type/SecureValueType">SecureValueTypes</a>, and the parameters that can be set/requested when using each type.</p>
<p>When a service requests data, it passes a <em>nonce</em> 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.</p>
<p>Once the user authorizes the Telegram Passport data transfer, the client forms the credentials (<ahref="/passport#credentials">Credentials JSON object</a>). Credentials contain the <em>data_hash</em> and <em>data_secret</em> from each element of Telegram Passport to which the user has allowed access. In addition to this, the credentials will always contain the <em>nonce</em> that the client received from the service at the initiation of the request. </p>
<p>Credentials are then passed to the service through the Bot API in encrypted form. To encrypt the credentials, the client generates a <em>credentials_secret</em> (a 32-byte number with the modulo 255 sum of bytes equal to 239). Then the credentials are encrypted according to the following scheme:</p>
<ul>
<li>
<p>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.</p>
</li>
<li>
<p>A hash of the padded credentials <em>credentials_hash</em> is calculated:</p>
<p>The encrypted credentials are passed to the service via the MTProto API together with the encrypred <em>credentials_secret</em> and <em>credentials_hash</em>. Along with the credentials, the service receives from the Telegram Cloud the data it requested in encrypted form. See <ahref="/api/passport#submitting-the-passport-form">Submitting the Passport Form</a> and <ahref="/bots/api#passportdata">PassportData</a>:</p>