Software /
code /
prosody
Comparison
util/sasl/scram.lua @ 3214:a69d8021b1db
Merge with Tobias.
author | Waqas Hussain <waqas20@gmail.com> |
---|---|
date | Wed, 09 Jun 2010 21:34:32 +0500 |
parent | 3206:ff1d3f751da1 |
child | 3374:ce52f1d5cb74 |
comparison
equal
deleted
inserted
replaced
3204:7a15cbf23c5b | 3214:a69d8021b1db |
---|---|
33 Supported Authentication Backends | 33 Supported Authentication Backends |
34 | 34 |
35 scram_{MECH}: | 35 scram_{MECH}: |
36 -- MECH being a standard hash name (like those at IANA's hash registry) with '-' replaced with '_' | 36 -- MECH being a standard hash name (like those at IANA's hash registry) with '-' replaced with '_' |
37 function(username, realm) | 37 function(username, realm) |
38 return salted_password, iteration_count, salt, state; | 38 return stored_key, server_key, iteration_count, salt, state; |
39 end | 39 end |
40 ]] | 40 ]] |
41 | 41 |
42 local default_i = 4096 | 42 local default_i = 4096 |
43 | 43 |
95 | 95 |
96 local function hashprep(hashname) | 96 local function hashprep(hashname) |
97 return hashname:lower():gsub("-", "_"); | 97 return hashname:lower():gsub("-", "_"); |
98 end | 98 end |
99 | 99 |
100 function saltedPasswordSHA1(password, salt, iteration_count) | 100 function getAuthenticationDatabaseSHA1(password, salt, iteration_count) |
101 local salted_password | |
102 if type(password) ~= "string" or type(salt) ~= "string" or type(iteration_count) ~= "number" then | 101 if type(password) ~= "string" or type(salt) ~= "string" or type(iteration_count) ~= "number" then |
103 return false, "inappropriate argument types" | 102 return false, "inappropriate argument types" |
104 end | 103 end |
105 if iteration_count < 4096 then | 104 if iteration_count < 4096 then |
106 log("warn", "Iteration count < 4096 which is the suggested minimum according to RFC 5802.") | 105 log("warn", "Iteration count < 4096 which is the suggested minimum according to RFC 5802.") |
107 end | 106 end |
108 | 107 local salted_password = Hi(hmac_sha1, password, salt, iteration_count); |
109 return true, Hi(hmac_sha1, password, salt, iteration_count); | 108 local stored_key = sha1(hmac_sha1(salted_password, "Client Key")) |
109 local server_key = hmac_sha1(salted_password, "Server Key"); | |
110 return true, stored_key, server_key | |
110 end | 111 end |
111 | 112 |
112 local function scram_gen(hash_name, H_f, HMAC_f) | 113 local function scram_gen(hash_name, H_f, HMAC_f) |
113 local function scram_hash(self, message) | 114 local function scram_hash(self, message) |
114 if not self.state then self["state"] = {} end | 115 if not self.state then self["state"] = {} end |
154 | 155 |
155 self.state.salt = generate_uuid(); | 156 self.state.salt = generate_uuid(); |
156 self.state.iteration_count = default_i; | 157 self.state.iteration_count = default_i; |
157 | 158 |
158 local succ = false; | 159 local succ = false; |
159 succ, self.state.salted_password = saltedPasswordSHA1(password, self.state.salt, default_i, self.state.iteration_count); | 160 succ, self.state.stored_key, self.state.server_key = getAuthenticationDatabaseSHA1(password, self.state.salt, default_i, self.state.iteration_count); |
160 if not succ then | 161 if not succ then |
161 log("error", "Generating salted password failed. Reason: %s", self.state.salted_password); | 162 log("error", "Generating authentication database failed. Reason: %s", self.state.stored_key); |
162 return "failure", "temporary-auth-failure"; | 163 return "failure", "temporary-auth-failure"; |
163 end | 164 end |
164 elseif self.profile["scram_"..hashprep(hash_name)] then | 165 elseif self.profile["scram_"..hashprep(hash_name)] then |
165 local salted_password, iteration_count, salt, state = self.profile["scram_"..hashprep(hash_name)](self.state.name, self.realm); | 166 local stored_key, server_key, iteration_count, salt, state = self.profile["scram_"..hashprep(hash_name)](self.state.name, self.realm); |
166 if state == nil then return "failure", "not-authorized" | 167 if state == nil then return "failure", "not-authorized" |
167 elseif state == false then return "failure", "account-disabled" end | 168 elseif state == false then return "failure", "account-disabled" end |
168 | 169 |
169 self.state.salted_password = salted_password; | 170 self.state.stored_key = stored_key; |
171 self.state.server_key = server_key; | |
170 self.state.iteration_count = iteration_count; | 172 self.state.iteration_count = iteration_count; |
171 self.state.salt = salt | 173 self.state.salt = salt |
172 end | 174 end |
173 | 175 |
174 local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..self.state.iteration_count; | 176 local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..self.state.iteration_count; |
186 | 188 |
187 if self.state.nonce ~= self.state.clientnonce..self.state.servernonce then | 189 if self.state.nonce ~= self.state.clientnonce..self.state.servernonce then |
188 return "failure", "malformed-request", "Wrong nonce in client-final-message."; | 190 return "failure", "malformed-request", "Wrong nonce in client-final-message."; |
189 end | 191 end |
190 | 192 |
191 local SaltedPassword = self.state.salted_password; | 193 local ServerKey = self.state.server_key; |
192 local ClientKey = HMAC_f(SaltedPassword, "Client Key") | 194 local StoredKey = self.state.stored_key; |
193 local ServerKey = HMAC_f(SaltedPassword, "Server Key") | 195 |
194 local StoredKey = H_f(ClientKey) | |
195 local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+") | 196 local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+") |
196 local ClientSignature = HMAC_f(StoredKey, AuthMessage) | 197 local ClientSignature = HMAC_f(StoredKey, AuthMessage) |
197 local ClientProof = binaryXOR(ClientKey, ClientSignature) | 198 local ClientKey = binaryXOR(ClientSignature, base64.decode(self.state.proof)) |
198 local ServerSignature = HMAC_f(ServerKey, AuthMessage) | 199 local ServerSignature = HMAC_f(ServerKey, AuthMessage) |
199 | 200 |
200 if base64.encode(ClientProof) == self.state.proof then | 201 if StoredKey == H_f(ClientKey) then |
201 local server_final_message = "v="..base64.encode(ServerSignature); | 202 local server_final_message = "v="..base64.encode(ServerSignature); |
202 self["username"] = self.state.name; | 203 self["username"] = self.state.name; |
203 return "success", server_final_message; | 204 return "success", server_final_message; |
204 else | 205 else |
205 return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated."; | 206 return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated."; |