注意:我已经阅读了this question的非常好的答案,但它没有回答我的问题。
我正在尝试在Common Lisp中实现RFC 5802指定的SCRAM-SHA1身份验证标准。在生成客户端最终响应消息时,我遇到了问题。
这是函数的代码(其余函数可用here) - 这是尝试实现RFC第7页所述的算法:
(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=
的{{1}}部分)与示例中的部分完全不同。
我将所有中间变量添加到返回中,以防任何人在这里可以看到出错的地方。不幸的是,没有显示中间变量值的例子,所以我无法比较我得到的替代品。
答案 0 :(得分:5)
RFC 5802: Salted Challenge Response Authentication Mechanism (SCRAM) SASL and GSS-API Mechanisms中样本的中间值位于此答案的底部。
您的p
值过长;您可能将位编码为字符串而不是字节。你应该循环遍历字节块并分别对每个无符号字节进行异或。转换为整数,然后转换为位串,然后返回到八位字符串将失败,因为它可能会删除最重要的零位。一旦你得到了XOR'ed八位字节串,你就可以对其进行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