mitsuhiko / mitsuhiko/python-pbkdf2

python3 port

Open
#8 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
149
Forks
28
PR merge metrics
No merged PRs in 30d

Description

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 ;)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the existing PBKDF2 implementation and its test suite, then compare them with the Python 3 code and ported tests included in the issue. Done means the port is integrated without breaking the existing behavior and the full test suite passes.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cryptography
Issue type
Refactor
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.