__init__.py 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220
  1. """passlib.utils -- helpers for writing password hashes"""
  2. #=============================================================================
  3. # imports
  4. #=============================================================================
  5. from passlib.utils.compat import JYTHON
  6. # core
  7. from binascii import b2a_base64, a2b_base64, Error as _BinAsciiError
  8. from base64 import b64encode, b64decode
  9. try:
  10. from collections.abc import Sequence
  11. from collections.abc import Iterable
  12. except ImportError:
  13. # py2 compat
  14. from collections import Sequence
  15. from collections import Iterable
  16. from codecs import lookup as _lookup_codec
  17. from functools import update_wrapper
  18. import itertools
  19. import inspect
  20. import logging; log = logging.getLogger(__name__)
  21. import math
  22. import os
  23. import sys
  24. import random
  25. import re
  26. if JYTHON: # pragma: no cover -- runtime detection
  27. # Jython 2.5.2 lacks stringprep module -
  28. # see http://bugs.jython.org/issue1758320
  29. try:
  30. import stringprep
  31. except ImportError:
  32. stringprep = None
  33. _stringprep_missing_reason = "not present under Jython"
  34. else:
  35. import stringprep
  36. import time
  37. if stringprep:
  38. import unicodedata
  39. try:
  40. import threading
  41. except ImportError:
  42. # module optional before py37
  43. threading = None
  44. import timeit
  45. import types
  46. from warnings import warn
  47. # site
  48. # pkg
  49. from passlib.utils.binary import (
  50. # [remove these aliases in 2.0]
  51. BASE64_CHARS, AB64_CHARS, HASH64_CHARS, BCRYPT_CHARS,
  52. Base64Engine, LazyBase64Engine, h64, h64big, bcrypt64,
  53. ab64_encode, ab64_decode, b64s_encode, b64s_decode
  54. )
  55. from passlib.utils.decor import (
  56. # [remove these aliases in 2.0]
  57. deprecated_function,
  58. deprecated_method,
  59. memoized_property,
  60. classproperty,
  61. hybrid_method,
  62. )
  63. from passlib.exc import ExpectedStringError, ExpectedTypeError
  64. from passlib.utils.compat import (add_doc, join_bytes, join_byte_values,
  65. join_byte_elems, irange, imap, PY3, u,
  66. join_unicode, unicode, byte_elem_value, nextgetter,
  67. unicode_or_str, unicode_or_bytes_types,
  68. get_method_function, suppress_cause, PYPY)
  69. # local
  70. __all__ = [
  71. # constants
  72. 'JYTHON',
  73. 'sys_bits',
  74. 'unix_crypt_schemes',
  75. 'rounds_cost_values',
  76. # unicode helpers
  77. 'consteq',
  78. 'saslprep',
  79. # bytes helpers
  80. "xor_bytes",
  81. "render_bytes",
  82. # encoding helpers
  83. 'is_same_codec',
  84. 'is_ascii_safe',
  85. 'to_bytes',
  86. 'to_unicode',
  87. 'to_native_str',
  88. # host OS
  89. 'has_crypt',
  90. 'test_crypt',
  91. 'safe_crypt',
  92. 'tick',
  93. # randomness
  94. 'rng',
  95. 'getrandbytes',
  96. 'getrandstr',
  97. 'generate_password',
  98. # object type / interface tests
  99. 'is_crypt_handler',
  100. 'is_crypt_context',
  101. 'has_rounds_info',
  102. 'has_salt_info',
  103. ]
  104. #=============================================================================
  105. # constants
  106. #=============================================================================
  107. # bitsize of system architecture (32 or 64)
  108. sys_bits = int(math.log(sys.maxsize if PY3 else sys.maxint, 2) + 1.5)
  109. # list of hashes algs supported by crypt() on at least one OS.
  110. # XXX: move to .registry for passlib 2.0?
  111. unix_crypt_schemes = [
  112. "sha512_crypt", "sha256_crypt",
  113. "sha1_crypt", "bcrypt",
  114. "md5_crypt",
  115. # "bsd_nthash",
  116. "bsdi_crypt", "des_crypt",
  117. ]
  118. # list of rounds_cost constants
  119. rounds_cost_values = [ "linear", "log2" ]
  120. # legacy import, will be removed in 1.8
  121. from passlib.exc import MissingBackendError
  122. # internal helpers
  123. _BEMPTY = b''
  124. _UEMPTY = u("")
  125. _USPACE = u(" ")
  126. # maximum password size which passlib will allow; see exc.PasswordSizeError
  127. MAX_PASSWORD_SIZE = int(os.environ.get("PASSLIB_MAX_PASSWORD_SIZE") or 4096)
  128. #=============================================================================
  129. # type helpers
  130. #=============================================================================
  131. class SequenceMixin(object):
  132. """
  133. helper which lets result object act like a fixed-length sequence.
  134. subclass just needs to provide :meth:`_as_tuple()`.
  135. """
  136. def _as_tuple(self):
  137. raise NotImplementedError("implement in subclass")
  138. def __repr__(self):
  139. return repr(self._as_tuple())
  140. def __getitem__(self, idx):
  141. return self._as_tuple()[idx]
  142. def __iter__(self):
  143. return iter(self._as_tuple())
  144. def __len__(self):
  145. return len(self._as_tuple())
  146. def __eq__(self, other):
  147. return self._as_tuple() == other
  148. def __ne__(self, other):
  149. return not self.__eq__(other)
  150. if PY3:
  151. # getargspec() is deprecated, use this under py3.
  152. # even though it's a lot more awkward to get basic info :|
  153. _VAR_KEYWORD = inspect.Parameter.VAR_KEYWORD
  154. _VAR_ANY_SET = set([_VAR_KEYWORD, inspect.Parameter.VAR_POSITIONAL])
  155. def accepts_keyword(func, key):
  156. """test if function accepts specified keyword"""
  157. params = inspect.signature(get_method_function(func)).parameters
  158. if not params:
  159. return False
  160. arg = params.get(key)
  161. if arg and arg.kind not in _VAR_ANY_SET:
  162. return True
  163. # XXX: annoying what we have to do to determine if VAR_KWDS in use.
  164. return params[list(params)[-1]].kind == _VAR_KEYWORD
  165. else:
  166. def accepts_keyword(func, key):
  167. """test if function accepts specified keyword"""
  168. spec = inspect.getargspec(get_method_function(func))
  169. return key in spec.args or spec.keywords is not None
  170. def update_mixin_classes(target, add=None, remove=None, append=False,
  171. before=None, after=None, dryrun=False):
  172. """
  173. helper to update mixin classes installed in target class.
  174. :param target:
  175. target class whose bases will be modified.
  176. :param add:
  177. class / classes to install into target's base class list.
  178. :param remove:
  179. class / classes to remove from target's base class list.
  180. :param append:
  181. by default, prepends mixins to front of list.
  182. if True, appends to end of list instead.
  183. :param after:
  184. optionally make sure all mixins are inserted after
  185. this class / classes.
  186. :param before:
  187. optionally make sure all mixins are inserted before
  188. this class / classes.
  189. :param dryrun:
  190. optionally perform all calculations / raise errors,
  191. but don't actually modify the class.
  192. """
  193. if isinstance(add, type):
  194. add = [add]
  195. bases = list(target.__bases__)
  196. # strip out requested mixins
  197. if remove:
  198. if isinstance(remove, type):
  199. remove = [remove]
  200. for mixin in remove:
  201. if add and mixin in add:
  202. continue
  203. if mixin in bases:
  204. bases.remove(mixin)
  205. # add requested mixins
  206. if add:
  207. for mixin in add:
  208. # if mixin already present (explicitly or not), leave alone
  209. if any(issubclass(base, mixin) for base in bases):
  210. continue
  211. # determine insertion point
  212. if append:
  213. for idx, base in enumerate(bases):
  214. if issubclass(mixin, base):
  215. # don't insert mixin after one of it's own bases
  216. break
  217. if before and issubclass(base, before):
  218. # don't insert mixin after any <before> classes.
  219. break
  220. else:
  221. # append to end
  222. idx = len(bases)
  223. elif after:
  224. for end_idx, base in enumerate(reversed(bases)):
  225. if issubclass(base, after):
  226. # don't insert mixin before any <after> classes.
  227. idx = len(bases) - end_idx
  228. assert bases[idx-1] == base
  229. break
  230. else:
  231. idx = 0
  232. else:
  233. # insert at start
  234. idx = 0
  235. # insert mixin
  236. bases.insert(idx, mixin)
  237. # modify class
  238. if not dryrun:
  239. target.__bases__ = tuple(bases)
  240. #=============================================================================
  241. # collection helpers
  242. #=============================================================================
  243. def batch(source, size):
  244. """
  245. split iterable into chunks of <size> elements.
  246. """
  247. if size < 1:
  248. raise ValueError("size must be positive integer")
  249. if isinstance(source, Sequence):
  250. end = len(source)
  251. i = 0
  252. while i < end:
  253. n = i + size
  254. yield source[i:n]
  255. i = n
  256. elif isinstance(source, Iterable):
  257. itr = iter(source)
  258. while True:
  259. chunk_itr = itertools.islice(itr, size)
  260. try:
  261. first = next(chunk_itr)
  262. except StopIteration:
  263. break
  264. yield itertools.chain((first,), chunk_itr)
  265. else:
  266. raise TypeError("source must be iterable")
  267. #=============================================================================
  268. # unicode helpers
  269. #=============================================================================
  270. # XXX: should this be moved to passlib.crypto, or compat backports?
  271. def consteq(left, right):
  272. """Check two strings/bytes for equality.
  273. This function uses an approach designed to prevent
  274. timing analysis, making it appropriate for cryptography.
  275. a and b must both be of the same type: either str (ASCII only),
  276. or any type that supports the buffer protocol (e.g. bytes).
  277. Note: If a and b are of different lengths, or if an error occurs,
  278. a timing attack could theoretically reveal information about the
  279. types and lengths of a and b--but not their values.
  280. """
  281. # NOTE:
  282. # resources & discussions considered in the design of this function:
  283. # hmac timing attack --
  284. # http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/
  285. # python developer discussion surrounding similar function --
  286. # http://bugs.python.org/issue15061
  287. # http://bugs.python.org/issue14955
  288. # validate types
  289. if isinstance(left, unicode):
  290. if not isinstance(right, unicode):
  291. raise TypeError("inputs must be both unicode or both bytes")
  292. is_py3_bytes = False
  293. elif isinstance(left, bytes):
  294. if not isinstance(right, bytes):
  295. raise TypeError("inputs must be both unicode or both bytes")
  296. is_py3_bytes = PY3
  297. else:
  298. raise TypeError("inputs must be both unicode or both bytes")
  299. # do size comparison.
  300. # NOTE: the double-if construction below is done deliberately, to ensure
  301. # the same number of operations (including branches) is performed regardless
  302. # of whether left & right are the same size.
  303. same_size = (len(left) == len(right))
  304. if same_size:
  305. # if sizes are the same, setup loop to perform actual check of contents.
  306. tmp = left
  307. result = 0
  308. if not same_size:
  309. # if sizes aren't the same, set 'result' so equality will fail regardless
  310. # of contents. then, to ensure we do exactly 'len(right)' iterations
  311. # of the loop, just compare 'right' against itself.
  312. tmp = right
  313. result = 1
  314. # run constant-time string comparision
  315. # TODO: use izip instead (but first verify it's faster than zip for this case)
  316. if is_py3_bytes:
  317. for l,r in zip(tmp, right):
  318. result |= l ^ r
  319. else:
  320. for l,r in zip(tmp, right):
  321. result |= ord(l) ^ ord(r)
  322. return result == 0
  323. # keep copy of this around since stdlib's version throws error on non-ascii chars in unicode strings.
  324. # our version does, but suffers from some underlying VM issues. but something is better than
  325. # nothing for plaintext hashes, which need this. everything else should use consteq(),
  326. # since the stdlib one is going to be as good / better in the general case.
  327. str_consteq = consteq
  328. try:
  329. # for py3.3 and up, use the stdlib version
  330. from hmac import compare_digest as consteq
  331. except ImportError:
  332. pass
  333. # TODO: could check for cryptography package's version,
  334. # but only operates on bytes, so would need a wrapper,
  335. # or separate consteq() into a unicode & a bytes variant.
  336. # from cryptography.hazmat.primitives.constant_time import bytes_eq as consteq
  337. def splitcomma(source, sep=","):
  338. """split comma-separated string into list of elements,
  339. stripping whitespace.
  340. """
  341. source = source.strip()
  342. if source.endswith(sep):
  343. source = source[:-1]
  344. if not source:
  345. return []
  346. return [ elem.strip() for elem in source.split(sep) ]
  347. def saslprep(source, param="value"):
  348. """Normalizes unicode strings using SASLPrep stringprep profile.
  349. The SASLPrep profile is defined in :rfc:`4013`.
  350. It provides a uniform scheme for normalizing unicode usernames
  351. and passwords before performing byte-value sensitive operations
  352. such as hashing. Among other things, it normalizes diacritic
  353. representations, removes non-printing characters, and forbids
  354. invalid characters such as ``\\n``. Properly internationalized
  355. applications should run user passwords through this function
  356. before hashing.
  357. :arg source:
  358. unicode string to normalize & validate
  359. :param param:
  360. Optional noun identifying source parameter in error messages
  361. (Defaults to the string ``"value"``). This is mainly useful to make the caller's error
  362. messages make more sense contextually.
  363. :raises ValueError:
  364. if any characters forbidden by the SASLPrep profile are encountered.
  365. :raises TypeError:
  366. if input is not :class:`!unicode`
  367. :returns:
  368. normalized unicode string
  369. .. note::
  370. This function is not available under Jython,
  371. as the Jython stdlib is missing the :mod:`!stringprep` module
  372. (`Jython issue 1758320 <http://bugs.jython.org/issue1758320>`_).
  373. .. versionadded:: 1.6
  374. """
  375. # saslprep - http://tools.ietf.org/html/rfc4013
  376. # stringprep - http://tools.ietf.org/html/rfc3454
  377. # http://docs.python.org/library/stringprep.html
  378. # validate type
  379. # XXX: support bytes (e.g. run through want_unicode)?
  380. # might be easier to just integrate this into cryptcontext.
  381. if not isinstance(source, unicode):
  382. raise TypeError("input must be unicode string, not %s" %
  383. (type(source),))
  384. # mapping stage
  385. # - map non-ascii spaces to U+0020 (stringprep C.1.2)
  386. # - strip 'commonly mapped to nothing' chars (stringprep B.1)
  387. in_table_c12 = stringprep.in_table_c12
  388. in_table_b1 = stringprep.in_table_b1
  389. data = join_unicode(
  390. _USPACE if in_table_c12(c) else c
  391. for c in source
  392. if not in_table_b1(c)
  393. )
  394. # normalize to KC form
  395. data = unicodedata.normalize('NFKC', data)
  396. if not data:
  397. return _UEMPTY
  398. # check for invalid bi-directional strings.
  399. # stringprep requires the following:
  400. # - chars in C.8 must be prohibited.
  401. # - if any R/AL chars in string:
  402. # - no L chars allowed in string
  403. # - first and last must be R/AL chars
  404. # this checks if start/end are R/AL chars. if so, prohibited loop
  405. # will forbid all L chars. if not, prohibited loop will forbid all
  406. # R/AL chars instead. in both cases, prohibited loop takes care of C.8.
  407. is_ral_char = stringprep.in_table_d1
  408. if is_ral_char(data[0]):
  409. if not is_ral_char(data[-1]):
  410. raise ValueError("malformed bidi sequence in " + param)
  411. # forbid L chars within R/AL sequence.
  412. is_forbidden_bidi_char = stringprep.in_table_d2
  413. else:
  414. # forbid R/AL chars if start not setup correctly; L chars allowed.
  415. is_forbidden_bidi_char = is_ral_char
  416. # check for prohibited output - stringprep tables A.1, B.1, C.1.2, C.2 - C.9
  417. in_table_a1 = stringprep.in_table_a1
  418. in_table_c21_c22 = stringprep.in_table_c21_c22
  419. in_table_c3 = stringprep.in_table_c3
  420. in_table_c4 = stringprep.in_table_c4
  421. in_table_c5 = stringprep.in_table_c5
  422. in_table_c6 = stringprep.in_table_c6
  423. in_table_c7 = stringprep.in_table_c7
  424. in_table_c8 = stringprep.in_table_c8
  425. in_table_c9 = stringprep.in_table_c9
  426. for c in data:
  427. # check for chars mapping stage should have removed
  428. assert not in_table_b1(c), "failed to strip B.1 in mapping stage"
  429. assert not in_table_c12(c), "failed to replace C.1.2 in mapping stage"
  430. # check for forbidden chars
  431. if in_table_a1(c):
  432. raise ValueError("unassigned code points forbidden in " + param)
  433. if in_table_c21_c22(c):
  434. raise ValueError("control characters forbidden in " + param)
  435. if in_table_c3(c):
  436. raise ValueError("private use characters forbidden in " + param)
  437. if in_table_c4(c):
  438. raise ValueError("non-char code points forbidden in " + param)
  439. if in_table_c5(c):
  440. raise ValueError("surrogate codes forbidden in " + param)
  441. if in_table_c6(c):
  442. raise ValueError("non-plaintext chars forbidden in " + param)
  443. if in_table_c7(c):
  444. # XXX: should these have been caught by normalize?
  445. # if so, should change this to an assert
  446. raise ValueError("non-canonical chars forbidden in " + param)
  447. if in_table_c8(c):
  448. raise ValueError("display-modifying / deprecated chars "
  449. "forbidden in" + param)
  450. if in_table_c9(c):
  451. raise ValueError("tagged characters forbidden in " + param)
  452. # do bidi constraint check chosen by bidi init, above
  453. if is_forbidden_bidi_char(c):
  454. raise ValueError("forbidden bidi character in " + param)
  455. return data
  456. # replace saslprep() with stub when stringprep is missing
  457. if stringprep is None: # pragma: no cover -- runtime detection
  458. def saslprep(source, param="value"):
  459. """stub for saslprep()"""
  460. raise NotImplementedError("saslprep() support requires the 'stringprep' "
  461. "module, which is " + _stringprep_missing_reason)
  462. #=============================================================================
  463. # bytes helpers
  464. #=============================================================================
  465. def render_bytes(source, *args):
  466. """Peform ``%`` formating using bytes in a uniform manner across Python 2/3.
  467. This function is motivated by the fact that
  468. :class:`bytes` instances do not support ``%`` or ``{}`` formatting under Python 3.
  469. This function is an attempt to provide a replacement:
  470. it converts everything to unicode (decoding bytes instances as ``latin-1``),
  471. performs the required formatting, then encodes the result to ``latin-1``.
  472. Calling ``render_bytes(source, *args)`` should function roughly the same as
  473. ``source % args`` under Python 2.
  474. .. todo::
  475. python >= 3.5 added back limited support for bytes %,
  476. can revisit when 3.3/3.4 is dropped.
  477. """
  478. if isinstance(source, bytes):
  479. source = source.decode("latin-1")
  480. result = source % tuple(arg.decode("latin-1") if isinstance(arg, bytes)
  481. else arg for arg in args)
  482. return result.encode("latin-1")
  483. if PY3:
  484. # new in py32
  485. def bytes_to_int(value):
  486. return int.from_bytes(value, 'big')
  487. def int_to_bytes(value, count):
  488. return value.to_bytes(count, 'big')
  489. else:
  490. # XXX: can any of these be sped up?
  491. from binascii import hexlify, unhexlify
  492. def bytes_to_int(value):
  493. return int(hexlify(value),16)
  494. def int_to_bytes(value, count):
  495. return unhexlify(('%%0%dx' % (count<<1)) % value)
  496. add_doc(bytes_to_int, "decode byte string as single big-endian integer")
  497. add_doc(int_to_bytes, "encode integer as single big-endian byte string")
  498. def xor_bytes(left, right):
  499. """Perform bitwise-xor of two byte strings (must be same size)"""
  500. return int_to_bytes(bytes_to_int(left) ^ bytes_to_int(right), len(left))
  501. def repeat_string(source, size):
  502. """
  503. repeat or truncate <source> string, so it has length <size>
  504. """
  505. mult = 1 + (size - 1) // len(source)
  506. return (source * mult)[:size]
  507. def utf8_repeat_string(source, size):
  508. """
  509. variant of repeat_string() which truncates to nearest UTF8 boundary.
  510. """
  511. mult = 1 + (size - 1) // len(source)
  512. return utf8_truncate(source * mult, size)
  513. _BNULL = b"\x00"
  514. _UNULL = u("\x00")
  515. def right_pad_string(source, size, pad=None):
  516. """right-pad or truncate <source> string, so it has length <size>"""
  517. cur = len(source)
  518. if size > cur:
  519. if pad is None:
  520. pad = _UNULL if isinstance(source, unicode) else _BNULL
  521. return source+pad*(size-cur)
  522. else:
  523. return source[:size]
  524. def utf8_truncate(source, index):
  525. """
  526. helper to truncate UTF8 byte string to nearest character boundary ON OR AFTER <index>.
  527. returned prefix will always have length of at least <index>, and will stop on the
  528. first byte that's not a UTF8 continuation byte (128 - 191 inclusive).
  529. since utf8 should never take more than 4 bytes to encode known unicode values,
  530. we can stop after ``index+3`` is reached.
  531. :param bytes source:
  532. :param int index:
  533. :rtype: bytes
  534. """
  535. # general approach:
  536. #
  537. # * UTF8 bytes will have high two bits (0xC0) as one of:
  538. # 00 -- ascii char
  539. # 01 -- ascii char
  540. # 10 -- continuation of multibyte char
  541. # 11 -- start of multibyte char.
  542. # thus we can cut on anything where high bits aren't "10" (0x80; continuation byte)
  543. #
  544. # * UTF8 characters SHOULD always be 1 to 4 bytes, though they may be unbounded.
  545. # so we just keep going until first non-continuation byte is encountered, or end of str.
  546. # this should work predictably even for malformed/non UTF8 inputs.
  547. if not isinstance(source, bytes):
  548. raise ExpectedTypeError(source, bytes, "source")
  549. # validate index
  550. end = len(source)
  551. if index < 0:
  552. index = max(0, index + end)
  553. if index >= end:
  554. return source
  555. # can stop search after 4 bytes, won't ever have longer utf8 sequence.
  556. end = min(index + 3, end)
  557. # loop until we find non-continuation byte
  558. while index < end:
  559. if byte_elem_value(source[index]) & 0xC0 != 0x80:
  560. # found single-char byte, or start-char byte.
  561. break
  562. # else: found continuation byte.
  563. index += 1
  564. else:
  565. assert index == end
  566. # truncate at final index
  567. result = source[:index]
  568. def sanity_check():
  569. # try to decode source
  570. try:
  571. text = source.decode("utf-8")
  572. except UnicodeDecodeError:
  573. # if source isn't valid utf8, byte level match is enough
  574. return True
  575. # validate that result was cut on character boundary
  576. assert text.startswith(result.decode("utf-8"))
  577. return True
  578. assert sanity_check()
  579. return result
  580. #=============================================================================
  581. # encoding helpers
  582. #=============================================================================
  583. _ASCII_TEST_BYTES = b"\x00\n aA:#!\x7f"
  584. _ASCII_TEST_UNICODE = _ASCII_TEST_BYTES.decode("ascii")
  585. def is_ascii_codec(codec):
  586. """Test if codec is compatible with 7-bit ascii (e.g. latin-1, utf-8; but not utf-16)"""
  587. return _ASCII_TEST_UNICODE.encode(codec) == _ASCII_TEST_BYTES
  588. def is_same_codec(left, right):
  589. """Check if two codec names are aliases for same codec"""
  590. if left == right:
  591. return True
  592. if not (left and right):
  593. return False
  594. return _lookup_codec(left).name == _lookup_codec(right).name
  595. _B80 = b'\x80'[0]
  596. _U80 = u('\x80')
  597. def is_ascii_safe(source):
  598. """Check if string (bytes or unicode) contains only 7-bit ascii"""
  599. r = _B80 if isinstance(source, bytes) else _U80
  600. return all(c < r for c in source)
  601. def to_bytes(source, encoding="utf-8", param="value", source_encoding=None):
  602. """Helper to normalize input to bytes.
  603. :arg source:
  604. Source bytes/unicode to process.
  605. :arg encoding:
  606. Target encoding (defaults to ``"utf-8"``).
  607. :param param:
  608. Optional name of variable/noun to reference when raising errors
  609. :param source_encoding:
  610. If this is specified, and the source is bytes,
  611. the source will be transcoded from *source_encoding* to *encoding*
  612. (via unicode).
  613. :raises TypeError: if source is not unicode or bytes.
  614. :returns:
  615. * unicode strings will be encoded using *encoding*, and returned.
  616. * if *source_encoding* is not specified, byte strings will be
  617. returned unchanged.
  618. * if *source_encoding* is specified, byte strings will be transcoded
  619. to *encoding*.
  620. """
  621. assert encoding
  622. if isinstance(source, bytes):
  623. if source_encoding and not is_same_codec(source_encoding, encoding):
  624. return source.decode(source_encoding).encode(encoding)
  625. else:
  626. return source
  627. elif isinstance(source, unicode):
  628. return source.encode(encoding)
  629. else:
  630. raise ExpectedStringError(source, param)
  631. def to_unicode(source, encoding="utf-8", param="value"):
  632. """Helper to normalize input to unicode.
  633. :arg source:
  634. source bytes/unicode to process.
  635. :arg encoding:
  636. encoding to use when decoding bytes instances.
  637. :param param:
  638. optional name of variable/noun to reference when raising errors.
  639. :raises TypeError: if source is not unicode or bytes.
  640. :returns:
  641. * returns unicode strings unchanged.
  642. * returns bytes strings decoded using *encoding*
  643. """
  644. assert encoding
  645. if isinstance(source, unicode):
  646. return source
  647. elif isinstance(source, bytes):
  648. return source.decode(encoding)
  649. else:
  650. raise ExpectedStringError(source, param)
  651. if PY3:
  652. def to_native_str(source, encoding="utf-8", param="value"):
  653. if isinstance(source, bytes):
  654. return source.decode(encoding)
  655. elif isinstance(source, unicode):
  656. return source
  657. else:
  658. raise ExpectedStringError(source, param)
  659. else:
  660. def to_native_str(source, encoding="utf-8", param="value"):
  661. if isinstance(source, bytes):
  662. return source
  663. elif isinstance(source, unicode):
  664. return source.encode(encoding)
  665. else:
  666. raise ExpectedStringError(source, param)
  667. add_doc(to_native_str,
  668. """Take in unicode or bytes, return native string.
  669. Python 2: encodes unicode using specified encoding, leaves bytes alone.
  670. Python 3: leaves unicode alone, decodes bytes using specified encoding.
  671. :raises TypeError: if source is not unicode or bytes.
  672. :arg source:
  673. source unicode or bytes string.
  674. :arg encoding:
  675. encoding to use when encoding unicode or decoding bytes.
  676. this defaults to ``"utf-8"``.
  677. :param param:
  678. optional name of variable/noun to reference when raising errors.
  679. :returns: :class:`str` instance
  680. """)
  681. @deprecated_function(deprecated="1.6", removed="1.7")
  682. def to_hash_str(source, encoding="ascii"): # pragma: no cover -- deprecated & unused
  683. """deprecated, use to_native_str() instead"""
  684. return to_native_str(source, encoding, param="hash")
  685. _true_set = set("true t yes y on 1 enable enabled".split())
  686. _false_set = set("false f no n off 0 disable disabled".split())
  687. _none_set = set(["", "none"])
  688. def as_bool(value, none=None, param="boolean"):
  689. """
  690. helper to convert value to boolean.
  691. recognizes strings such as "true", "false"
  692. """
  693. assert none in [True, False, None]
  694. if isinstance(value, unicode_or_bytes_types):
  695. clean = value.lower().strip()
  696. if clean in _true_set:
  697. return True
  698. if clean in _false_set:
  699. return False
  700. if clean in _none_set:
  701. return none
  702. raise ValueError("unrecognized %s value: %r" % (param, value))
  703. elif isinstance(value, bool):
  704. return value
  705. elif value is None:
  706. return none
  707. else:
  708. return bool(value)
  709. #=============================================================================
  710. # host OS helpers
  711. #=============================================================================
  712. def is_safe_crypt_input(value):
  713. """
  714. UT helper --
  715. test if value is safe to pass to crypt.crypt();
  716. under PY3, can't pass non-UTF8 bytes to crypt.crypt.
  717. """
  718. if crypt_accepts_bytes or not isinstance(value, bytes):
  719. return True
  720. try:
  721. value.decode("utf-8")
  722. return True
  723. except UnicodeDecodeError:
  724. return False
  725. try:
  726. from crypt import crypt as _crypt
  727. except ImportError: # pragma: no cover
  728. _crypt = None
  729. has_crypt = False
  730. crypt_accepts_bytes = False
  731. crypt_needs_lock = False
  732. _safe_crypt_lock = None
  733. def safe_crypt(secret, hash):
  734. return None
  735. else:
  736. has_crypt = True
  737. _NULL = '\x00'
  738. # XXX: replace this with lazy-evaluated bug detection?
  739. if threading and PYPY and (7, 2, 0) <= sys.pypy_version_info <= (7, 3, 3):
  740. #: internal lock used to wrap crypt() calls.
  741. #: WARNING: if non-passlib code invokes crypt(), this lock won't be enough!
  742. _safe_crypt_lock = threading.Lock()
  743. #: detect if crypt.crypt() needs a thread lock around calls.
  744. crypt_needs_lock = True
  745. else:
  746. from passlib.utils.compat import nullcontext
  747. _safe_crypt_lock = nullcontext()
  748. crypt_needs_lock = False
  749. # some crypt() variants will return various constant strings when
  750. # an invalid/unrecognized config string is passed in; instead of
  751. # returning NULL / None. examples include ":", ":0", "*0", etc.
  752. # safe_crypt() returns None for any string starting with one of the
  753. # chars in this string...
  754. _invalid_prefixes = u("*:!")
  755. if PY3:
  756. # * pypy3 (as of v7.3.1) has a crypt which accepts bytes, or ASCII-only unicode.
  757. # * whereas CPython3 (as of v3.9) has a crypt which doesn't take bytes,
  758. # but accepts ANY unicode (which it always encodes to UTF8).
  759. crypt_accepts_bytes = True
  760. try:
  761. _crypt(b"\xEE", "xx")
  762. except TypeError:
  763. # CPython will throw TypeError
  764. crypt_accepts_bytes = False
  765. except: # no pragma
  766. # don't care about other errors this might throw,
  767. # just want to see if we get past initial type-coercion step.
  768. pass
  769. def safe_crypt(secret, hash):
  770. if crypt_accepts_bytes:
  771. # PyPy3 -- all bytes accepted, but unicode encoded to ASCII,
  772. # so handling that ourselves.
  773. if isinstance(secret, unicode):
  774. secret = secret.encode("utf-8")
  775. if _BNULL in secret:
  776. raise ValueError("null character in secret")
  777. if isinstance(hash, unicode):
  778. hash = hash.encode("ascii")
  779. else:
  780. # CPython3's crypt() doesn't take bytes, only unicode; unicode which is then
  781. # encoding using utf-8 before passing to the C-level crypt().
  782. # so we have to decode the secret.
  783. if isinstance(secret, bytes):
  784. orig = secret
  785. try:
  786. secret = secret.decode("utf-8")
  787. except UnicodeDecodeError:
  788. return None
  789. # sanity check it encodes back to original byte string,
  790. # otherwise when crypt() does it's encoding, it'll hash the wrong bytes!
  791. assert secret.encode("utf-8") == orig, \
  792. "utf-8 spec says this can't happen!"
  793. if _NULL in secret:
  794. raise ValueError("null character in secret")
  795. if isinstance(hash, bytes):
  796. hash = hash.decode("ascii")
  797. try:
  798. with _safe_crypt_lock:
  799. result = _crypt(secret, hash)
  800. except OSError:
  801. # new in py39 -- per https://bugs.python.org/issue39289,
  802. # crypt() now throws OSError for various things, mainly unknown hash formats
  803. # translating that to None for now (may revise safe_crypt behavior in future)
  804. return None
  805. # NOTE: per issue 113, crypt() may return bytes in some odd cases.
  806. # assuming it should still return an ASCII hash though,
  807. # or there's a bigger issue at hand.
  808. if isinstance(result, bytes):
  809. result = result.decode("ascii")
  810. if not result or result[0] in _invalid_prefixes:
  811. return None
  812. return result
  813. else:
  814. #: see feature-detection in PY3 fork above
  815. crypt_accepts_bytes = True
  816. # Python 2 crypt handler
  817. def safe_crypt(secret, hash):
  818. if isinstance(secret, unicode):
  819. secret = secret.encode("utf-8")
  820. if _NULL in secret:
  821. raise ValueError("null character in secret")
  822. if isinstance(hash, unicode):
  823. hash = hash.encode("ascii")
  824. with _safe_crypt_lock:
  825. result = _crypt(secret, hash)
  826. if not result:
  827. return None
  828. result = result.decode("ascii")
  829. if result[0] in _invalid_prefixes:
  830. return None
  831. return result
  832. add_doc(safe_crypt, """Wrapper around stdlib's crypt.
  833. This is a wrapper around stdlib's :func:`!crypt.crypt`, which attempts
  834. to provide uniform behavior across Python 2 and 3.
  835. :arg secret:
  836. password, as bytes or unicode (unicode will be encoded as ``utf-8``).
  837. :arg hash:
  838. hash or config string, as ascii bytes or unicode.
  839. :returns:
  840. resulting hash as ascii unicode; or ``None`` if the password
  841. couldn't be hashed due to one of the issues:
  842. * :func:`crypt()` not available on platform.
  843. * Under Python 3, if *secret* is specified as bytes,
  844. it must be use ``utf-8`` or it can't be passed
  845. to :func:`crypt()`.
  846. * Some OSes will return ``None`` if they don't recognize
  847. the algorithm being used (though most will simply fall
  848. back to des-crypt).
  849. * Some OSes will return an error string if the input config
  850. is recognized but malformed; current code converts these to ``None``
  851. as well.
  852. """)
  853. def test_crypt(secret, hash):
  854. """check if :func:`crypt.crypt` supports specific hash
  855. :arg secret: password to test
  856. :arg hash: known hash of password to use as reference
  857. :returns: True or False
  858. """
  859. # safe_crypt() always returns unicode, which means that for py3,
  860. # 'hash' can't be bytes, or "== hash" will never be True.
  861. # under py2 unicode & str(bytes) will compare fine;
  862. # so just enforcing "unicode_or_str" limitation
  863. assert isinstance(hash, unicode_or_str), \
  864. "hash must be unicode_or_str, got %s" % type(hash)
  865. assert hash, "hash must be non-empty"
  866. return safe_crypt(secret, hash) == hash
  867. timer = timeit.default_timer
  868. # legacy alias, will be removed in passlib 2.0
  869. tick = timer
  870. def parse_version(source):
  871. """helper to parse version string"""
  872. m = re.search(r"(\d+(?:\.\d+)+)", source)
  873. if m:
  874. return tuple(int(elem) for elem in m.group(1).split("."))
  875. return None
  876. #=============================================================================
  877. # randomness
  878. #=============================================================================
  879. #------------------------------------------------------------------------
  880. # setup rng for generating salts
  881. #------------------------------------------------------------------------
  882. # NOTE:
  883. # generating salts (e.g. h64_gensalt, below) doesn't require cryptographically
  884. # strong randomness. it just requires enough range of possible outputs
  885. # that making a rainbow table is too costly. so it should be ok to
  886. # fall back on python's builtin mersenne twister prng, as long as it's seeded each time
  887. # this module is imported, using a couple of minor entropy sources.
  888. try:
  889. os.urandom(1)
  890. has_urandom = True
  891. except NotImplementedError: # pragma: no cover
  892. has_urandom = False
  893. def genseed(value=None):
  894. """generate prng seed value from system resources"""
  895. from hashlib import sha512
  896. if hasattr(value, "getstate") and hasattr(value, "getrandbits"):
  897. # caller passed in RNG as seed value
  898. try:
  899. value = value.getstate()
  900. except NotImplementedError:
  901. # this method throws error for e.g. SystemRandom instances,
  902. # so fall back to extracting 4k of state
  903. value = value.getrandbits(1 << 15)
  904. text = u("%s %s %s %.15f %.15f %s") % (
  905. # if caller specified a seed value, mix it in
  906. value,
  907. # add current process id
  908. # NOTE: not available in some environments, e.g. GAE
  909. os.getpid() if hasattr(os, "getpid") else None,
  910. # id of a freshly created object.
  911. # (at least 1 byte of which should be hard to predict)
  912. id(object()),
  913. # the current time, to whatever precision os uses
  914. time.time(),
  915. tick(),
  916. # if urandom available, might as well mix some bytes in.
  917. os.urandom(32).decode("latin-1") if has_urandom else 0,
  918. )
  919. # hash it all up and return it as int/long
  920. return int(sha512(text.encode("utf-8")).hexdigest(), 16)
  921. if has_urandom:
  922. rng = random.SystemRandom()
  923. else: # pragma: no cover -- runtime detection
  924. # NOTE: to reseed use ``rng.seed(genseed(rng))``
  925. # XXX: could reseed on every call
  926. rng = random.Random(genseed())
  927. #------------------------------------------------------------------------
  928. # some rng helpers
  929. #------------------------------------------------------------------------
  930. def getrandbytes(rng, count):
  931. """return byte-string containing *count* number of randomly generated bytes, using specified rng"""
  932. # NOTE: would be nice if this was present in stdlib Random class
  933. ###just in case rng provides this...
  934. ##meth = getattr(rng, "getrandbytes", None)
  935. ##if meth:
  936. ## return meth(count)
  937. if not count:
  938. return _BEMPTY
  939. def helper():
  940. # XXX: break into chunks for large number of bits?
  941. value = rng.getrandbits(count<<3)
  942. i = 0
  943. while i < count:
  944. yield value & 0xff
  945. value >>= 3
  946. i += 1
  947. return join_byte_values(helper())
  948. def getrandstr(rng, charset, count):
  949. """return string containing *count* number of chars/bytes, whose elements are drawn from specified charset, using specified rng"""
  950. # NOTE: tests determined this is 4x faster than rng.sample(),
  951. # which is why that's not being used here.
  952. # check alphabet & count
  953. if count < 0:
  954. raise ValueError("count must be >= 0")
  955. letters = len(charset)
  956. if letters == 0:
  957. raise ValueError("alphabet must not be empty")
  958. if letters == 1:
  959. return charset * count
  960. # get random value, and write out to buffer
  961. def helper():
  962. # XXX: break into chunks for large number of letters?
  963. value = rng.randrange(0, letters**count)
  964. i = 0
  965. while i < count:
  966. yield charset[value % letters]
  967. value //= letters
  968. i += 1
  969. if isinstance(charset, unicode):
  970. return join_unicode(helper())
  971. else:
  972. return join_byte_elems(helper())
  973. _52charset = '2346789ABCDEFGHJKMNPQRTUVWXYZabcdefghjkmnpqrstuvwxyz'
  974. @deprecated_function(deprecated="1.7", removed="2.0",
  975. replacement="passlib.pwd.genword() / passlib.pwd.genphrase()")
  976. def generate_password(size=10, charset=_52charset):
  977. """generate random password using given length & charset
  978. :param size:
  979. size of password.
  980. :param charset:
  981. optional string specified set of characters to draw from.
  982. the default charset contains all normal alphanumeric characters,
  983. except for the characters ``1IiLl0OoS5``, which were omitted
  984. due to their visual similarity.
  985. :returns: :class:`!str` containing randomly generated password.
  986. .. note::
  987. Using the default character set, on a OS with :class:`!SystemRandom` support,
  988. this function should generate passwords with 5.7 bits of entropy per character.
  989. """
  990. return getrandstr(rng, charset, size)
  991. #=============================================================================
  992. # object type / interface tests
  993. #=============================================================================
  994. _handler_attrs = (
  995. "name",
  996. "setting_kwds", "context_kwds",
  997. "verify", "hash", "identify",
  998. )
  999. def is_crypt_handler(obj):
  1000. """check if object follows the :ref:`password-hash-api`"""
  1001. # XXX: change to use isinstance(obj, PasswordHash) under py26+?
  1002. return all(hasattr(obj, name) for name in _handler_attrs)
  1003. _context_attrs = (
  1004. "needs_update",
  1005. "genconfig", "genhash",
  1006. "verify", "encrypt", "identify",
  1007. )
  1008. def is_crypt_context(obj):
  1009. """check if object appears to be a :class:`~passlib.context.CryptContext` instance"""
  1010. # XXX: change to use isinstance(obj, CryptContext)?
  1011. return all(hasattr(obj, name) for name in _context_attrs)
  1012. ##def has_many_backends(handler):
  1013. ## "check if handler provides multiple baceknds"
  1014. ## # NOTE: should also provide get_backend(), .has_backend(), and .backends attr
  1015. ## return hasattr(handler, "set_backend")
  1016. def has_rounds_info(handler):
  1017. """check if handler provides the optional :ref:`rounds information <rounds-attributes>` attributes"""
  1018. return ('rounds' in handler.setting_kwds and
  1019. getattr(handler, "min_rounds", None) is not None)
  1020. def has_salt_info(handler):
  1021. """check if handler provides the optional :ref:`salt information <salt-attributes>` attributes"""
  1022. return ('salt' in handler.setting_kwds and
  1023. getattr(handler, "min_salt_size", None) is not None)
  1024. ##def has_raw_salt(handler):
  1025. ## "check if handler takes in encoded salt as unicode (False), or decoded salt as bytes (True)"
  1026. ## sc = getattr(handler, "salt_chars", None)
  1027. ## if sc is None:
  1028. ## return None
  1029. ## elif isinstance(sc, unicode):
  1030. ## return False
  1031. ## elif isinstance(sc, bytes):
  1032. ## return True
  1033. ## else:
  1034. ## raise TypeError("handler.salt_chars must be None/unicode/bytes")
  1035. #=============================================================================
  1036. # eof
  1037. #=============================================================================