Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

245 lignes
8.3 KiB

  1. """passlib.handlers.mssql - MS-SQL Password Hash
  2. Notes
  3. =====
  4. MS-SQL has used a number of hash algs over the years,
  5. most of which were exposed through the undocumented
  6. 'pwdencrypt' and 'pwdcompare' sql functions.
  7. Known formats
  8. -------------
  9. 6.5
  10. snefru hash, ascii encoded password
  11. no examples found
  12. 7.0
  13. snefru hash, unicode (what encoding?)
  14. saw ref that these blobs were 16 bytes in size
  15. no examples found
  16. 2000
  17. byte string using displayed as 0x hex, using 0x0100 prefix.
  18. contains hashes of password and upper-case password.
  19. 2007
  20. same as 2000, but without the upper-case hash.
  21. refs
  22. ----------
  23. https://blogs.msdn.com/b/lcris/archive/2007/04/30/sql-server-2005-about-login-password-hashes.aspx?Redirected=true
  24. http://us.generation-nt.com/securing-passwords-hash-help-35429432.html
  25. http://forum.md5decrypter.co.uk/topic230-mysql-and-mssql-get-password-hashes.aspx
  26. http://www.theregister.co.uk/2002/07/08/cracking_ms_sql_server_passwords/
  27. """
  28. #=============================================================================
  29. # imports
  30. #=============================================================================
  31. # core
  32. from binascii import hexlify, unhexlify
  33. from hashlib import sha1
  34. import re
  35. import logging; log = logging.getLogger(__name__)
  36. from warnings import warn
  37. # site
  38. # pkg
  39. from passlib.utils import consteq
  40. from passlib.utils.compat import bascii_to_str, unicode, u
  41. import passlib.utils.handlers as uh
  42. # local
  43. __all__ = [
  44. "mssql2000",
  45. "mssql2005",
  46. ]
  47. #=============================================================================
  48. # mssql 2000
  49. #=============================================================================
  50. def _raw_mssql(secret, salt):
  51. assert isinstance(secret, unicode)
  52. assert isinstance(salt, bytes)
  53. return sha1(secret.encode("utf-16-le") + salt).digest()
  54. BIDENT = b"0x0100"
  55. ##BIDENT2 = b("\x01\x00")
  56. UIDENT = u("0x0100")
  57. def _ident_mssql(hash, csize, bsize):
  58. """common identify for mssql 2000/2005"""
  59. if isinstance(hash, unicode):
  60. if len(hash) == csize and hash.startswith(UIDENT):
  61. return True
  62. elif isinstance(hash, bytes):
  63. if len(hash) == csize and hash.startswith(BIDENT):
  64. return True
  65. ##elif len(hash) == bsize and hash.startswith(BIDENT2): # raw bytes
  66. ## return True
  67. else:
  68. raise uh.exc.ExpectedStringError(hash, "hash")
  69. return False
  70. def _parse_mssql(hash, csize, bsize, handler):
  71. """common parser for mssql 2000/2005; returns 4 byte salt + checksum"""
  72. if isinstance(hash, unicode):
  73. if len(hash) == csize and hash.startswith(UIDENT):
  74. try:
  75. return unhexlify(hash[6:].encode("utf-8"))
  76. except TypeError: # throw when bad char found
  77. pass
  78. elif isinstance(hash, bytes):
  79. # assumes ascii-compat encoding
  80. assert isinstance(hash, bytes)
  81. if len(hash) == csize and hash.startswith(BIDENT):
  82. try:
  83. return unhexlify(hash[6:])
  84. except TypeError: # throw when bad char found
  85. pass
  86. ##elif len(hash) == bsize and hash.startswith(BIDENT2): # raw bytes
  87. ## return hash[2:]
  88. else:
  89. raise uh.exc.ExpectedStringError(hash, "hash")
  90. raise uh.exc.InvalidHashError(handler)
  91. class mssql2000(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
  92. """This class implements the password hash used by MS-SQL 2000, and follows the :ref:`password-hash-api`.
  93. It supports a fixed-length salt.
  94. The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords:
  95. :type salt: bytes
  96. :param salt:
  97. Optional salt string.
  98. If not specified, one will be autogenerated (this is recommended).
  99. If specified, it must be 4 bytes in length.
  100. :type relaxed: bool
  101. :param relaxed:
  102. By default, providing an invalid value for one of the other
  103. keywords will result in a :exc:`ValueError`. If ``relaxed=True``,
  104. and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning`
  105. will be issued instead. Correctable errors include
  106. ``salt`` strings that are too long.
  107. """
  108. #===================================================================
  109. # algorithm information
  110. #===================================================================
  111. name = "mssql2000"
  112. setting_kwds = ("salt",)
  113. checksum_size = 40
  114. min_salt_size = max_salt_size = 4
  115. #===================================================================
  116. # formatting
  117. #===================================================================
  118. # 0100 - 2 byte identifier
  119. # 4 byte salt
  120. # 20 byte checksum
  121. # 20 byte checksum
  122. # = 46 bytes
  123. # encoded '0x' + 92 chars = 94
  124. @classmethod
  125. def identify(cls, hash):
  126. return _ident_mssql(hash, 94, 46)
  127. @classmethod
  128. def from_string(cls, hash):
  129. data = _parse_mssql(hash, 94, 46, cls)
  130. return cls(salt=data[:4], checksum=data[4:])
  131. def to_string(self):
  132. raw = self.salt + self.checksum
  133. # raw bytes format - BIDENT2 + raw
  134. return "0x0100" + bascii_to_str(hexlify(raw).upper())
  135. def _calc_checksum(self, secret):
  136. if isinstance(secret, bytes):
  137. secret = secret.decode("utf-8")
  138. salt = self.salt
  139. return _raw_mssql(secret, salt) + _raw_mssql(secret.upper(), salt)
  140. @classmethod
  141. def verify(cls, secret, hash):
  142. # NOTE: we only compare against the upper-case hash
  143. # XXX: add 'full' just to verify both checksums?
  144. uh.validate_secret(secret)
  145. self = cls.from_string(hash)
  146. chk = self.checksum
  147. if chk is None:
  148. raise uh.exc.MissingDigestError(cls)
  149. if isinstance(secret, bytes):
  150. secret = secret.decode("utf-8")
  151. result = _raw_mssql(secret.upper(), self.salt)
  152. return consteq(result, chk[20:])
  153. #=============================================================================
  154. # handler
  155. #=============================================================================
  156. class mssql2005(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
  157. """This class implements the password hash used by MS-SQL 2005, and follows the :ref:`password-hash-api`.
  158. It supports a fixed-length salt.
  159. The :meth:`~passlib.ifc.PasswordHash.using` method accepts the following optional keywords:
  160. :type salt: bytes
  161. :param salt:
  162. Optional salt string.
  163. If not specified, one will be autogenerated (this is recommended).
  164. If specified, it must be 4 bytes in length.
  165. :type relaxed: bool
  166. :param relaxed:
  167. By default, providing an invalid value for one of the other
  168. keywords will result in a :exc:`ValueError`. If ``relaxed=True``,
  169. and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning`
  170. will be issued instead. Correctable errors include
  171. ``salt`` strings that are too long.
  172. """
  173. #===================================================================
  174. # algorithm information
  175. #===================================================================
  176. name = "mssql2005"
  177. setting_kwds = ("salt",)
  178. checksum_size = 20
  179. min_salt_size = max_salt_size = 4
  180. #===================================================================
  181. # formatting
  182. #===================================================================
  183. # 0x0100 - 2 byte identifier
  184. # 4 byte salt
  185. # 20 byte checksum
  186. # = 26 bytes
  187. # encoded '0x' + 52 chars = 54
  188. @classmethod
  189. def identify(cls, hash):
  190. return _ident_mssql(hash, 54, 26)
  191. @classmethod
  192. def from_string(cls, hash):
  193. data = _parse_mssql(hash, 54, 26, cls)
  194. return cls(salt=data[:4], checksum=data[4:])
  195. def to_string(self):
  196. raw = self.salt + self.checksum
  197. # raw bytes format - BIDENT2 + raw
  198. return "0x0100" + bascii_to_str(hexlify(raw)).upper()
  199. def _calc_checksum(self, secret):
  200. if isinstance(secret, bytes):
  201. secret = secret.decode("utf-8")
  202. return _raw_mssql(secret, self.salt)
  203. #===================================================================
  204. # eoc
  205. #===================================================================
  206. #=============================================================================
  207. # eof
  208. #=============================================================================