188 # usernames. So we have to generate different hashes for different |
191 # usernames. So we have to generate different hashes for different |
189 # versions. See also: |
192 # versions. See also: |
190 # http://dovecot.org/list/dovecot-news/2009-March/000103.html |
193 # http://dovecot.org/list/dovecot-news/2009-March/000103.html |
191 # http://hg.dovecot.org/dovecot-1.1/rev/2b0043ba89ae |
194 # http://hg.dovecot.org/dovecot-1.1/rev/2b0043ba89ae |
192 if cfg_dget('misc.dovecot_version') >= 0x1010cf00: |
195 if cfg_dget('misc.dovecot_version') >= 0x1010cf00: |
193 md5.update('%s:%s:' % (user.localpart, user.domainname)) |
196 md5.update(user.localpart.encode() + b':' + |
|
197 user.domainname.encode() + b':') |
194 else: |
198 else: |
195 md5.update('%s::' % user) |
199 md5.update('%s::' % user) |
196 md5.update(password) |
200 md5.update(password) |
197 if (scheme in ('PLAIN-MD5', 'DIGEST-MD5') and encoding in DEFAULT_HEX) or \ |
201 if (scheme in ('PLAIN-MD5', 'DIGEST-MD5') and encoding in DEFAULT_HEX) or \ |
198 (scheme == 'LDAP-MD5' and encoding == 'HEX'): |
202 (scheme == 'LDAP-MD5' and encoding == 'HEX'): |
199 digest = md5.hexdigest() |
203 digest = md5.hexdigest() |
200 else: |
204 else: |
201 digest = md5.digest().encode('base64').rstrip() |
205 digest = b64encode(md5.digest()).decode() |
202 return _format_digest(digest, scheme, encoding) |
206 return _format_digest(digest, scheme, encoding) |
203 |
207 |
204 |
208 |
205 def _ntlm_hash(password, scheme, encoding): |
209 def _ntlm_hash(password, scheme, encoding): |
206 """Generates NTLM hashes.""" |
210 """Generates NTLM hashes.""" |
207 md4 = _md4_new() |
211 md4 = _md4_new() |
208 if md4: |
212 if md4: |
209 password = ''.join('%s\x00' % c for c in password) |
213 password = b''.join(bytes(x) |
|
214 for x in zip(password, bytes(len(password)))) |
210 md4.update(password) |
215 md4.update(password) |
211 if encoding in DEFAULT_HEX: |
216 if encoding in DEFAULT_HEX: |
212 digest = md4.hexdigest() |
217 digest = md4.hexdigest() |
213 else: |
218 else: |
214 digest = md4.digest().encode('base64').rstrip() |
219 digest = b64encode(md4.digest()).decode() |
215 return _format_digest(digest, scheme, encoding) |
220 return _format_digest(digest, scheme, encoding) |
216 return _dovecotpw(password, scheme, encoding) |
221 return _dovecotpw(password, scheme, encoding) |
217 |
222 |
218 |
223 |
219 def _sha1_hash(password, scheme, encoding): |
224 def _sha1_hash(password, scheme, encoding): |
220 """Generates SHA1 aka SHA hashes.""" |
225 """Generates SHA1 aka SHA hashes.""" |
221 sha1 = hashlib.sha1(password) |
226 sha1 = hashlib.sha1(password) |
222 if encoding in DEFAULT_B64: |
227 if encoding in DEFAULT_B64: |
223 digest = sha1.digest().encode('base64').rstrip() |
228 digest = b64encode(sha1.digest()).decode() |
224 else: |
229 else: |
225 digest = sha1.hexdigest() |
230 digest = sha1.hexdigest() |
226 return _format_digest(digest, scheme, encoding) |
231 return _format_digest(digest, scheme, encoding) |
227 |
232 |
228 |
233 |
229 def _sha256_hash(password, scheme, encoding): |
234 def _sha256_hash(password, scheme, encoding): |
230 """Generates SHA256 hashes.""" |
235 """Generates SHA256 hashes.""" |
231 sha256 = hashlib.sha256(password) |
236 sha256 = hashlib.sha256(password) |
232 if encoding in DEFAULT_B64: |
237 if encoding in DEFAULT_B64: |
233 digest = sha256.digest().encode('base64').rstrip() |
238 digest = b64encode(sha256.digest()).decode() |
234 else: |
239 else: |
235 digest = sha256.hexdigest() |
240 digest = sha256.hexdigest() |
236 return _format_digest(digest, scheme, encoding) |
241 return _format_digest(digest, scheme, encoding) |
237 |
242 |
238 |
243 |
239 def _sha512_hash(password, scheme, encoding): |
244 def _sha512_hash(password, scheme, encoding): |
240 """Generates SHA512 hashes.""" |
245 """Generates SHA512 hashes.""" |
241 sha512 = hashlib.sha512(password) |
246 sha512 = hashlib.sha512(password) |
242 if encoding in DEFAULT_B64: |
247 if encoding in DEFAULT_B64: |
243 digest = sha512.digest().encode('base64').replace('\n', '') |
248 digest = b64encode(sha512.digest()).decode() |
244 else: |
249 else: |
245 digest = sha512.hexdigest() |
250 digest = sha512.hexdigest() |
246 return _format_digest(digest, scheme, encoding) |
251 return _format_digest(digest, scheme, encoding) |
247 |
252 |
248 |
253 |
249 def _smd5_hash(password, scheme, encoding): |
254 def _smd5_hash(password, scheme, encoding): |
250 """Generates SMD5 (salted PLAIN-MD5) hashes.""" |
255 """Generates SMD5 (salted PLAIN-MD5) hashes.""" |
251 md5 = hashlib.md5(password) |
256 md5 = hashlib.md5(password) |
252 salt = _get_salt(SALTED_ALGO_SALT_LEN) |
257 salt = _get_salt(SALTED_ALGO_SALT_LEN).encode() |
253 md5.update(salt) |
258 md5.update(salt) |
254 if encoding in DEFAULT_B64: |
259 if encoding in DEFAULT_B64: |
255 digest = (md5.digest() + salt).encode('base64').rstrip() |
260 digest = b64encode(md5.digest() + salt).decode() |
256 else: |
261 else: |
257 digest = md5.hexdigest() + salt.encode('hex') |
262 digest = md5.hexdigest() + b2a_hex(salt).decode() |
258 return _format_digest(digest, scheme, encoding) |
263 return _format_digest(digest, scheme, encoding) |
259 |
264 |
260 |
265 |
261 def _ssha1_hash(password, scheme, encoding): |
266 def _ssha1_hash(password, scheme, encoding): |
262 """Generates SSHA (salted SHA/SHA1) hashes.""" |
267 """Generates SSHA (salted SHA/SHA1) hashes.""" |
263 sha1 = hashlib.sha1(password) |
268 sha1 = hashlib.sha1(password) |
264 salt = _get_salt(SALTED_ALGO_SALT_LEN) |
269 salt = _get_salt(SALTED_ALGO_SALT_LEN).encode() |
265 sha1.update(salt) |
270 sha1.update(salt) |
266 if encoding in DEFAULT_B64: |
271 if encoding in DEFAULT_B64: |
267 digest = (sha1.digest() + salt).encode('base64').rstrip() |
272 digest = b64encode(sha1.digest() + salt).decode() |
268 else: |
273 else: |
269 digest = sha1.hexdigest() + salt.encode('hex') |
274 digest = sha1.hexdigest() + b2a_hex(salt).decode() |
270 return _format_digest(digest, scheme, encoding) |
275 return _format_digest(digest, scheme, encoding) |
271 |
276 |
272 |
277 |
273 def _ssha256_hash(password, scheme, encoding): |
278 def _ssha256_hash(password, scheme, encoding): |
274 """Generates SSHA256 (salted SHA256) hashes.""" |
279 """Generates SSHA256 (salted SHA256) hashes.""" |
275 sha256 = hashlib.sha256(password) |
280 sha256 = hashlib.sha256(password) |
276 salt = _get_salt(SALTED_ALGO_SALT_LEN) |
281 salt = _get_salt(SALTED_ALGO_SALT_LEN).encode() |
277 sha256.update(salt) |
282 sha256.update(salt) |
278 if encoding in DEFAULT_B64: |
283 if encoding in DEFAULT_B64: |
279 digest = (sha256.digest() + salt).encode('base64').rstrip() |
284 digest = b64encode(sha256.digest() + salt).decode() |
280 else: |
285 else: |
281 digest = sha256.hexdigest() + salt.encode('hex') |
286 digest = sha256.hexdigest() + b2a_hex(salt).decode() |
282 return _format_digest(digest, scheme, encoding) |
287 return _format_digest(digest, scheme, encoding) |
283 |
288 |
284 |
289 |
285 def _ssha512_hash(password, scheme, encoding): |
290 def _ssha512_hash(password, scheme, encoding): |
286 """Generates SSHA512 (salted SHA512) hashes.""" |
291 """Generates SSHA512 (salted SHA512) hashes.""" |
287 salt = _get_salt(SALTED_ALGO_SALT_LEN) |
292 salt = _get_salt(SALTED_ALGO_SALT_LEN).encode() |
288 sha512 = hashlib.sha512(password + salt) |
293 sha512 = hashlib.sha512(password + salt) |
289 if encoding in DEFAULT_B64: |
294 if encoding in DEFAULT_B64: |
290 digest = (sha512.digest() + salt).encode('base64').replace('\n', '') |
295 digest = b64encode(sha512.digest() + salt).decode() |
291 else: |
296 else: |
292 digest = sha512.hexdigest() + salt.encode('hex') |
297 digest = sha512.hexdigest() + b2a_hex(salt).decode() |
293 return _format_digest(digest, scheme, encoding) |
298 return _format_digest(digest, scheme, encoding) |
294 |
299 |
295 _scheme_info = { |
300 _scheme_info = { |
296 'CLEARTEXT': (_clear_hash, 0x10000f00), |
301 'CLEARTEXT': (_clear_hash, 0x10000f00), |
297 'CRAM-MD5': (_dovecotpw, 0x10000f00), |
302 'CRAM-MD5': (_dovecotpw, 0x10000f00), |