<p>Telegram uses the <ahref="https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol">Secure Remote Password protocol</a> version 6a to implement 2FA.</p>
<h3><aclass="anchor"href="#checking-the-password-with-srp"id="checking-the-password-with-srp"name="checking-the-password-with-srp"><iclass="anchor-icon"></i></a>Checking the password with SRP</h3>
<p>To login to an account protected by a 2FA password or to perform some other actions (like changing channel owner), you will need to verify the user's knowledge of the current 2FA account password.</p>
<p>To do this, first the client needs to obtain SRP parameters and the KDF algorithm to use to check the validity of the password via <ahref="https://core.telegram.org/method/account.getPassword">account.getPassword</a> method. For now, only the <ahref="/constructor/passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow">passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow</a> algorithm is supported, so we'll only explain that.</p>
<p>Then, after the user provides a password, the client should generate an <ahref="/type/InputCheckPasswordSRP">InputCheckPasswordSRP</a> object using SRP and a specific KDF algorithm as shown below and pass it to appropriate method (e.g. <ahref="/method/auth.checkPassword">auth.checkPassword</a> in case of authorization).</p>
<p>This extension of the <ahref="https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol">SRP protocol</a> uses the password-based <ahref="https://en.wikipedia.org/wiki/PBKDF2">PBKDF2</a> with 100000 iterations using sha512 (<code>PBKDF2HMACSHA512iter100000</code>).
PBKDF2 is used to additionally rehash the <code>x</code> parameter, obtained using a method similar to the one described in <ahref="https://tools.ietf.org/html/rfc2945#section-3">RFC 2945</a> (<code>H(s | H ( I | password | I) | s)</code> instead of <code>H(s | H ( I | ":" | password)</code>) (see below).</p>
<p>Here, <code>|</code> denotes concatenation and <code>+</code> denotes the arithmetical operator <code>+</code>.
In all cases where concatenation of numbers passed to hashing functions is done, the numbers must be used in big-endian form, padded to 2048 bits; all maths is modulo <code>p</code>.
Instead of <code>I</code>, <code>salt1</code> will be used (see <ahref="https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol">SRP protocol</a>).
Instead of <code>s</code>, <code>salt2</code> will be used (see <ahref="https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol">SRP protocol</a>).</p>
<p>Client-side, the following parameters are extracted from the <ahref="/constructor/passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow">passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow</a> object, contained in the <ahref="/constructor/account.password">account.password</a> object.</p>
The client is expected to check whether <strong>p</strong> is a safe 2048-bit prime (meaning that both <strong>p</strong> and <strong>(p-1)/2</strong> are prime, and that <code>2^2047 < p < 2^2048</code>), and that <strong>g</strong> generates a cyclic subgroup of prime order <strong>(p-1)/2</strong>, i.e. is a quadratic residue <strong>mod p</strong>. Since <strong>g</strong> is always equal to 2, 3, 4, 5, 6 or 7, this is easily done using quadratic reciprocity law, yielding a simple condition on <strong>p mod 4g</strong> -- namely, <strong>p mod 8 = 7</strong> for <strong>g = 2</strong>; <strong>p mod 3 = 2</strong> for <strong>g = 3</strong>; no extra condition for <strong>g = 4</strong>; <strong>p mod 5 = 1 or 4</strong> for <strong>g = 5</strong>; <strong>p mod 24 = 19 or 23</strong> for <strong>g = 6</strong>; and <strong>p mod 7 = 3, 5 or 6</strong> for <strong>g = 7</strong>. After <strong>g</strong> and <strong>p</strong> have been checked by the client, it makes sense to cache the result, so as to avoid repeating lengthy computations in future. This cache might be shared with one used for <ahref="/mtproto/auth_key">Authorization Key generation</a>.</p>
<p>If the client has an inadequate random number generator, it makes sense to use the <strong>secure_random</strong> of account.password as additional seed.</p>
<p>The <code>k</code> parameter is generated, both on client and server:</p>
<ul>
<li><code>k := H(p | g)</code></li>
</ul>
<p>The shared param <code>u</code> is generated: the client does this, and the server does the same with the <code>g_a</code> we will send him later (see below)</p>
<ul>
<li><code>u := H(g_a | g_b)</code></li>
</ul>
<p>The final parameters are generated client-side only:</p>
<p>The server already has <code>v</code>, from when we set the password.</p>
<p>A final shared param is generated, for commodity:</p>
<ul>
<li><code>k_v := (k * v) mod p</code></li>
</ul>
<p>Finally, the <ahref="https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol#Protocol">key exchange process</a> starts on both parties.</p>
<p>The client computes a 2048-bit number <strong>a</strong> (using sufficient entropy or the server’s <strong>random</strong>; see above) and generates:</p>
<ul>
<li><code>g_a := pow(g, a) mod p</code>.</li>
</ul>
<p>The server computes a 2048-bit number <strong>b</strong> using sufficient entropy and generates the <code>g_b</code> parameter that was sent to us (see above).</p>
<ul>
<li><code>g_b := (k_v + (pow(g, b) mod p)) mod p</code></li>
</ul>
<p>Finally, the <ahref="https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol#Protocol">SRP session keys</a> are generated:</p>
<p>Client side: </p>
<ul>
<li><code>t := (g_b - k_v) mod p</code> (positive modulo, if the result is negative increment by <code>p</code>) </li>
<li><code>s_a := pow(t, a + u * x) mod p</code></li>
<li><code>k_a := H(s_a)</code></li>
</ul>
<p>Server side: </p>
<ul>
<li><code>s_b := pow(g_a * (pow(v, u) mod p), b) mod p</code></li>
<li><code>k_b := H(s_b)</code></li>
</ul>
<p>Since:</p>
<ul>
<li><code>g_b := (k_v + (pow(g, b) mod p)) mod p</code></li>
<li><code>t := (g_b - k_v) mod p</code></li>
<li><code>t := ((k_v + (pow(g, b) mod p)) - k_v) mod p</code></li>
<li><code>t := pow(g, b) mod p</code></li>
<li><code>s_a := pow(t, a + u * x) mod p</code></li>
<li><code>s_a := pow(pow(g, b) mod p, a + u * x) mod p</code></li>
<p><code>M1</code> is passed to <ahref="/constructor/inputCheckPasswordSRP">inputCheckPasswordSRP</a>, along with <code>g_a</code> (as <code>A</code> parameter) and the <code>srp_id</code>, extracted from the <ahref="/constructor/account.password">account.password</a> object.</p>
<p>If the password isn't correct, <ahref="/method/auth.checkPassword#possible-errors">400 PASSWORD_HASH_INVALID</a> will be returned.</p>
<h3><aclass="anchor"href="#setting-a-new-2fa-password"id="setting-a-new-2fa-password"name="setting-a-new-2fa-password"><iclass="anchor-icon"></i></a>Setting a new 2FA password</h3>
<p>To set a new 2FA password use the <ahref="/method/account.updatePasswordSettings">account.updatePasswordSettings</a> method.<br>
If a password is already set, generate an InputCheckPasswordSRP object as per <ahref="#checking-the-password-with-srp">checking passwords with SRP</a>, and insert it in the <code>password</code> field of the <ahref="/method/account.updatePasswordSettings">account.updatePasswordSettings</a> method.<br>
To remove the current password, pass an empty <code>new_password_hash</code> in the <ahref="/type/account.PasswordInputSettings">account.PasswordInputSettings</a> object.</p>
<p>To set a new password, use the SRP parameters and the KDF algorithm obtained using <ahref="https://core.telegram.org/method/account.getPassword">account.getPassword</a> when generating the <code>password</code> field.
Then generate a new <code>new_password_hash</code> using the KDF algorithm specified in the <code>new_settings</code>, just append 32 sufficiently random bytes to the <code>salt1</code>, first.
Proceed as for <ahref="#checking-the-password-with-srp">checking passwords with SRP</a>, just stop at the generation of the <code>v</code> parameter, and use it as <code>new_password_hash</code>:</p>
<p>When setting up two-factor authorization, it is recommended to set up a <strong>recovery email</strong>, to allow recovery of the password through the user's email address, in case they forget it.</p>
<p>To set up a recovery email, it must first be verified.
This can be done directly when setting the new password using <ahref="/method/account.updatePasswordSettings">account.updatePasswordSettings</a> by setting the email parameter and flag in the <ahref="/constructor/account.passwordInputSettings">account.passwordInputSettings</a> constructor.
If the email isn't verified, an <ahref="/method/account.updatePasswordSettings#possible-errors">EMAIL_UNCONFIRMED_X 400 error</a> will be returned, where X is the length of the verification code that was just sent to the email.
Use <ahref="/method/account.confirmPasswordEmail">account.confirmPasswordEmail</a> to enter the received verification code and enable the recovery email.
Use <ahref="/method/account.resendPasswordEmail">account.resendPasswordEmail</a> to resend the verification code.
Use <ahref="/method/account.cancelPasswordEmail">account.cancelPasswordEmail</a> to cancel the verification code.</p>
<p>In order to recover a forgotten 2FA password, an email must be sent to the <ahref="#email-verification">previously specified address</a> using the <ahref="/method/auth.requestPasswordRecovery">auth.requestPasswordRecovery</a> method.<br>
Use <ahref="/method/auth.checkRecoveryPassword">auth.checkRecoveryPassword</a> to make sure that the user provided a valid code.<br>
Then use <ahref="/method/auth.recoverPassword">auth.recoverPassword</a> with the received code to delete the current 2FA password, to set a new one follow <ahref="/api/srp">these instructions</a>.</p>