Explain the TOTP algorithm

This commit is contained in:
Quantum 2025-02-16 16:42:09 -05:00
parent f56b81d83a
commit 81c757505d
5 changed files with 54 additions and 4 deletions

View file

@ -6,15 +6,15 @@
<link rel="icon" type="image/svg+xml" href="/totp.svg"/>
<link rel="shortcut icon" href="/favicon.ico"/>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"/>
<meta name="apple-mobile-web-app-title" content="TOTP.lol"/>
<meta name="apple-mobile-web-app-title" content="TOTP.fyi"/>
<link rel="manifest" href="/site.webmanifest"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>TOTP.lol — A TOTP Code Generator for Developers</title>
<title>TOTP.fyi — A TOTP Code Generator for Developers</title>
</head>
<body>
<nav class="navbar navbar-expand-lg">
<div class="container">
<a class="navbar-brand" href="#">TOTP.lol</a>
<a class="navbar-brand" href="#">TOTP.fyi</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
@ -27,6 +27,9 @@
<li class="nav-item">
<a class="nav-link" href="#how-to-use">How to use?</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#how-does-it-work">How does it work?</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#support-me">Support me</a>
</li>
@ -85,6 +88,50 @@
directly to a certain configuration.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h3 class="card-title" id="how-does-it-work">How does TOTP work?</h3>
<p class="card-text">Time-based one-time password (TOTP), defined in <a
href="https://datatracker.ietf.org/doc/html/rfc6238">RFC 6238</a>, is based on the HMAC-based one-time password
(HOTP) algorithm, which uses the common HMAC construction based on the current time. TOTP requires the following
inputs:
</p>
<ul class="card-text">
<li>The cryptographic hash function <var>H</var>, which defaults to SHA-1. This is configurable in the advanced
settings;
</li>
<li>The secret key <var>K</var>, which is commonly encoded as Base32. This value, encoded in Base32, is what you
enter into the <strong>secret key</strong> field;
</li>
<li>The time window <var>X</var>, which is how long each code is valid for;</li>
<li>The epoch <var>T<sub>0</sub></var>, which is the Unix epoch (0 in Unix time) in every known implementation,
but could be changed; and
</li>
<li>The number of digits <var>d</var>, which is the length of the final output code in decimal digits.</li>
</ul>
<p class="card-text">The algorithm is as follows:</p>
<ol class="card-text">
<li>Take the current unix time <var>U</var>;</li>
<li>Compute the time step count
<img class="math" src="math/t.svg" alt="T=\left\lfloor\frac{U - T_0}{X}\right\rfloor" height="40">;
</li>
<li>Compute the HMAC <img class="math" src="math/h.svg" alt="h = \text{HMAC}_H(K, T)" height="18">;</li>
<li>Extract the 4 lowest order bits, i.e. the 4 least significant bits from the last byte of <var>h</var>, to
create the integer <var>i</var>;
</li>
<li>Take four bytes from <var>h</var> starting at <var>i</var>, i.e. bytes [<var>i</var>, <var>i</var>+4), mask
off the most significant bit (to support signed arithmetic), and use it to create the integer <var>y</var>;
and finally
</li>
<li>Compute the code as <img class="math" src="math/mod.svg" alt="y \bmod{10^d}" height="18"
style="vertical-align: -3px">.
</li>
</ol>
<p class="card-text">To avoid clock synchronization issues, most implementations will accept TOTP codes from the
window before and after the one based on the current time. This tool lets you see the previous and next codes to
help you debug.</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h3 class="card-title" id="support-me">I like this website. How can I support you?</h3>

1
math/h.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.3 KiB

1
math/mod.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" viewBox="0 -903.7 4385.3 1108.7"><defs><path id="a" d="M21 287q0 14 15 48t48 71 74 36q41 0 66-23t26-64q-2-19-3-21 0-3-16-46t-33-97-16-86q0-43 14-60t42-18q23 0 43 11t31 23 27 33q0 1 5 20t14 59 19 74q38 150 42 157 13 27 43 27 13 0 21-7t11-12 2-9q0-13-49-210T391-23q-28-83-97-132t-138-50q-45 0-79 22t-34 66q0 22 7 37t19 22 20 10 17 3q44 0 44-42 0-20-12-35t-23-20-13-5l-3-1q2-5 19-12t34-7h8q17 0 26 2 33 9 61 38t43 62 23 56 8 30l-6-4q-6-4-19-11T270-6q-20-5-39-5-46 0-81 22t-46 71q-1 7-1 31 0 57 35 149t35 117v14q0 3-4 7t-11 4h-4q-23 0-42-19t-30-41-17-42-8-22q-2-2-16-2H27q-6 6-6 9Z"/><path id="b" d="M41 46h14q39 0 47 14v62q0 17 1 39t0 42v66q0 35-1 59v23q-3 19-14 25t-45 9H25v23q0 23 2 23l10 1q10 1 28 2t37 2l36 2q19 1 29 3t11 1h3v-40q0-38 1-38t5 5 12 15 19 18 29 19 38 16q20 5 51 5 15 0 28-2t23-6 19-8 15-9 11-11 9-11 7-11 4-10 3-8l2-5 3 4 6 8q3 4 9 11t13 13 15 13 20 12 23 10 26 7 31 3q126 0 137-113 1-7 1-139v-86q0-38 2-45t11-10q21-3 49-3h16V0h-8l-23 1q-24 1-51 1t-38 1Q596 3 587 0h-8v46h16q61 0 61 16 1 2 1 138-1 135-2 143-6 28-20 42t-24 17-26 2q-45 0-79-34-27-27-34-55t-8-83V108q0-30 1-40t3-13 9-6q21-3 49-3h16V0h-8l-24 1q-23 1-50 1t-38 1Q319 3 310 0h-8v46h16q61 0 61 16 1 2 1 138-1 135-2 143-6 28-20 42t-24 17-26 2q-45 0-79-34-27-27-34-55t-8-83V108q0-30 1-40t3-13 9-6q21-3 49-3h16V0h-8l-23 1q-24 1-51 1t-38 1Q42 3 33 0h-8v46h16Z"/><path id="c" d="M28 214q0 95 65 164t157 70q90 0 155-68t66-165q0-95-64-160T250-10q-97 0-159 67T28 214ZM250 30q122 0 122 163v57q0 22-1 38t-7 38-16 36-31 28-49 20q-5 1-16 1-30 0-57-12-43-22-56-61t-13-92v-20q0-96 19-135 32-61 105-61Z"/><path id="d" d="M376 495v40q0 24 1 33 0 45-10 56t-51 13h-18v23q0 23 2 23l10 1q10 1 29 2t37 2l37 2q20 1 30 3t11 1h3V390q0-306 1-309 3-20 14-26t45-9h18V0q-2 0-76-5t-79-6h-7v55l-8-7q-58-48-130-48-77 0-139 61T34 215q0 100 63 163t147 64q75 0 132-49v102Zm-3-153q-45 63-113 63-49 0-87-36-27-28-34-64t-8-94q0-56 7-91t35-61q30-33 78-33 71 0 122 77v239Z"/><path id="e" d="m213 578-13-5q-14-5-40-10t-58-7H83v46h19q47 2 87 15t56 24 28 22q2 3 12 3 9 0 17-6V361l1-300q7-7 12-9t24-4 62-2h26V0h-11q-21 3-159 3-136 0-157-3H88v46h64q16 0 25 1t16 3 8 2 6 5 6 4v517Z"/><path id="f" d="M96 585q56 81 153 81 48 0 96-26t78-92q37-83 37-228 0-155-43-237-20-42-55-67t-61-31-51-7q-26 0-52 6t-61 32-55 67q-43 82-43 237 0 174 57 265Zm225 12q-30 32-71 32-42 0-72-32-25-26-33-72t-8-192q0-158 8-208t36-79q28-30 69-30 40 0 68 30 29 30 36 84t8 203q0 145-8 191t-33 73Z"/><path id="g" d="m366 683 72 5q71 5 73 6 12 0 12-8 0-7-73-302T375 83t-1-15q0-42 28-42 9 1 20 9 21 20 41 96 6 20 10 21 2 1 10 1h8q15 0 15-8 0-5-3-16-13-50-30-81T445 8 417-8q-8-2-24-2-34 0-57 15t-30 31l-6 15q-1 1-4-1l-4-4q-59-56-120-56-55 0-97 40T33 157q0 48 20 98t48 86q47 57 94 79t85 22q56 0 84-42 5-6 5-4l27 109q26 105 28 111 0 13-7 16t-39 5h-21q-6 6-6 8t2 19q5 19 13 19Zm-14-357q-23 79-75 79-35 0-67-31t-50-81q-29-79-41-164v-11q0-8-1-12 0-45 18-62t43-18q54 0 111 72l8 11 54 217Z"/></defs><g stroke="#000" stroke-width="0"><use xlink:href="#a" transform="scale(1 -1)"/><g transform="matrix(1 0 0 -1 767.8 0)"><use xlink:href="#b"/><use xlink:href="#c" transform="translate(833)"/><use xlink:href="#d" transform="translate(1333)"/></g><g><g><g transform="matrix(1 0 0 -1 2934.6 0)"><use xlink:href="#e"/><use xlink:href="#f" transform="translate(500)"/></g><use xlink:href="#g" transform="matrix(.7 0 0 -.7 3967.6 -413)"/></g></g></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

1
math/t.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" viewBox="0 -1449.5 6653.6 2399"><defs><path id="a" d="M40 437q-19 0-19 8 0 5 16 56t34 101l17 49q5 18 13 26h558q32 0 38-1t7-9q0-6-17-114t-19-109q0-7-19-7h-12q-3 0-6 5l-2 3q0 6 6 45t6 61q0 35-13 53t-55 25q-5 1-58 2-46 0-58-1t-18-8q-1-1-71-279T298 60q0-12 88-14 32 0 41-1t9-9q0-5-3-14-4-18-9-21l-2-1h-7l-52 1q-47 1-135 1Q99 2 64 0H49q-6 6-6 9t2 18q4 13 10 19h39q80 0 95 9 1 1 2 1 5 3 10 20t40 157q17 68 28 111 70 275 70 281 0 5-29 5h-31q-67 0-88-6-45-10-70-41T67 467q-7-22-10-26t-14-4h-3Z"/><path id="b" d="M56 347q0 13 14 20h637q15-8 15-20 0-11-14-19l-318-1H72q-16 5-16 20Zm0-194q0 15 16 20h636q14-10 14-20 0-13-15-20H70q-14 7-14 20Z"/><path id="c" d="M246-949v2399h62V-887h263v-62H246Z"/><path id="d" d="M107 637q-34 0-36 4-1 2-1 8 0 24 11 33 2 1 17 1 41-2 136-2h63q29 0 45 1t20 0q16 0 16-10 0-2-2-14-5-17-10-20h-14q-4 0-9-1t-9 0q-39-1-50-3t-18-11q-1-2-28-105t-54-216-30-133q-2-14-2-29 0-54 31-85t86-31q67 0 134 45t98 136l51 201q47 192 47 200 0 27-64 31-24 0-24 11 0 2 2 12 4 16 6 19t10 4l32-1q29-1 84-2 51 0 78 1t29 1q15 0 15-10 0-22-8-30-3-5-22-5-71-4-89-40-2-5-50-193-41-169-50-199-33-100-115-163T263-22q-92 0-147 56T60 167v16q0 18 55 238 49 201 49 207 0 7-57 9Z"/><path id="e" d="M84 237v13l14 20h581q15-8 15-20t-15-20H98q-14 7-14 20Z"/><path id="f" d="M96 585q56 81 153 81 48 0 96-26t78-92q37-83 37-228 0-155-43-237-20-42-55-67t-61-31-51-7q-26 0-52 6t-61 32-55 67q-43 82-43 237 0 174 57 265Zm225 12q-30 32-71 32-42 0-72-32-25-26-33-72t-8-192q0-158 8-208t36-79q28-30 69-30 40 0 68 30 29 30 36 84t8 203q0 145-8 191t-33 73Z"/><path id="g" d="M42 0h-2Q26 0 26 11q0 4 3 16 4 14 7 16t19 3q86 3 135 52 10 10 116 126t105 118Q302 620 297 625q-9 11-63 12h-28q-6 6-6 8t2 19q4 13 10 19h14q34-2 121-2h61q28 0 45 1t20 0q17 0 17-11 0-1-2-13-4-15-7-18t-16-3q-31-3-54-17l77-194 53 59q105 113 105 125 0 18-24 25-5 0-13 2-15 0-15 11 0 2 2 16 4 13 10 19h37q24 0 54-2t41-1q90 0 99 3h8q7-7 7-11-2-25-12-35h-16q-34-1-61-9t-41-17-24-18l-11-9q0 1-95-104l-87-96q0-1 31-80t65-162 37-86q10-9 61-10 35 0 35-9 0-2-2-14-4-16-7-19t-14-3h-33q-30 0-89 1h-93q-32 0-35-1-17 0-17 9 0 1 2 15 2 10 4 14t5 5 9 2 16 1 26 7q17 8 17 10-1 0-47 117l-47 118Q241 95 236 84q-4-8-4-12 0-19 29-25h6q5 0 6-1h4q1 0 3-1t3-3 1-7q0-9-2-16-3-13-6-15t-15-3h-18q-15 0-42 1t-59 0Q64 2 42 0Z"/><path id="h" d="M274-887v2337h62V-949H11v62h263Z"/></defs><g stroke="#000" stroke-width="0"><use xlink:href="#a" transform="scale(1 -1)"/><use xlink:href="#b" transform="matrix(1 0 0 -1 981.8 0)"/><g><use xlink:href="#c" transform="matrix(1 0 0 -1 2037.6 .5)"/><g><g><use xlink:href="#d" transform="matrix(1 0 0 -1 2840.6 -676)"/><use xlink:href="#e" transform="matrix(1 0 0 -1 3829.8 -676)"/><g><use xlink:href="#a" transform="matrix(1 0 0 -1 4830 -676)"/><use xlink:href="#f" transform="matrix(.7 0 0 -.7 5447 -526)"/></g></g><use xlink:href="#g" transform="matrix(1 0 0 -1 3919.6 686)"/><path stroke="none" d="M2740.6-220h3210v-60h-3210z"/></g><use xlink:href="#h" transform="matrix(1 0 0 -1 6070.6 .5)"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -1,5 +1,5 @@
{
"name": "TOTP.lol",
"name": "TOTP.fyi",
"short_name": "TOTP",
"icons": [
{