From bc5620629377f44598154fe4421da002c33f2775 Mon Sep 17 00:00:00 2001 From: Alex Burke Date: Thu, 12 Sep 2024 11:48:33 +0200 Subject: [PATCH] Repair make_hash on Python 3. --- mig/shared/pwcrypto.py | 13 ++++---- tests/test_mig_shared_pwcrypto.py | 49 +++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 tests/test_mig_shared_pwcrypto.py diff --git a/mig/shared/pwcrypto.py b/mig/shared/pwcrypto.py index a20344f0a..c2642256d 100644 --- a/mig/shared/pwcrypto.py +++ b/mig/shared/pwcrypto.py @@ -35,6 +35,7 @@ from builtins import zip, range from base64 import b64encode, b64decode, b16encode, b16decode, \ urlsafe_b64encode, urlsafe_b64decode +import codecs from os import urandom from random import SystemRandom from string import ascii_lowercase, ascii_uppercase, digits @@ -114,12 +115,14 @@ def best_crypt_salt(configuration): return salt_data -def make_hash(password): +def make_hash(password, _urandom=urandom): """Generate a random salt and return a new hash for the password.""" - salt = b64encode(urandom(SALT_LENGTH)) - derived = b64encode(hashlib.pbkdf2_hmac(HASH_FUNCTION, - force_utf8(password), salt, - COST_FACTOR, KEY_LENGTH)) + salt = b64encode(_urandom(SALT_LENGTH)) + password_bytes = codecs.encode(password, 'utf8') + password_hashed = hashlib.pbkdf2_hmac(HASH_FUNCTION, + password_bytes, salt, + COST_FACTOR, KEY_LENGTH) + derived = b64encode(password_hashed) return 'PBKDF2${}${}${}${}'.format(HASH_FUNCTION, COST_FACTOR, salt, derived) diff --git a/tests/test_mig_shared_pwcrypto.py b/tests/test_mig_shared_pwcrypto.py new file mode 100644 index 000000000..e984c19a0 --- /dev/null +++ b/tests/test_mig_shared_pwcrypto.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# +# --- BEGIN_HEADER --- +# +# Copyright (C) 2003-2024 The MiG Project by the Science HPC Center at UCPH +# +# This file is part of MiG. +# +# MiG is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# MiG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. +# +# --- END_HEADER --- +# + +"""Unit test pwcrypto functions""" + +import os +import sys + +sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), "."))) + +from support import PY2, MigTestCase, temppath, testmain +from mig.shared.pwcrypto import * + +class MigSharedPwcrypto_make_hash(MigTestCase): + def test_pickle_string(self): + expected_py2 = "PBKDF2$sha256$10000$MDAwMDAwMDAwMDAw$epib2rEg/HYTQZFnCp7hmIGZ6rzHnViy" + expected_py3 = "PBKDF2$sha256$10000$b'MDAwMDAwMDAwMDAw'$b'epib2rEg/HYTQZFnCp7hmIGZ6rzHnViy'" + expected = expected_py2 if PY2 else expected_py3 + + actual = make_hash('foobar', _urandom=lambda vlen: b'0' * vlen) + + self.assertEqual(actual, expected, "mismatch pickling string") + + +if __name__ == '__main__': + testmain()