title: Convert python 2 check hash to python 3
body: <p>I need to transfer users and their passwords from a python 2 system to a python 3 system.</p>
  
  <p>The PW hash looks like this:</p>
  
  <pre><code>PBKDF2$sha256$10000$KlCW+ewerd19fS9f$l+5LgvcWTzghtz77086MSVG+q5z2Lij
  </code></pre>
  
  <p>In the python 2 system I used these functions to check hashes:</p>
  
  <pre><code>def check_hash(password, hash_):
      """Check a password against an existing hash."""
      if isinstance(password, unicode):
          password = password.encode('utf-8')
      algorithm, hash_function, cost_factor, salt, hash_a = hash_.split('$')
      assert algorithm == 'PBKDF2'
      hash_a = b64decode(hash_a)
      hash_b = pbkdf2_bin(password, salt, int(cost_factor), len(hash_a),
                          getattr(hashlib, hash_function))
      assert len(hash_a) == len(hash_b)  # we requested this from pbkdf2_bin()
      # Same as "return hash_a == hash_b" but takes a constant time.
      # See http://carlos.bueno.org/2011/10/timing.html
      diff = 0
      for char_a, char_b in izip(hash_a, hash_b):
          diff |= ord(char_a) ^ ord(char_b)
      return diff == 0
  </code></pre>
  
  <p>and this:</p>
  
  <pre><code>_pack_int = Struct('&gt;I').pack
  
  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)
      def _pseudorandom(x, mac=mac):
          h = mac.copy()
          h.update(x)
          return map(ord, h.digest())
      buf = []
      for block in xrange(1, -(-keylen // mac.digest_size) + 1):
          rv = u = _pseudorandom(salt + _pack_int(block))
          for i in xrange(iterations - 1):
              u = _pseudorandom(''.join(map(chr, u)))
              rv = starmap(xor, izip(rv, u))
          buf.extend(rv)
      return ''.join(map(chr, buf))[:keylen]
  </code></pre>
  
  <p>What have I done so far:</p>
  
  <p>Right after copying the code into my python 3 scripts I had to change some variables:</p>
  
  <p><code>izip</code> -> <code>zip</code></p>
  
  <p>I kept unicode: <code>from past.builtins import unicode</code></p>
  
  <p>I kept xrange: <code>from past.builtins import xrange</code></p>
  
  <p>Now I had no script errors, but after executing the script I got an error here (in the <code>pbkdf2_bin</code> function):</p>
  
  <pre><code>rv = u = _pseudorandom(salt + _pack_int(block))
  TypeError: must be str, not bytes
  </code></pre>
  
  <p>So I fixed it by converting bytes to str:</p>
  
  <pre><code>rv = u = _pseudorandom(salt + _pack_int(block).decode('utf-8'))
  </code></pre>
  
  <p>Now the next error appears (in the <code>pbkdf2_bin</code> function):</p>
  
  <pre><code>h.update(x)
  TypeError: Unicode-objects must be encoded before hashing
  </code></pre>
  
  <p>I also fixed this with the proper encoding:</p>
  
  <pre><code>h.update(x.encode('utf-8'))
  </code></pre>
  
  <p>Next error:</p>
  
  <pre><code>  File "C:\Users\User\Eclipse-Workspace\Monteurzimmer-Remastered\hash_passwords.py", line 123, in check_hash
      getattr(hashlib, hash_function))
    File "C:\Users\User\Eclipse-Workspace\Monteurzimmer-Remastered\pbkdf2.py", line 125, in pbkdf2_bin_old_2
      u = _pseudorandom(''.join(map(chr, u)))
  TypeError: ord() expected string of length 1, but int found
  </code></pre>
  
  <p>There was an issue with the return value of <code>_pseudorandom</code> (in the <code>pbkdf2_bin</code> function). It had to be converted, so I fixed it:</p>
  
  <p><strong>Maybe the issue is here</strong></p>
  
  <pre><code>#return map(ord, h.digest()) # throws the error
  #return map(int, h.digest()) # returns nothing (length 0)
  #return list(map(ord, h.digest())) # throws the error
  return list(map(int, h.digest())) # seems to work with the correct length
  </code></pre>
  
  <p>The last error is at the end of the <code>check_hash</code> function:</p>
  
  <pre><code>File "C:\Users\User\Eclipse-Workspace\Monteurzimmer-Remastered\hash_passwords.py", line 129, in check_hash
      diff |= ord(char_a) ^ ord(char_b)
  TypeError: ord() expected string of length 1, but int found
  
  for char_a, char_b in zip(hash_a, hash_b):
      diff |= ord(char_a) ^ ord(char_b)
  </code></pre>
  
  <p>char_a is an integer and chat_b is not. I was able to fix this by converting char_a to the real char:</p>
  
  <pre><code>for char_a, char_b in zip(hash_a, hash_b):
      diff |= ord(chr(char_a)) ^ ord(char_b)
  </code></pre>
  
  <p>Finally I had no errors, but it tells me the entered password is wrong,
  so somewhere is an error, because I know that the password is correct and it works on the python 2 app.</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>Someone mentioned the 2to3 library, so I tried it. All in all it has done the same things, which I have done already and the problem is the same.</p>
  
  <p><strong>EDIT for bounty</strong></p>
  
  <p>To sum it up. The 2 functions which I posted above come from python 2 and work in python 2. </p>
  
  <p>This hash:</p>
  
  <pre><code>PBKDF2$sha256$10000$r+Gy8ewTkE7Qv0V7$uqmgaPgpaT1RSvFPMcGb6cGaFAhjyxE9
  </code></pre>
  
  <p>is this password: <code>Xs12'io!12</code></p>
  
  <p>I can correctly login with this password on my python 2 app.</p>
  
  <p>Now I want to use the same two functions in python 3, but eventhough I worked through all errors, it tells me the password is wrong.</p>
  
  <p>The imports:</p>
  
  <pre><code>import hmac
  import hashlib
  from struct import Struct
  from operator import xor
  from itertools import izip, starmap
  
  from base64 import b64encode, b64decode
  import hashlib
  from itertools import izip
  from os import urandom
  import random
  import string
  </code></pre>
  
  <p>These imports are used in the python 2 script.</p>