Реализация клиента SCRAM-SHA1, где-то неправильно
Примечание: я уже прочитал очень хороший ответ на этот вопрос, но он не отвечает на мои вопросы.
Я пытаюсь реализовать стандарт аутентификации SCRAM-SHA1, как указано в RFC 5802, в Common Lisp. Я сталкиваюсь с проблемами, когда дело доходит до генерации окончательного ответного сообщения клиента.
Это код функции (остальные функции доступны здесь) - это попытка реализовать алгоритм, как описано на странице 7 RFC:
(defun gen-client-final-message
(&key password client-nonce client-initial-message server-response)
(check-type client-nonce string)
(check-type client-initial-message string)
(check-type server-response string)
(check-type password string)
"Takes a password, the initial client nonce, the initial client message & the server response.
Generates the final client message, and returns it along with the server signature."
(progn
(if (eq nil (parse-server-nonce :nonce client-nonce :response server-response)) NIL)
(let* ((final-message-bare (format nil "c=biws,r=~a" (parse-server-nonce :nonce client-nonce
:response server-response)))
(salted-password (ironclad:pbkdf2-hash-password
(ironclad:ascii-string-to-byte-array password)
:salt (ironclad:ascii-string-to-byte-array
(parse-server-salt :response server-response))
:digest :sha1
:iterations (parse-server-iterations :response server-response)))
(client-key (gen-hmac-digest :key salted-password
:message (ironclad:ascii-string-to-byte-array "Client Key")))
(stored-key (gen-sha1-digest :key client-key))
(auth-message (format nil "~a,~a,~a"
client-initial-message
server-response
final-message-bare))
(client-signature (gen-hmac-digest :key stored-key
:message (ironclad:ascii-string-to-byte-array auth-message)))
(client-proof (integer->bit-vector (logxor (ironclad:octets-to-integer client-key)
(ironclad:octets-to-integer client-signature))))
(server-key (gen-hmac-digest :key salted-password
:message (ironclad:ascii-string-to-byte-array "Server Key")))
(server-signature (gen-hmac-digest :key server-key
:message (ironclad:ascii-string-to-byte-array auth-message)))
(final-message (format nil "~a,p=~a"
final-message-bare
(base64-encode (write-to-string client-proof)))))
(pairlis '(final-message
final-message-bare
salted-password
client-key
stored-key
auth-message
client-signature
client-proof
server-key
server-signature)
(list final-message
final-message-bare
salted-password
client-key
stored-key
auth-message
client-signature
client-proof
server-key
server-signature)))))
В примере разговора в RFC используется имя пользователя user
и пароль pencil
:
C: n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
S: r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,
i=4096
C: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,
p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=
S: v=rmF9pqV8S7suAoZWja4dJRkFsKQ=
Принимая тот же ответ сервера (r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096
) и кормя его в свою функцию, я получаю:
* (cl-scram:gen-client-final-message :password "pencil" :client-nonce "fyko+d2lbbFgONRv9qkxdawL" :client-initial-message "n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL" :server-response "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096")
((CL-SCRAM::SERVER-SIGNATURE
. #(33 115 21 228 67 190 35 238 223 122 117 125 222 242 209 136 175 228 67
151))
(CL-SCRAM::SERVER-KEY
. #(15 224 146 88 179 172 133 43 165 2 204 98 186 144 62 170 205 191 125 49))
(CL-SCRAM::CLIENT-PROOF
. #*1100100111101011000000111010100000010101011001000101011100110001111100001100100010001101001000110101001010101010001011111000100011100001001110100001001110000)
(CL-SCRAM::CLIENT-SIGNATURE
. #(251 9 164 14 244 111 236 112 227 116 148 143 243 255 231 75 58 114 21
88))
(CL-SCRAM::AUTH-MESSAGE
. "n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096,c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j")
(CL-SCRAM::STORED-KEY
. #(233 217 70 96 195 157 101 195 143 186 217 28 53 143 20 218 14 239 43
214))
(CL-SCRAM::CLIENT-KEY
. #(226 52 196 123 246 195 102 150 221 109 133 43 153 170 162 186 38 85 87
40))
(CL-SCRAM::SALTED-PASSWORD
. #(29 150 238 58 82 155 90 95 158 71 192 31 34 154 44 184 166 225 95 125))
(CL-SCRAM::FINAL-MESSAGE-BARE
. "c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j")
(CL-SCRAM::FINAL-MESSAGE
. "c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=IyoxMTAwMTAwMTExMTAxMDExMDAwMDAwMTExMDEwMTAwMDAwMDEwMTAxMDExMDAxMDAwMTAxMDExMTAwMTEwMDAxMTExMTAwMDAxMTAwMTAwMDEwMDAxMTAxMDAxMDAwMTEwMTAxMDAxMDEwMTAxMDEwMDAxMDExMTExMDAwMTAwMDExMTAwMDAxMDAxMTEwMTAwMDAxMDAxMTEwMDAw"))
Как видите, мой client-proof
(p=
часть final-message
) сильно отличается от того, что в примере.
Я добавил все промежуточные переменные в возвращаемый результат на тот случай, если кто-нибудь здесь увидит, что происходит не так. К сожалению, нет примеров, показывающих значения промежуточных переменных, поэтому я не могу сравнить то, что я получаю с альтернативами.
1 ответ
Промежуточные значения для образца в RFC 5802: Механизмы аутентификации ответа на соленый вызов (SCRAM) SASL и GSS-API находятся в нижней части этого ответа.
Ваш p
ценность слишком длинная; вы, вероятно, кодируете биты как строки, а не байты. Вы должны перебрать блоки байтов и XOR каждый неподписанный байт отдельно. Преобразование в целое число, затем в строку битов, а затем обратно в строку октетов завершится неудачей, поскольку, вероятно, удалит наиболее значимые нулевые биты. Получив строку октетов XOR, вы можете кодировать ее с помощью 64-го кода.
Кроме того, вам нужно удалить n,,
с самого начала вашего AuthMessage
, как указано в RFC.
Для будущих разработчиков, без лишних слов, промежуточные значения:
В базе 64:
SaltedPassword: HZbuOlKbWl+eR8AfIposuKbhX30=
ClientKey: 4jTEe/bDZpbdbYUrmaqiuiZVVyg=
StoredKey: 6dlGYMOdZcOPutkcNY8U2g7vK9Y=
AuthMessage: n=user,r=fyko+d2lbbFgONRv9qkxdawL,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096,c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j
ClientSignature: XXE4xIawv6vfSePi2ovW5cedthM=
ClientProof: v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=
Использование десятичных массивов:
SaltedPassword: 29 150 238 58 82 155 90 95 158 71 192 31 34 154 44 184 166 225 95 125
ClientKey: 226 52 196 123 246 195 102 150 221 109 133 43 153 170 162 186 38 85 87 40
StoredKey: 233 217 70 96 195 157 101 195 143 186 217 28 53 143 20 218 14 239 43 214
AuthMessage: n=user,r=fyko+d2lbbFgONRv9qkxdawL,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096,c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j
ClientSignature: 93 113 56 196 134 176 191 171 223 73 227 226 218 139 214 229 199 157 182 19
ClientProof: 191 69 252 191 112 115 217 61 2 36 102 201 67 33 116 95 225 200 225 59