Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
_md4.py245 linesDownload Raw Back to crypto
1"""2passlib.crypto._md4 -- fallback implementation of MD43 4Helper implementing insecure and obsolete md4 algorithm.5used for NTHASH format, which is also insecure and broken,6since it's just md4(password).7 8Implementated based on rfc at http://www.faqs.org/rfcs/rfc1320.html9 10.. note::11 12    This shouldn't be imported directly, it's merely used conditionally13    by ``passlib.crypto.lookup_hash()`` when a native implementation can't be found.14"""15 16#=============================================================================17# imports18#=============================================================================19# core20from binascii import hexlify21import struct22# site23from passlib.utils.compat import bascii_to_str, irange, PY324# local25__all__ = ["md4"]26 27#=============================================================================28# utils29#=============================================================================30def F(x,y,z):31    return (x&y) | ((~x) & z)32 33def G(x,y,z):34    return (x&y) | (x&z) | (y&z)35 36##def H(x,y,z):37##    return x ^ y ^ z38 39MASK_32 = 2**32-140 41#=============================================================================42# main class43#=============================================================================44class md4(object):45    """pep-247 compatible implementation of MD4 hash algorithm46 47    .. attribute:: digest_size48 49        size of md4 digest in bytes (16 bytes)50 51    .. method:: update52 53        update digest by appending additional content54 55    .. method:: copy56 57        create clone of digest object, including current state58 59    .. method:: digest60 61        return bytes representing md4 digest of current content62 63    .. method:: hexdigest64 65        return hexadecimal version of digest66    """67    # FIXME: make this follow hash object PEP better.68    # FIXME: this isn't threadsafe69 70    name = "md4"71    digest_size = digestsize = 1672    block_size = 6473 74    _count = 0 # number of 64-byte blocks processed so far (not including _buf)75    _state = None # list of [a,b,c,d] 32 bit ints used as internal register76    _buf = None # data processed in 64 byte blocks, this holds leftover from last update77 78    def __init__(self, content=None):79        self._count = 080        self._state = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476]81        self._buf = b''82        if content:83            self.update(content)84 85    # round 1 table - [abcd k s]86    _round1 = [87        [0,1,2,3, 0,3],88        [3,0,1,2, 1,7],89        [2,3,0,1, 2,11],90        [1,2,3,0, 3,19],91 92        [0,1,2,3, 4,3],93        [3,0,1,2, 5,7],94        [2,3,0,1, 6,11],95        [1,2,3,0, 7,19],96 97        [0,1,2,3, 8,3],98        [3,0,1,2, 9,7],99        [2,3,0,1, 10,11],100        [1,2,3,0, 11,19],101 102        [0,1,2,3, 12,3],103        [3,0,1,2, 13,7],104        [2,3,0,1, 14,11],105        [1,2,3,0, 15,19],106    ]107 108    # round 2 table - [abcd k s]109    _round2 = [110        [0,1,2,3, 0,3],111        [3,0,1,2, 4,5],112        [2,3,0,1, 8,9],113        [1,2,3,0, 12,13],114 115        [0,1,2,3, 1,3],116        [3,0,1,2, 5,5],117        [2,3,0,1, 9,9],118        [1,2,3,0, 13,13],119 120        [0,1,2,3, 2,3],121        [3,0,1,2, 6,5],122        [2,3,0,1, 10,9],123        [1,2,3,0, 14,13],124 125        [0,1,2,3, 3,3],126        [3,0,1,2, 7,5],127        [2,3,0,1, 11,9],128        [1,2,3,0, 15,13],129    ]130 131    # round 3 table - [abcd k s]132    _round3 = [133        [0,1,2,3, 0,3],134        [3,0,1,2, 8,9],135        [2,3,0,1, 4,11],136        [1,2,3,0, 12,15],137 138        [0,1,2,3, 2,3],139        [3,0,1,2, 10,9],140        [2,3,0,1, 6,11],141        [1,2,3,0, 14,15],142 143        [0,1,2,3, 1,3],144        [3,0,1,2, 9,9],145        [2,3,0,1, 5,11],146        [1,2,3,0, 13,15],147 148        [0,1,2,3, 3,3],149        [3,0,1,2, 11,9],150        [2,3,0,1, 7,11],151        [1,2,3,0, 15,15],152    ]153 154    def _process(self, block):155        """process 64 byte block"""156        # unpack block into 16 32-bit ints157        X = struct.unpack("<16I", block)158 159        # clone state160        orig = self._state161        state = list(orig)162 163        # round 1 - F function - (x&y)|(~x & z)164        for a,b,c,d,k,s in self._round1:165            t = (state[a] + F(state[b],state[c],state[d]) + X[k]) & MASK_32166            state[a] = ((t<<s) & MASK_32) + (t>>(32-s))167 168        # round 2 - G function169        for a,b,c,d,k,s in self._round2:170            t = (state[a] + G(state[b],state[c],state[d]) + X[k] + 0x5a827999) & MASK_32171            state[a] = ((t<<s) & MASK_32) + (t>>(32-s))172 173        # round 3 - H function - x ^ y ^ z174        for a,b,c,d,k,s in self._round3:175            t = (state[a] + (state[b] ^ state[c] ^ state[d]) + X[k] + 0x6ed9eba1) & MASK_32176            state[a] = ((t<<s) & MASK_32) + (t>>(32-s))177 178        # add back into original state179        for i in irange(4):180            orig[i] = (orig[i]+state[i]) & MASK_32181 182    def update(self, content):183        if not isinstance(content, bytes):184            if PY3:185                raise TypeError("expected bytes")186            else:187                # replicate behavior of hashlib under py2188                content = content.encode("ascii")189        buf = self._buf190        if buf:191            content = buf + content192        idx = 0193        end = len(content)194        while True:195            next = idx + 64196            if next <= end:197                self._process(content[idx:next])198                self._count += 1199                idx = next200            else:201                self._buf = content[idx:]202                return203 204    def copy(self):205        other = md4()206        other._count = self._count207        other._state = list(self._state)208        other._buf = self._buf209        return other210 211    def digest(self):212        # NOTE: backing up state so we can restore it after _process is called,213        #       in case object is updated again (this is only attr altered by this method)214        orig = list(self._state)215 216        # final block: buf + 0x80,217        # then 0x00 padding until congruent w/ 56 mod 64 bytes218        # then last 8 bytes = msg length in bits219        buf = self._buf220        msglen = self._count*512 + len(buf)*8221        block = buf + b'\x80' + b'\x00' * ((119-len(buf)) % 64) + \222            struct.pack("<2I", msglen & MASK_32, (msglen>>32) & MASK_32)223        if len(block) == 128:224            self._process(block[:64])225            self._process(block[64:])226        else:227            assert len(block) == 64228            self._process(block)229 230        # render digest & restore un-finalized state231        out = struct.pack("<4I", *self._state)232        self._state = orig233        return out234 235    def hexdigest(self):236        return bascii_to_str(hexlify(self.digest()))237 238    #===================================================================239    # eoc240    #===================================================================241 242#=============================================================================243# eof244#=============================================================================245 
codekingpro/portable-devtools · Team Ai