You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					129 lines
				
				4.7 KiB
			
		
		
			
		
	
	
					129 lines
				
				4.7 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								"""passlib.handlers.mysql
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								MySQL 3.2.3 / OLD_PASSWORD()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This implements Mysql's OLD_PASSWORD algorithm, introduced in version 3.2.3, deprecated in version 4.1.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    See :mod:`passlib.handlers.mysql_41` for the new algorithm was put in place in version 4.1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This algorithm is known to be very insecure, and should only be used to verify existing password hashes.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    http://djangosnippets.org/snippets/1508/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								MySQL 4.1.1 / NEW PASSWORD
							 | 
						||
| 
								 | 
							
								    This implements Mysql new PASSWORD algorithm, introduced in version 4.1.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This function is unsalted, and therefore not very secure against rainbow attacks.
							 | 
						||
| 
								 | 
							
								    It should only be used when dealing with mysql passwords,
							 | 
						||
| 
								 | 
							
								    for all other purposes, you should use a salted hash function.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Description taken from http://dev.mysql.com/doc/refman/6.0/en/password-hashing.html
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# imports
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# core
							 | 
						||
| 
								 | 
							
								from hashlib import sha1
							 | 
						||
| 
								 | 
							
								import re
							 | 
						||
| 
								 | 
							
								import logging; log = logging.getLogger(__name__)
							 | 
						||
| 
								 | 
							
								from warnings import warn
							 | 
						||
| 
								 | 
							
								# site
							 | 
						||
| 
								 | 
							
								# pkg
							 | 
						||
| 
								 | 
							
								from passlib.utils import to_native_str
							 | 
						||
| 
								 | 
							
								from passlib.utils.compat import bascii_to_str, unicode, u, \
							 | 
						||
| 
								 | 
							
								                                 byte_elem_value, str_to_uascii
							 | 
						||
| 
								 | 
							
								import passlib.utils.handlers as uh
							 | 
						||
| 
								 | 
							
								# local
							 | 
						||
| 
								 | 
							
								__all__ = [
							 | 
						||
| 
								 | 
							
								    'mysql323',
							 | 
						||
| 
								 | 
							
								    'mysq41',
							 | 
						||
| 
								 | 
							
								]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# backend
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								class mysql323(uh.StaticHandler):
							 | 
						||
| 
								 | 
							
								    """This class implements the MySQL 3.2.3 password hash, and follows the :ref:`password-hash-api`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    It has no salt and a single fixed round.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept no optional keywords.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								    # class attrs
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								    name = "mysql323"
							 | 
						||
| 
								 | 
							
								    checksum_size = 16
							 | 
						||
| 
								 | 
							
								    checksum_chars = uh.HEX_CHARS
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								    # methods
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def _norm_hash(cls, hash):
							 | 
						||
| 
								 | 
							
								        return hash.lower()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _calc_checksum(self, secret):
							 | 
						||
| 
								 | 
							
								        # FIXME: no idea if mysql has a policy about handling unicode passwords
							 | 
						||
| 
								 | 
							
								        if isinstance(secret, unicode):
							 | 
						||
| 
								 | 
							
								            secret = secret.encode("utf-8")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        MASK_32 = 0xffffffff
							 | 
						||
| 
								 | 
							
								        MASK_31 = 0x7fffffff
							 | 
						||
| 
								 | 
							
								        WHITE = b' \t'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        nr1 = 0x50305735
							 | 
						||
| 
								 | 
							
								        nr2 = 0x12345671
							 | 
						||
| 
								 | 
							
								        add = 7
							 | 
						||
| 
								 | 
							
								        for c in secret:
							 | 
						||
| 
								 | 
							
								            if c in WHITE:
							 | 
						||
| 
								 | 
							
								                continue
							 | 
						||
| 
								 | 
							
								            tmp = byte_elem_value(c)
							 | 
						||
| 
								 | 
							
								            nr1 ^= ((((nr1 & 63)+add)*tmp) + (nr1 << 8)) & MASK_32
							 | 
						||
| 
								 | 
							
								            nr2 = (nr2+((nr2 << 8) ^ nr1)) & MASK_32
							 | 
						||
| 
								 | 
							
								            add = (add+tmp) & MASK_32
							 | 
						||
| 
								 | 
							
								        return u("%08x%08x") % (nr1 & MASK_31, nr2 & MASK_31)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								    # eoc
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# handler
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								class mysql41(uh.StaticHandler):
							 | 
						||
| 
								 | 
							
								    """This class implements the MySQL 4.1 password hash, and follows the :ref:`password-hash-api`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    It has no salt and a single fixed round.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept no optional keywords.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								    # class attrs
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								    name = "mysql41"
							 | 
						||
| 
								 | 
							
								    _hash_prefix = u("*")
							 | 
						||
| 
								 | 
							
								    checksum_chars = uh.HEX_CHARS
							 | 
						||
| 
								 | 
							
								    checksum_size = 40
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								    # methods
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								    @classmethod
							 | 
						||
| 
								 | 
							
								    def _norm_hash(cls, hash):
							 | 
						||
| 
								 | 
							
								        return hash.upper()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _calc_checksum(self, secret):
							 | 
						||
| 
								 | 
							
								        # FIXME: no idea if mysql has a policy about handling unicode passwords
							 | 
						||
| 
								 | 
							
								        if isinstance(secret, unicode):
							 | 
						||
| 
								 | 
							
								            secret = secret.encode("utf-8")
							 | 
						||
| 
								 | 
							
								        return str_to_uascii(sha1(sha1(secret).digest()).hexdigest()).upper()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								    # eoc
							 | 
						||
| 
								 | 
							
								    #===================================================================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 | 
						||
| 
								 | 
							
								# eof
							 | 
						||
| 
								 | 
							
								#=============================================================================
							 |