1"""passlib.handlers.mysql 2 3MySQL 3.2.3 / OLD_PASSWORD() 4 5 This implements Mysql's OLD_PASSWORD algorithm, introduced in version 3.2.3, deprecated in version 4.1. 6 7 See :mod:`passlib.handlers.mysql_41` for the new algorithm was put in place in version 4.1 8 9 This algorithm is known to be very insecure, and should only be used to verify existing password hashes. 10 11 http://djangosnippets.org/snippets/1508/ 12 13MySQL 4.1.1 / NEW PASSWORD 14 This implements Mysql new PASSWORD algorithm, introduced in version 4.1. 15 16 This function is unsalted, and therefore not very secure against rainbow attacks. 17 It should only be used when dealing with mysql passwords, 18 for all other purposes, you should use a salted hash function. 19 20 Description taken from http://dev.mysql.com/doc/refman/6.0/en/password-hashing.html 21""" 22#============================================================================= 23# imports 24#============================================================================= 25# core 26from hashlib import sha1 27import re 28import logging; log = logging.getLogger(__name__) 29from warnings import warn 30# site 31# pkg 32from passlib.utils import to_native_str 33from passlib.utils.compat import bascii_to_str, unicode, u, \ 34 byte_elem_value, str_to_uascii 35import passlib.utils.handlers as uh 36# local 37__all__ = [ 38 'mysql323', 39 'mysq41', 40] 41 42#============================================================================= 43# backend 44#============================================================================= 45class mysql323(uh.StaticHandler): 46 """This class implements the MySQL 3.2.3 password hash, and follows the :ref:`password-hash-api`. 47 48 It has no salt and a single fixed round. 49 50 The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept no optional keywords. 51 """ 52 #=================================================================== 53 # class attrs 54 #=================================================================== 55 name = "mysql323" 56 checksum_size = 16 57 checksum_chars = uh.HEX_CHARS 58 59 #=================================================================== 60 # methods 61 #=================================================================== 62 @classmethod 63 def _norm_hash(cls, hash): 64 return hash.lower() 65 66 def _calc_checksum(self, secret): 67 # FIXME: no idea if mysql has a policy about handling unicode passwords 68 if isinstance(secret, unicode): 69 secret = secret.encode("utf-8") 70 71 MASK_32 = 0xffffffff 72 MASK_31 = 0x7fffffff 73 WHITE = b' \t' 74 75 nr1 = 0x50305735 76 nr2 = 0x12345671 77 add = 7 78 for c in secret: 79 if c in WHITE: 80 continue 81 tmp = byte_elem_value(c) 82 nr1 ^= ((((nr1 & 63)+add)*tmp) + (nr1 << 8)) & MASK_32 83 nr2 = (nr2+((nr2 << 8) ^ nr1)) & MASK_32 84 add = (add+tmp) & MASK_32 85 return u("%08x%08x") % (nr1 & MASK_31, nr2 & MASK_31) 86 87 #=================================================================== 88 # eoc 89 #=================================================================== 90 91#============================================================================= 92# handler 93#============================================================================= 94class mysql41(uh.StaticHandler): 95 """This class implements the MySQL 4.1 password hash, and follows the :ref:`password-hash-api`. 96 97 It has no salt and a single fixed round. 98 99 The :meth:`~passlib.ifc.PasswordHash.hash` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept no optional keywords. 100 """ 101 #=================================================================== 102 # class attrs 103 #=================================================================== 104 name = "mysql41" 105 _hash_prefix = u("*") 106 checksum_chars = uh.HEX_CHARS 107 checksum_size = 40 108 109 #=================================================================== 110 # methods 111 #=================================================================== 112 @classmethod 113 def _norm_hash(cls, hash): 114 return hash.upper() 115 116 def _calc_checksum(self, secret): 117 # FIXME: no idea if mysql has a policy about handling unicode passwords 118 if isinstance(secret, unicode): 119 secret = secret.encode("utf-8") 120 return str_to_uascii(sha1(sha1(secret).digest()).hexdigest()).upper() 121 122 #=================================================================== 123 # eoc 124 #=================================================================== 125 126#============================================================================= 127# eof 128#============================================================================= 129