Exemple #1
0
def _encode_bytes_helper(source):
    #FIXME: do something much more efficient here.
    # can't quite just use base64 and then translate chars,
    # since this scheme is little-endian.
    end = len(source)
    tail = end % 3
    end -= tail
    idx = 0
    while idx < end:
        v1 = bord(source[idx])
        v2 = bord(source[idx+1])
        v3 = bord(source[idx+2])
        yield encode_int24(v1 + (v2<<8) + (v3<<16))
        idx += 3
    if tail:
        v1 = bord(source[idx])
        if tail == 1:
            #NOTE: 4 msb of int are always 0
            yield encode_int12(v1)
        else:
            #NOTE: 2 msb of int are always 0
            v2 = bord(source[idx+1])
            yield encode_int18(v1 + (v2<<8))
Exemple #2
0
    def genhash(cls, secret, config):
        if config is not None and not cls.identify(config):
            raise ValueError("not a mysql-3.2.3 hash")

        #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

        nr1 = 0x50305735
        nr2 = 0x12345671
        add = 7
        for c in secret:
            if c in b(' \t'):
                continue
            tmp = bord(c)
            nr1 ^= ((((nr1 & 63) + add) * tmp) + (nr1 << 8)) & MASK_32
            nr2 = (nr2 + ((nr2 << 8) ^ nr1)) & MASK_32
            add = (add + tmp) & MASK_32
        hash = u"%08x%08x" % (nr1 & MASK_31, nr2 & MASK_31)
        return to_hash_str(hash)
Exemple #3
0
    def genhash(cls, secret, config):
        if config is not None and not cls.identify(config):
            raise ValueError("not a mysql-3.2.3 hash")

        #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

        nr1 = 0x50305735
        nr2 = 0x12345671
        add = 7
        for c in secret:
            if c in b(' \t'):
                continue
            tmp = bord(c)
            nr1 ^= ((((nr1 & 63)+add)*tmp) + (nr1 << 8)) & MASK_32
            nr2 = (nr2+((nr2 << 8) ^ nr1)) & MASK_32
            add = (add+tmp) & MASK_32
        hash = u"%08x%08x" % (nr1 & MASK_31, nr2 & MASK_31)
        return to_hash_str(hash)
Exemple #4
0
def _crypt_secret_to_key(secret):
    "crypt helper which converts lower 7 bits of first 8 chars of secret -> 56-bit des key, padded to 64 bits"
    return sum(
        (bord(c) & 0x7f) << (57-8*i)
        for i, c in enumerate(secret[:8])
    )
def raw_sun_md5_crypt(secret, rounds, salt):
    "given secret & salt, return encoded sun-md5-crypt checksum"
    global MAGIC_HAMLET
    assert isinstance(secret, bytes)
    assert isinstance(salt, bytes)

    # validate rounds
    if rounds <= 0:
        rounds = 0
    real_rounds = 4096 + rounds
    # NOTE: spec seems to imply max 'rounds' is 2**32-1

    # generate initial digest to start off round 0.
    # NOTE: algorithm 'salt' includes full config string w/ trailing "$"
    result = md5(secret + salt).digest()
    assert len(result) == 16

    # NOTE: many things have been inlined to speed up the loop as much as possible,
    # so that this only barely resembles the algorithm as described in the docs.
    # * all accesses to a given bit have been inlined using the formula
    #       rbitval(bit) = (rval((bit>>3) & 15) >> (bit & 7)) & 1
    # * the calculation of coinflip value R has been inlined
    # * the conditional division of coinflip value V has been inlined as a shift right of 0 or 1.
    # * the i, i+3, etc iterations are precalculated in lists.
    # * the round-based conditional division of x & y is now performed
    #   by choosing an appropriate precalculated list, so only the 7 used bits
    #   are actually calculated
    X_ROUNDS_0, X_ROUNDS_1, Y_ROUNDS_0, Y_ROUNDS_1 = _XY_ROUNDS

    # NOTE: % appears to be *slightly* slower than &, so we prefer & if possible

    round = 0
    while round < real_rounds:
        # convert last result byte string to list of byte-ints for easy access
        rval = [bord(c) for c in result].__getitem__

        # build up X bit by bit
        x = 0
        xrounds = X_ROUNDS_1 if (rval((round >> 3) & 15) >> (round & 7)) & 1 else X_ROUNDS_0
        for i, ia, ib in xrounds:
            a = rval(ia)
            b = rval(ib)
            v = rval((a >> (b % 5)) & 15) >> ((b >> (a & 7)) & 1)
            x |= ((rval((v >> 3) & 15) >> (v & 7)) & 1) << i

        # build up Y bit by bit
        y = 0
        yrounds = Y_ROUNDS_1 if (rval(((round + 64) >> 3) & 15) >> (round & 7)) & 1 else Y_ROUNDS_0
        for i, ia, ib in yrounds:
            a = rval(ia)
            b = rval(ib)
            v = rval((a >> (b % 5)) & 15) >> ((b >> (a & 7)) & 1)
            y |= ((rval((v >> 3) & 15) >> (v & 7)) & 1) << i

        # extract x'th and y'th bit, xoring them together to yeild "coin flip"
        coin = ((rval(x >> 3) >> (x & 7)) ^ (rval(y >> 3) >> (y & 7))) & 1

        # construct hash for this round
        h = md5(result)
        if coin:
            h.update(MAGIC_HAMLET)
        h.update(unicode(round).encode("ascii"))
        result = h.digest()

        round += 1

    # encode output
    return h64.encode_transposed_bytes(result, _chk_offsets)
Exemple #6
0
def raw_sun_md5_crypt(secret, rounds, salt):
    "given secret & salt, return encoded sun-md5-crypt checksum"
    global MAGIC_HAMLET
    assert isinstance(secret, bytes)
    assert isinstance(salt, bytes)

    #validate rounds
    if rounds <= 0:
        rounds = 0
    real_rounds = 4096 + rounds
    #NOTE: spec seems to imply max 'rounds' is 2**32-1

    #generate initial digest to start off round 0.
    #NOTE: algorithm 'salt' includes full config string w/ trailing "$"
    result = md5(secret + salt).digest()
    assert len(result) == 16

    #NOTE: many things have been inlined to speed up the loop as much as possible,
    # so that this only barely resembles the algorithm as described in the docs.
    # * all accesses to a given bit have been inlined using the formula
    #       rbitval(bit) = (rval((bit>>3) & 15) >> (bit & 7)) & 1
    # * the calculation of coinflip value R has been inlined
    # * the conditional division of coinflip value V has been inlined as a shift right of 0 or 1.
    # * the i, i+3, etc iterations are precalculated in lists.
    # * the round-based conditional division of x & y is now performed
    #   by choosing an appropriate precalculated list, so only the 7 used bits
    #   are actually calculated
    X_ROUNDS_0, X_ROUNDS_1, Y_ROUNDS_0, Y_ROUNDS_1 = _XY_ROUNDS

    #NOTE: % appears to be *slightly* slower than &, so we prefer & if possible

    round = 0
    while round < real_rounds:
        #convert last result byte string to list of byte-ints for easy access
        rval = [ bord(c) for c in result ].__getitem__

        #build up X bit by bit
        x = 0
        xrounds = X_ROUNDS_1 if (rval((round>>3) & 15)>>(round & 7)) & 1 else X_ROUNDS_0
        for i, ia, ib in xrounds:
            a = rval(ia)
            b = rval(ib)
            v = rval((a >> (b % 5)) & 15) >> ((b>>(a&7)) & 1)
            x |= ((rval((v>>3)&15)>>(v&7))&1) << i

        #build up Y bit by bit
        y = 0
        yrounds = Y_ROUNDS_1 if (rval(((round+64)>>3) & 15)>>(round & 7)) & 1 else Y_ROUNDS_0
        for i, ia, ib in yrounds:
            a = rval(ia)
            b = rval(ib)
            v = rval((a >> (b % 5)) & 15) >> ((b>>(a&7)) & 1)
            y |= ((rval((v>>3)&15)>>(v&7))&1) << i

        #extract x'th and y'th bit, xoring them together to yeild "coin flip"
        coin = ((rval(x>>3) >> (x&7)) ^ (rval(y>>3) >> (y&7))) & 1

        #construct hash for this round
        h = md5(result)
        if coin:
            h.update(MAGIC_HAMLET)
        h.update(unicode(round).encode("ascii"))
        result = h.digest()

        round += 1

    #encode output
    return h64.encode_transposed_bytes(result, _chk_offsets)
def raw_sha_crypt(secret, salt, rounds, hash):
    """perform raw sha crypt

    :arg secret: password to encode (if unicode, encoded to utf-8)
    :arg salt: salt string to use (required)
    :arg rounds: int rounds
    :arg hash: hash constructor function for 256/512 variant

    :returns:
        Returns tuple of ``(unencoded checksum, normalized salt, normalized rounds)``.

    """
    #validate secret
    if not isinstance(secret, bytes):
        raise TypeError("secret must be encoded as bytes")

    #validate rounds
    if rounds < 1000:
        rounds = 1000
    if rounds > 999999999: #pragma: no cover
        rounds = 999999999

    #validate salt
    if not isinstance(salt, bytes):
        raise TypeError("salt must be encoded as bytes")
    if any(c in salt for c in INVALID_SALT_VALUES):
        raise ValueError("invalid chars in salt")
    if len(salt) > 16:
        salt = salt[:16]

    #init helpers
    def extend(source, size_ref):
        "helper which repeats <source> digest string until it's the same length as <size_ref> string"
        assert len(source) == chunk_size
        size = len(size_ref)
        return source * int(size/chunk_size) + source[:size % chunk_size]

    #calc digest B
    b = hash(secret)
    chunk_size = b.digest_size #grab this once hash is created
    b.update(salt)
    a = b.copy() #make a copy to save a little time later
    b.update(secret)
    b_result = b.digest()
    b_extend = extend(b_result, secret)

    #begin digest A
    #a = hash(secret) <- performed above
    #a.update(salt) <- performed above
    a.update(b_extend)

    #for each bit in slen, add B or SECRET
    value = len(secret)
    while value > 0:
        if value % 2:
            a.update(b_result)
        else:
            a.update(secret)
        value >>= 1

    #finish A
    a_result = a.digest()

    #calc DP - hash of password, extended to size of password
    dp = hash(secret * len(secret))
    dp_result = extend(dp.digest(), secret)

    #calc DS - hash of salt, extended to size of salt
    ds = hash(salt * (16+bord(a_result[0])))
    ds_result = extend(ds.digest(), salt) #aka 'S'

    #
    #calc digest C
    #NOTE: this has been contorted a little to allow pre-computing
    #some of the hashes. the original algorithm was that
    #each round generates digest composed of:
    #   if round%2>0 => dp else lr
    #   if round%3>0 => ds
    #   if round%7>0 => dp
    #   if round%2>0 => lr else dp
    #where lr is digest of the last round's hash (initially = a_result)
    #

    #pre-calculate some digests to speed up odd rounds
    dp_hash = hash(dp_result).copy
    dp_ds_hash = hash(dp_result + ds_result).copy
    dp_dp_hash = hash(dp_result * 2).copy
    dp_ds_dp_hash = hash(dp_result + ds_result + dp_result).copy

    #pre-calculate some strings to speed up even rounds
    ds_dp_result = ds_result + dp_result
    dp_dp_result = dp_result * 2
    ds_dp_dp_result = ds_result + dp_dp_result

    #run through rounds
    last_result = a_result
    i = 0
    while i < rounds:
        if i % 2:
            if i % 3:
                if i % 7:
                    c = dp_ds_dp_hash()
                else:
                    c = dp_ds_hash()
            elif i % 7:
                c = dp_dp_hash()
            else:
                c = dp_hash()
            c.update(last_result)
        else:
            c = hash(last_result)
            if i % 3:
                if i % 7:
                    c.update(ds_dp_dp_result)
                else:
                    c.update(ds_dp_result)
            elif i % 7:
                c.update(dp_dp_result)
            else:
                c.update(dp_result)
        last_result = c.digest()
        i += 1

    #return unencoded result, along w/ normalized config values
    return last_result, salt, rounds
Exemple #8
0
 def iter_bits(source):
     for c in source:
         v = bord(c)
         for i in xrange(7,-1,-1):
             yield (v>>i) & 1
Exemple #9
0
def raw_sha_crypt(secret, salt, rounds, hash):
    """perform raw sha crypt

    :arg secret: password to encode (if unicode, encoded to utf-8)
    :arg salt: salt string to use (required)
    :arg rounds: int rounds
    :arg hash: hash constructor function for 256/512 variant

    :returns:
        Returns tuple of ``(unencoded checksum, normalized salt, normalized rounds)``.

    """
    #validate secret
    if not isinstance(secret, bytes):
        raise TypeError("secret must be encoded as bytes")

    #validate rounds
    if rounds < 1000:
        rounds = 1000
    if rounds > 999999999:  #pragma: no cover
        rounds = 999999999

    #validate salt
    if not isinstance(salt, bytes):
        raise TypeError("salt must be encoded as bytes")
    if any(c in salt for c in INVALID_SALT_VALUES):
        raise ValueError("invalid chars in salt")
    if len(salt) > 16:
        salt = salt[:16]

    #init helpers
    def extend(source, size_ref):
        "helper which repeats <source> digest string until it's the same length as <size_ref> string"
        assert len(source) == chunk_size
        size = len(size_ref)
        return source * int(size / chunk_size) + source[:size % chunk_size]

    #calc digest B
    b = hash(secret)
    chunk_size = b.digest_size  #grab this once hash is created
    b.update(salt)
    a = b.copy()  #make a copy to save a little time later
    b.update(secret)
    b_result = b.digest()
    b_extend = extend(b_result, secret)

    #begin digest A
    #a = hash(secret) <- performed above
    #a.update(salt) <- performed above
    a.update(b_extend)

    #for each bit in slen, add B or SECRET
    value = len(secret)
    while value > 0:
        if value % 2:
            a.update(b_result)
        else:
            a.update(secret)
        value >>= 1

    #finish A
    a_result = a.digest()

    #calc DP - hash of password, extended to size of password
    dp = hash(secret * len(secret))
    dp_result = extend(dp.digest(), secret)

    #calc DS - hash of salt, extended to size of salt
    ds = hash(salt * (16 + bord(a_result[0])))
    ds_result = extend(ds.digest(), salt)  #aka 'S'

    #
    #calc digest C
    #NOTE: this has been contorted a little to allow pre-computing
    #some of the hashes. the original algorithm was that
    #each round generates digest composed of:
    #   if round%2>0 => dp else lr
    #   if round%3>0 => ds
    #   if round%7>0 => dp
    #   if round%2>0 => lr else dp
    #where lr is digest of the last round's hash (initially = a_result)
    #

    #pre-calculate some digests to speed up odd rounds
    dp_hash = hash(dp_result).copy
    dp_ds_hash = hash(dp_result + ds_result).copy
    dp_dp_hash = hash(dp_result * 2).copy
    dp_ds_dp_hash = hash(dp_result + ds_result + dp_result).copy

    #pre-calculate some strings to speed up even rounds
    ds_dp_result = ds_result + dp_result
    dp_dp_result = dp_result * 2
    ds_dp_dp_result = ds_result + dp_dp_result

    #run through rounds
    last_result = a_result
    i = 0
    while i < rounds:
        if i % 2:
            if i % 3:
                if i % 7:
                    c = dp_ds_dp_hash()
                else:
                    c = dp_ds_hash()
            elif i % 7:
                c = dp_dp_hash()
            else:
                c = dp_hash()
            c.update(last_result)
        else:
            c = hash(last_result)
            if i % 3:
                if i % 7:
                    c.update(ds_dp_dp_result)
                else:
                    c.update(ds_dp_result)
            elif i % 7:
                c.update(dp_dp_result)
            else:
                c.update(dp_result)
        last_result = c.digest()
        i += 1

    #return unencoded result, along w/ normalized config values
    return last_result, salt, rounds