From 127b461b11af985a52fb482f09c7cd7a08832f9d Mon Sep 17 00:00:00 2001
From: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Sun, 5 Aug 2012 16:12:10 +0200
Subject: [PATCH] [py3] Ported django.utils.crypto.

---
 django/utils/crypto.py                | 11 ++++++-----
 tests/regressiontests/utils/crypto.py | 28 +++++++++++++++------------
 2 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/django/utils/crypto.py b/django/utils/crypto.py
index 1edbb43eb3..70a07e7fde 100644
--- a/django/utils/crypto.py
+++ b/django/utils/crypto.py
@@ -50,7 +50,7 @@ def salted_hmac(key_salt, value, secret=None):
     # line is redundant and could be replaced by key = key_salt + secret, since
     # the hmac module does the same thing for keys longer than the block size.
     # However, we need to ensure that we *always* do this.
-    return hmac.new(key, msg=value, digestmod=hashlib.sha1)
+    return hmac.new(key, msg=smart_bytes(value), digestmod=hashlib.sha1)
 
 
 def get_random_string(length=12,
@@ -99,7 +99,7 @@ def _bin_to_long(x):
 
     This is a clever optimization for fast xor vector math
     """
-    return int(x.encode('hex'), 16)
+    return int(binascii.hexlify(x), 16)
 
 
 def _long_to_bin(x, hex_format_string):
@@ -112,13 +112,14 @@ def _long_to_bin(x, hex_format_string):
 
 def _fast_hmac(key, msg, digest):
     """
-    A trimmed down version of Python's HMAC implementation
+    A trimmed down version of Python's HMAC implementation.
+
+    This function operates on bytes.
     """
     dig1, dig2 = digest(), digest()
-    key = smart_bytes(key)
     if len(key) > dig1.block_size:
         key = digest(key).digest()
-    key += chr(0) * (dig1.block_size - len(key))
+    key += b'\x00' * (dig1.block_size - len(key))
     dig1.update(key.translate(_trans_36))
     dig1.update(msg)
     dig2.update(key.translate(_trans_5c))
diff --git a/tests/regressiontests/utils/crypto.py b/tests/regressiontests/utils/crypto.py
index 2bdc5ba530..52a286cb27 100644
--- a/tests/regressiontests/utils/crypto.py
+++ b/tests/regressiontests/utils/crypto.py
@@ -1,4 +1,6 @@
+from __future__ import unicode_literals
 
+import binascii
 import math
 import timeit
 import hashlib
@@ -108,15 +110,15 @@ class TestUtilsCryptoPBKDF2(unittest.TestCase):
                        "c4007d5298f9033c0241d5ab69305e7b64eceeb8d"
                        "834cfec"),
         },
-        # Check leading zeros are not stripped (#17481) 
+        # Check leading zeros are not stripped (#17481)
         {
-            "args": { 
-                "password": chr(186), 
-                "salt": "salt", 
-                "iterations": 1, 
-                "dklen": 20, 
-                "digest": hashlib.sha1, 
-            }, 
+            "args": {
+                "password": b'\xba',
+                "salt": "salt",
+                "iterations": 1,
+                "dklen": 20,
+                "digest": hashlib.sha1,
+            },
             "result": '0053d3b91a7f1e54effebd6d68771e8a6e0b2c5b',
         },
     ]
@@ -124,12 +126,14 @@ class TestUtilsCryptoPBKDF2(unittest.TestCase):
     def test_public_vectors(self):
         for vector in self.rfc_vectors:
             result = pbkdf2(**vector['args'])
-            self.assertEqual(result.encode('hex'), vector['result'])
+            self.assertEqual(binascii.hexlify(result).decode('ascii'),
+                             vector['result'])
 
     def test_regression_vectors(self):
         for vector in self.regression_vectors:
             result = pbkdf2(**vector['args'])
-            self.assertEqual(result.encode('hex'), vector['result'])
+            self.assertEqual(binascii.hexlify(result).decode('ascii'),
+                             vector['result'])
 
     def test_performance_scalability(self):
         """
@@ -140,11 +144,11 @@ class TestUtilsCryptoPBKDF2(unittest.TestCase):
         # to run the test suite and false positives caused by imprecise
         # measurement.
         n1, n2 = 200000, 800000
-        elapsed = lambda f: timeit.Timer(f, 
+        elapsed = lambda f: timeit.Timer(f,
                     'from django.utils.crypto import pbkdf2').timeit(number=1)
         t1 = elapsed('pbkdf2("password", "salt", iterations=%d)' % n1)
         t2 = elapsed('pbkdf2("password", "salt", iterations=%d)' % n2)
         measured_scale_exponent = math.log(t2 / t1, n2 / n1)
-        # This should be less than 1. We allow up to 1.2 so that tests don't 
+        # This should be less than 1. We allow up to 1.2 so that tests don't
         # fail nondeterministically too often.
         self.assertLess(measured_scale_exponent, 1.2)