Генератор TOTP

Генерируйте и проверяйте временные одноразовые пароли (TOTP) из секрета в кодировке base32. Совместимо с Google Authenticator и RFC 6238.

Одноразовые пароли, RFC 6238. Сгенерируйте текущий TOTP для секрета в кодировке base32 и проверьте полученный код. Счётчик выводится из текущего времени, поэтому коды обновляются каждые 30 или 60 секунд. Работает полностью в вашем браузере.

------

Проверить код

Как работает TOTP

Общий секрет плюс часы

TOTP определён в RFC 6238 и является тонким слоем поверх HOTP. Обе стороны хранят один и тот же секрет, обычно передаваемый однажды как QR-код и сохраняемый в приложении-аутентификаторе. Чтобы создать код, каждая сторона берёт текущее время Unix, делит его на размер шага (по умолчанию 30 секунд), получая счётчик, вычисляет HMAC-SHA1 этого счётчика под секретом и усекает результат до требуемого числа разрядов.

Поскольку счётчик берётся из часов, а не из сообщения, после регистрации ничего не нужно передавать между сторонами. Сервер не отправляет вызов, а приложению не нужен сетевой доступ — поэтому приложения-аутентификаторы работают в режиме «в самолёте».

Усечение и число разрядов

Вывод HMAC — 20 байт, что гораздо больше 6-разрядного кода. Динамическое усечение использует младший полубайт последнего байта как смещение, читает четыре байта, начиная с него, сбрасывает старший бит во избежание проблем со знаком и берёт это число по модулю 10^digits. Использование переменного смещения вместо фиксированного означает, что атакующий не может сосредоточить анализ на известном куске дайджеста.

Шесть разрядов — почти повсеместное значение по умолчанию. Восемь разрядов поддерживается большинством приложений и даёт примерно два лишних десятичных разряда устойчивости к угадыванию, что гораздо менее важно, чем ограничение частоты — 6-разрядный код имеет шанс 1 к миллиону на одну попытку, так что реальная защита — блокировка после нескольких неудач.

Дрейф часов и повтор

Устройства дрейфуют. Серверы обычно принимают код из предыдущего и следующего окна, а также текущего, давая допуск ±30 секунд. Расширение этого окна более чем на минуту-две начинает заметно увеличивать поверхность атаки и обычно является признаком того, что часы устройства нужно исправить.

Два свойства стоит помнить при развёртывании. Код остаётся действительным в течение всего своего окна, поэтому перехваченный код может быть воспроизведён в этом окне, если сервер не помечает использованные счётчики как израсходованные. А секрет симметричен: тот, кто хранит серверную копию, может генерировать действительные коды вечно, поэтому он требует той же защиты, что и база паролей, — зашифрован в покое, никогда не логируется, никогда не попадает в git-репозиторий.

Примечание об открытом ПО: реализовано с помощью нативного браузерного API Web Crypto (crypto.subtle) и самодельного декодера base32. Без сторонних библиотек.

FAQ

Может ли это заменить моё приложение-аутентификатор?
Полезно для тестирования и для восстановления кода, когда телефон недоступен, но вкладка браузера — небезопасное место для хранения долговременного общего секрета.
Почему мой код отклоняется?
Почти всегда дрейф часов. TOTP выводит код из текущего времени UNIX, поэтому устройство, отстающее от сервера более чем на один 30-секундный шаг, выдаёт код, который сервер уже прошёл.
Что представляет собой секрет Base32?
Это общий ключ, который хранят обе стороны. Base32 используется, потому что он нечувствителен к регистру и избегает неоднозначных символов, что удобно для ввода или кодирования в QR-код.
Почему коды шестиразрядные?
RFC 6238 усекает HMAC до 31-битного значения и берёт его по модулю 10^6. Шесть разрядов балансируют удобство против вероятности угадывания 1 к миллиону за попытку, что ограничение частоты снижает ещё сильнее.
В чём разница между TOTP и HOTP?
TOTP считает 30-секундные шаги времени; HOTP считает события и продвигается только при использовании кода. TOTP нужны синхронизированные часы, HOTP — синхронизированные счётчики.
Можно ли использовать один код дважды?
Не должно быть. Код остаётся действительным в течение всего временного шага, поэтому сервер ожидает записывать, какой шаг пользователь уже использовал, и отклонять повтор.