/usr/share/pyshared/passlib/handlers/sha1_crypt.py is in python-passlib 1.5.3-0ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | """passlib.handlers.sha1_crypt
"""
#=========================================================
#imports
#=========================================================
#core
from hmac import new as hmac
from hashlib import sha1
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
from passlib.utils import h64, handlers as uh, safe_os_crypt, classproperty, \
to_hash_str, to_unicode, bytes, b
from passlib.utils.pbkdf2 import hmac_sha1
#pkg
#local
__all__ = [
]
#=========================================================
#sha1-crypt
#=========================================================
class sha1_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler):
"""This class implements the SHA1-Crypt password hash, and follows the :ref:`password-hash-api`.
It supports a variable-length salt, and a variable number of rounds.
The :meth:`encrypt()` and :meth:`genconfig` methods accept the following optional keywords:
:param salt:
Optional salt string.
If not specified, an 8 character one will be autogenerated (this is recommended).
If specified, it must be 0-64 characters, drawn from the regexp range ``[./0-9A-Za-z]``.
:param salt_size:
Optional number of bytes to use when autogenerating new salts.
Defaults to 8 bytes, but can be any value between 0 and 64.
:param rounds:
Optional number of rounds to use.
Defaults to 40000, must be between 1 and 4294967295, inclusive.
It will use the first available of two possible backends:
* stdlib :func:`crypt()`, if the host OS supports sha1-crypt (NetBSD).
* a pure python implementation of sha1-crypt
You can see which backend is in use by calling the :meth:`get_backend()` method.
"""
#=========================================================
#class attrs
#=========================================================
#--GenericHandler--
name = "sha1_crypt"
setting_kwds = ("salt", "salt_size", "rounds")
ident = u"$sha1$"
checksum_size = 28
checksum_chars = uh.H64_CHARS
#--HasSalt--
default_salt_size = 8
min_salt_size = 0
max_salt_size = 64
salt_chars = uh.H64_CHARS
#--HasRounds--
default_rounds = 40000 #current passlib default
min_rounds = 1 #really, this should be higher.
max_rounds = 4294967295 # 32-bit integer limit
rounds_cost = "linear"
#=========================================================
#formatting
#=========================================================
@classmethod
def from_string(cls, hash):
rounds, salt, chk = uh.parse_mc3(hash, cls.ident, cls.name)
if rounds.startswith("0"):
raise ValueError("invalid sha1-crypt hash (zero-padded rounds)")
return cls(
rounds=int(rounds),
salt=salt,
checksum=chk,
strict=bool(chk),
)
def to_string(self, native=True):
out = u"$sha1$%d$%s" % (self.rounds, self.salt)
if self.checksum:
out += u"$" + self.checksum
return to_hash_str(out) if native else out
#=========================================================
#backend
#=========================================================
backends = ("os_crypt", "builtin")
_has_backend_builtin = True
@classproperty
def _has_backend_os_crypt(cls):
h = u'$sha1$1$Wq3GL2Vp$C8U25GvfHS8qGHimExLaiSFlGkAe'
return bool(safe_os_crypt and safe_os_crypt(u"test",h)[1]==h)
def _calc_checksum_builtin(self, secret):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
rounds = self.rounds
#NOTE: this uses a different format than the hash...
result = u"%s$sha1$%s" % (self.salt, rounds)
result = result.encode("ascii")
r = 0
while r < rounds:
result = hmac_sha1(secret, result)
r += 1
return h64.encode_transposed_bytes(result, self._chk_offsets).decode("ascii")
_chk_offsets = [
2,1,0,
5,4,3,
8,7,6,
11,10,9,
14,13,12,
17,16,15,
0,19,18,
]
def _calc_checksum_os_crypt(self, secret):
ok, hash = safe_os_crypt(secret, self.to_string(native=False))
if ok:
return hash[hash.rindex("$")+1:]
else:
return self._calc_checksum_builtin(secret)
#=========================================================
#eoc
#=========================================================
#=========================================================
#eof
#=========================================================
|