Необходимо пройти аутентификацию на Jabber сервере на основе алгоритма RFC 2831 использование MD5-Digest аутентификации в SASL.
Все вроде открыто, ясно и понятно.... но на практике ничего не выходит.
Проверить правильность работы своей не могу, так как отсутствуют реальные логи обмена Сlient-Server.
Нашел с примером только следующее:
1. в примере response=16351f86cc5591312e20b4ccd880eadb у меня такого не получаетсяОбщие принципы работы SASL
Метод SASL (Simple Authentication and Security Layer) используется для добавления поддержки аутентификации в различные протоколы соединения. Для аутентификации могут быть использованы различные механизмы.
Имя требуемого механизма задаётся клиентом в команде аутентификации. Если сервер поддерживает указанный механизм, он посылает клиенту последовательность окликов (challenges), на которые клиент посылает ответы (responses), чтобы удостоверить себя. Содержимое окликов и ответов определяется используемым механизмом и может представлять собой двоичные последовательности произвольной длины. Кодировка последовательностей определяется прикладным протоколом. Вместо очередного оклика сервер может послать подтверждение аутентификации или отказ. Кодировка также определяется протоколом. Вместо ответа клиент может послать отказ от аутентификации. Кодировка опять определяется протоколом. В результате обменов откликам и ответами должна произойти аутентификация (или отказ), передача идентификатора клиента (пустой идентификатор влечёт получение идентификатора из аутентификации) серверу и, возможно, договорённость об использовании безопасного транспортного протокола (security layer), включая максимальный размер буфера шифрования.
Идентификатор клиента может отличаться от идентификатора, определяемого из аутентификации, для обеспечения возможности работы прокси.
Реализация на примере механизма MD5-Digest
Схема работы SASL для нашего клиента основана на использовании механизма MD-Digest и имеет следующий алгоритм работы:
Сервер посылает случайную строку nonce, наличие поддержки utf-8 в параметре charset для имени и пароля, алгоритм аутентификации (обязательно md5-sess) в параметре algorithm.
То есть те данные, что мы раскодировали ранее из пакета challenge:Клиент отвечает строкой, содержащей: идентификатор клиента username, идентификатор домена realm, полученную от сервера случайную строку nonce, случайную строку клиента cnonce, номер запроса (позволяет серверу заметить попытку replay attack) nc. параметр digest-uri (сочетание имени сервиса, имени сервера т.е. 'xmpp/' + JID Domain), строку responce подтверждающею знание пароля и ответ на оклик (MD5 от имени пользователя, realm, пароля, случайной строки сервера, случайной строки клиента, идентификатора клиента, номера запроса, уровня защиты, digest-uri; некоторые компоненты берутся в виде MD5, некоторые в исходном виде, некоторые в обоих видах), использование utf-8 для имени и пароля, принятый алгоритм шифрования и идентификатор клиента.Код: Выделить всё
nonce="22647748",qop="auth",charset=utf-8,algorithm=md5-sess
То есть, как вы догадались эта та строка, которую мы формируем в ответ:username — JID-node пользователяКод: Выделить всё
username="delphi-test", realm="jabber.ru", nonce="22647748", cnonce="2313e069649daa0ca2b76363525059ebd", nc=00000001, qop=auth, digest-uri="xmpp/jabber.ru", charset=utf-8, response=16351f86cc5591312e20b4ccd880eadb
realm — JID-domain пользователя
nonce — Уникальный код сессии, присланный нам ранее сервером
cnonce — Уникальный код ответной клиентской сессии, сгенерированный клиентом
nc — Так называемый once count — сколько раз был использован текущий nonce. Обычно значение параметра равно 00000001, его и будем использовать. На самом деле параметр довольно интересный и стоит отдельного рассмотрения и изучения в RFC, но как показала практика его смело можно игнорировать.
digest-uri — Протокол подключения, для XMPP сервера он состоит из соединения строк "xmpp/" + JID Domain
charset — поддержка кодировки пароля и имени, в нашем случае UTF-8
И самый важный параметр response в котором заключен ключ ответа серверу, включающий в себя пароль и ответные данные в формате MD5 строящийся по определенному алгоритму.
Сервер проверяет ответ на оклик и посылает ответ на ответ в похожем формате (но всё же отличающемся, чтобы клиент мог убедиться в подлинности сервера). Данный механизм слабее системы с открытыми ключами, но лучше простой CRAM-MD5.
Алгоритм вычисления строки ответа response
Алгоритм вычисления строки ответа response имеет следующую формулу:Где:Код: Выделить всё
response-value = HEX( KD ( HEX(H(A1)), { nonce-value, ":" nc-value, ":", cnonce-value, ":", qop-value, ":", HEX(H(A2)) })) A1 = { H( { username-value, ":", realm-value, ":", passwd } ), ":", nonce-value, ":", cnonce-value } A2 = { "AUTHENTICATE:", digest-uri-value }
Выражение { a, b, ... } — означает сложение строк a, b
HEX(n) — 16-байтовый MD5-хеш n, приведенный в 32 байтовую Hex-строку в нижнем регистре. Фактически строковое представление дайджеста MD5.
H(s) — 16-байтовый MD5-хеш строки s
KD(k, s) — объединение данных (строк) k, s
H({k, ":", s}) — 16-байтовый MD5-хеш, полученный в результате сложения строки k, ":", S
Как видите, особо ничего сложного нет.
- руки кривые?
- неправильный алгоритм?
2. есть описание, где присутствует ":" в первой строке
Код: Выделить всё
response-value =
HEX( KD ( HEX(H(A1)), ":" ,
{ nonce-value, ":" nc-value, ":",
cnonce-value, ":", qop-value, ":", HEX(H(A2)) }))
A1 = { H( { username-value, ":", realm-value, ":", passwd } ),
":", nonce-value, ":", cnonce-value }
A2 = { "AUTHENTICATE:", digest-uri-value }
Помогите с реализацией алгоритма расчета response-value