Как стать автором
Обновить

Почему длинные TOTP-коды почти всегда содержат повторы (и это нормально)

Уровень сложностиСредний
Время на прочтение2 мин
Количество просмотров2K

TL;DR

Если вы когда-нибудь замечали, что длинные коды двухфакторной аутентификации (TOTP) часто содержат повторы вроде 131488 или симметрии вроде 1221 — это не баг, а статистическая закономерность. Чем длиннее код, тем выше вероятность, что в нём встретятся простые или "запоминающиеся" фрагменты. Это нормально и не снижает безопасность.

Базовая идея

TOTP-коды генерируются по стандарту RFC 6238: берётся криптографический HMAC от текущего времени и секретного ключа. Итоговая 6- или 8-значная строка — результат детерминированной, но непредсказуемой функции.

Секрет K + время THMAC(K, T) → усечённый до 6 цифр код.

Почему повторы встречаются чаще, чем кажется

1. Вероятность совпадений при фиксированном алфавите

6 цифр, 10 возможных значений (0–9): всего 1 000 000 комбинаций. Но без повторяющихся цифр — только ~150 000. Значит, в 85% случаев в коде есть хотя бы одна повторяющаяся цифра.

Чем длиннее код, тем выше вероятность:

  • повторов (44, 000, 878)

  • последовательностей (123, 321)

  • симметрий (2442, 9009)

Это описывается через парадокс дней рождения и законы теории информации.

2. Эффект Рамсея: паттерны появляются неизбежно

Согласно идеям теории Рамсея, любая достаточно длинная случайная строка почти гарантированно содержит локально "организованные" подстроки — даже если глобально она абсолютно случайна.

Безопасность не страдает

Появление симметрии или повтора не делает код менее защищённым. Ключевые свойства сохраняются:

  • Секретный ключ K остаётся криптостойким

  • Хэш-функция (обычно SHA-1 или SHA-256) односторонняя

  • Код живёт 30 секунд, что исключает эффективный перебор

Если кто-то хочет "делать коды более красивыми" — это уже вмешательство в криптографию и снижение энтропии. Так делать не стоит.

Вывод

Запоминающиеся паттерны в TOTP-кодах — это не слабость, а статистическое следствие. Чем длиннее код, тем больше в нём места для "совпадений". Это подтверждает, что генерация работает корректно — а не наоборот.

P.S. Пример на Python для тех, кто хочет экспериментировать

import time, hmac, base64, hashlib

def totp(secret, digits=6, interval=30):
    key = base64.b32decode(secret.upper())
    counter = int(time.time() / interval)
    msg = counter.to_bytes(8, 'big')
    h = hmac.new(key, msg, hashlib.sha1).digest()
    o = h[-1] & 0x0F
    code = (int.from_bytes(h[o:o+4], 'big') & 0x7fffffff) % (10**digits)
    return str(code).zfill(digits)

print(totp('JBSWY3DPEHPK3PXP'))
Теги:
Хабы:
+1
Комментарии7

Публикации