实现SCRAM-SHA1客户端,在某处出错

时间:2015-09-08 23:10:27

标签: authentication cryptography common-lisp sasl-scram

注意:我已经阅读了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-proofp=的{​​{1}}部分)与示例中的部分完全不同。

我将所有中间变量添加到返回中,以防任何人在这里可以看到出错的地方。不幸的是,没有显示中间变量值的例子,所以我无法比较我得到的替代品。

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