Skip to content

python3 port #8

Description

@Tcll

if I could submit a PR, I would

  • the machine I wrote the updated code on is offline behind a non-functional subnet.
  • I'm not willing to give Micro$**t the undeserved pleasure of me putting my sources on their platform for them to control by forking a repo, I pulled my sources when they partnered, and I intend to keep things that way.
    (call me rude all you like, I'm not the one restricting freedoms and making a profit off my sheep)

but anyways, with that out of the way, here's the updated code:

import hmac
import hashlib
from struct import Struct
from operator import xor
from itertools import starmap

try:
    from itertools import izip as zip
except ImportError: pass # py3

try: range = xrange
except NameError: pass # py3

_pack_int = Struct('>I').pack


def pbkdf2_hex(data, salt, iterations=1000, keylen=24, hashfunc=None):
    """Like :func:`pbkdf2_bin` but returns a hex encoded string."""
    return ''.join('%02x'%(v if type(v) is int else ord(v)) for v in
        pbkdf2_bin(data, salt, iterations, keylen, hashfunc))


def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
    """Returns a binary digest for the PBKDF2 hash algorithm of `data`
    with the given `salt`.  It iterates `iterations` time and produces a
    key of `keylen` bytes.  By default SHA-1 is used as hash function,
    a different hashlib `hashfunc` can be provided.
    """
    hashfunc = hashfunc or hashlib.sha1
    mac = hmac.new(data, None, hashfunc)

    buf = []
    for block in range(1, -(-keylen // mac.digest_size) + 1):
        h = mac.copy()
        h.update(salt + _pack_int(block))
        u = h.digest()
        rv = list(bytearray(u)) # needs further testing on py2 and could possibly be more performant
        for i in range(iterations - 1):
            h = mac.copy()
            h.update(bytes(u))
            u = h.digest()
            rv = starmap(xor, zip(rv, list(bytearray(u))))

        buf.extend(rv)
    return ''.join(map(chr, buf))[:keylen]

I've even ported the tests over and manually verified every expected key with your keys
(it was easier working 2 keyboards for 12 keys than copying the tests over on a flash drive)
all tests have passed.

a few things you may notice:

  • removed _pseudorandom() to improve overhead performance while maintaining namespace security
  • yes I'm locally overriding zip and range for py2, since this reflects a py3 namespace
    (@triggeredpythonists: I wouldn't do this if the original functionality was actually needed, please remain calm)

respect:

  • +1 for not following the crowd by using ''%() over ''.format() ;)

tips/advice:

  • you might want to from __future__ import print_function for porting print to print() in test()->check()

keep the credit, I care more about security than I care about being the one who ported your code ;)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions