Алгоритм одноразового пароля на основе HMAC
Алгоритм одноразового пароля на основе HMAC (HOTP) – это алгоритм для создания значений одноразового пароля на основе HMAC (код аутентификации хешированного сообщения). Это один из основных протоколов для алгоритмов двухфакторной аутентификации. Алгоритм HOTP основан на возрастающем значении счетчика и статическом симметричном ключе, известном только токену и службе проверки. Для создания значения HOTP будет использоваться алгоритм HMAC-SHA-1. Это односторонний алгоритм аутентификации: сервер выполняет аутентификацию клиентов.

Цель 
В последние годы быстрый рост сетевых угроз выявил неадекватность статических паролей как основного средства аутентификации в Интернете. Использование дорогостоящего специального однофункционального устройства, которое используется только для аутентификации в сети, явно не является правильным решением. Только открытый системный подход гарантирует, что основные примитивы двухфакторной аутентификации могут быть встроены в потребительские устройства следующего поколения, такие как USB-накопители, IP-телефоны и персональные цифровые помощники. Одноразовый пароль, безусловно, является одной из самых простых и популярных форм двухфакторной аутентификации для защиты доступа к сети.

История 
HOTP был опубликован в качестве информационного документа IETF RFC 4226 в декабре 2005 года, документируя алгоритм вместе с реализацией Java. С тех пор алгоритм был принят многими компаниями по всему миру (см. ниже). Алгоритм HOTP является свободно доступным открытым стандартом.

HMAC 
HMAC (short for hash-based message authentication code, код аутентификации сообщения с использованием однонаправленных хеш-функций) - в криптографии один из механизмов проверки целостности информации, гарантирующий, что данные, передаваемые или хранящиеся в ненадежной среде, не были изменены посторонними лицами (атака типа «человек посередине»). Алгоритм HOTP использует хеш-функцию SHA-1, которая неустойчива к коллизиям. Но на работоспособности это не сказывается, так как важен сам факт случайности числа.
Описание алгоритма
Если ввести следующие обозначения:
 b, block_size — размер блока в байтах;
 H, hash — хеш-функция;
 ipad — блок вида ( 0x36 0x36 0x36 ... 0x36 ), где байт 0x36 повторяется b раз; 0x36 — константа, приведённое в RFC 2104 «i» от «inner»
 K, key — секретный ключ (общий для отправителя и получателя);
 K0 — изменённый ключ K (уменьшенный или увеличенный до размера блока (до b байт));
 L — размер в байтах строки, возвращаемой хеш-функцией H; L зависит от выбранной хеш-функции и обычно меньше размера блока
 opad — блок вида ( 0x5c 0x5c 0x5c ... 0x5c), где байт 0x5c повторяется b раз; 0x5c — константа, приведённое в RFC 2104 «o» от «outer»
 text — сообщение (данные), которое будет передаваться отправителем и подлинность которого будет проверяться получателем;
 n — длина сообщения text в битах.
То алгоритм HMAC можно записать следующей формулой: 
Или алгоритмически:
 Получить K0, увеличив или уменьшив ключ K до размера блока (до b байта).

1.a) Если длина ключа K равна размеру блока, то скопируйте K в K0 без изменений.

1.б) Если длина ключа K больше размера блока, то к ключу K применяется хеш-функция H, так что получается строка L размер байта. Затем к правой части строки добавляются нули, чтобы получить строку размером b в байтах, и результат копируется в K0.

1.c) Если длина ключа K меньше размера блока, то в правую часть K добавляются нули, чтобы получить строку размером b в байтах и результат копируется в K0.

  Получить блок Si размером b в байтах, используя  операция:
Si = xor( K0, ipad ) = K0  ipad.

  Получить блок So размером b в байтах, используя  операция:
So = xor( K0, opad ) = K0  opad.

  Разделить сообщение text на блоки размером b байт.
 Объединить строку Si с каждым блоком сообщения М.
 Применить хеш-функцию Н к строке из предыдущего шага.
 Объединить строку So со строкой из предыдущего шага.
 Применяем хеш-функцию Н к строке из предыдущего шага.

Ключи меньше L байт считаются небезопасными. Рекомендуется выбирать ключи случайным образом и регулярно их менять. Ключи размером более L байт, существенно не увеличивают силу функции, могут использоваться при наличии сомнений в случайности данных, использованных для создания ключа и полученных от генератора случайных чисел.
Размер ключа K должен быть больше или равен L/2 байт.

Общее описание алгоритма HOTP
Алгоритм должен возвращать не менее 6 цифр, чтобы обеспечить достаточную безопасность пароля. В зависимости от уровня требований безопасности вы можете использовать более высокие значения цифр для HOTP, чтобы сделать пароль более устойчивым к атакам. Работу алгоритма можно описать следующей формулой:Процесс работы алгоритма можно разделить на следующие этапы:
 Создайте строку  из 20 байтов, используя хеш-функцию , инициализированную с помощью  и : 
 Выберите 4 байта из  определенным образом: 
 Последние четыре бита последнего байта результата  преобразуются в число 
 Последовательность байтов  преобразуется в переменную 
  возвращает последние 31 бит . Причина, по которой старший бит  игнорируется, состоит в разных реализациях целочисленных вычислений для разных процессоров
 Результат  преобразуется в последовательность цифр : 
Где введены обозначения:
  — Секретный ключ, известный только клиенту и серверу. Длина от 128 до 160 бит
  — Текущее состояние 8-байтового счётчика
  — Количество цифр в генерируемом пароле

Пример работы HOTP
Пусть на выходе HMAC с некоторыми параметрами получили следующее 20-байтное значение:

 Последний байт - 0x5a
 Значение offset, полученное из младших 4 бит — 0xa, это даёт нам число 10
 Значение 4 последовательных байтов, начиная с 10-ой позиции — 0x50ef7f19
 Из значения на предыдущем шаге получаем младшие 31 бит  0x50ef7f19
 Получаем численное значение.
 Для того, чтобы получить шестизначное число для HOTP, необходимо взять число, полученное на предыдущем шаге по модулю 106 —

Проверка значений HOTP 
Клиент HOTP (аппаратный или программный токен) увеличивает свой счетчик, а затем вычисляет следующее значение клиента HOTP. Если значение, полученное сервером аутентификации, совпадает со значением, рассчитанным клиентом, то проверяется значение HOTP. В этом случае сервер увеличивает счетчик на единицу.
Если значение, полученное сервером, не совпадает со значением, рассчитанным клиентом, сервер инициирует протокол повторной синхронизации (окно просмотра вперед) перед запросом другого прохода.
Если повторная синхронизация не удалась, сервер запрашивает повторную попытку аутентификации протокола до тех пор, пока не будет достигнуто максимальное количество авторизованных попыток.

Если и когда будет достигнуто максимально допустимое количество попыток, серверу СЛЕДУЕТ заблокировать учетную запись и инициировать процедуру информирования пользователя.

Ресинхронизация счетчика 
Хотя счетчик сервера увеличивается только после успешной аутентификации HOTP, счетчик токена увеличивается каждый раз, когда пользователь запрашивает новый HOTP. Из-за этого значения счетчиков на сервере и на токене могут не синхронизироваться.
Синхронизация счетчика в этом сценарии просто требует, чтобы сервер вычислил следующие значения HOTP и определил, есть ли совпадение. При желании система МОЖЕТ потребовать от пользователя отправить последовательность (скажем, 2, 3) значений HOTP для целей ресинхронизации, поскольку подмена последовательности последовательных значений HOTP еще сложнее, чем угадывание одного значения HOTP.
Верхняя граница, указанная параметром s, гарантирует, что сервер не будет постоянно проверять значения HOTP (вызывая атаку типа «отказ в обслуживании»), а также ограничивает возможное пространство решений для злоумышленника, пытающегося создать значения HOTP. s СЛЕДУЕТ установить как можно более низкое значение, гарантируя, что это не повлияет на удобство использования.

Улучшения
Улучшение HOTP является алгоритм TOTP (Time-based One-Time Password Algorithm). В нем генерация пароля основывается на времени (время - параметр), а точнее на временном окне.

Cсылки 
 RFC 4226
 hotp-totp-difference

Алгоритмы