Last active
May 7, 2024 14:24
-
-
Save 84adam/51b30ef4b8edd420f6f1d6ab6eea40fe to your computer and use it in GitHub Desktop.
bcrypt/argon2/pbkdf2 hash test -- target a work factor that requires at least 250 ms to compute
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # bcrypt-argon2-pbkdf2-hash-test.py | |
| import threading | |
| import bcrypt | |
| from pwdlib.hashers import argon2 | |
| from pwdlib import PasswordHash | |
| from pwdlib.hashers.argon2 import Argon2Hasher | |
| from hashlib import pbkdf2_hmac | |
| import time | |
| import psutil | |
| from statistics import median | |
| def monitor_cpu(): | |
| while not stop_thread: | |
| global cpu_load | |
| cpu_load.append(psutil.cpu_percent(interval=1, percpu=True)) | |
| def hash_password(algorithm, work_factor, memory_cost=None): | |
| password = b"your_secret_password" | |
| start_time = time.time() | |
| if algorithm == 'bcrypt': | |
| _ = bcrypt.hashpw(password, bcrypt.gensalt(work_factor)) | |
| elif algorithm == 'pbkdf2': | |
| # Assuming salt is also bytes; normally should be securely generated | |
| salt = b'some_random_salt' | |
| # pbkdf2_hmac requires the number of iterations, the salt, the desired hash name, and the password | |
| _ = pbkdf2_hmac('sha256', password, salt, work_factor) | |
| else: | |
| # assume argon2 | |
| if memory_cost == None: | |
| memory_cost = 65536 # 64 MiB; see: https://github.com/hynek/argon2-cffi/blob/0805dbdded04dc3c4bc8573236c80be50ff30113/src/argon2/profiles.py#L30-L38 | |
| password_hash = PasswordHash(( | |
| Argon2Hasher(time_cost=work_factor, memory_cost=memory_cost), | |
| )) | |
| _ = password_hash.hash(password) | |
| end_time = time.time() | |
| if algorithm == 'argon2': | |
| print(f"Hashing with {algorithm} work factor of {work_factor} and memory cost of {memory_cost} took {end_time - start_time:.3f} seconds.") | |
| else: | |
| print(f"Hashing with {algorithm} work factor of {work_factor} took {end_time - start_time:.3f} seconds.") | |
| if __name__ == "__main__": | |
| # select from: 'pbkdf2', 'argon2' or 'bcrypt' | |
| algorithm = 'argon2' | |
| # for argon2 | |
| memory_cost = 256 * 1024 # 256 MiB; see: https://github.com/sparrowwallet/drongo/blob/master/src/main/java/com/sparrowwallet/drongo/crypto/Argon2KeyDeriver.java | |
| min_work = 5 | |
| max_work = 30 | |
| # for bcrypt | |
| if algorithm == 'bcrypt': | |
| if max_work > 20: | |
| max_work = 20 | |
| # for argon2 / bcrypt | |
| work_factors = [x for x in range(min_work, max_work+1)] | |
| # for pbkdf2 | |
| if algorithm == 'pbkdf2': | |
| min_work = 700_000 | |
| max_work = 1_000_000 | |
| work_factors = [x for x in range(min_work, max_work+1, 20_000)] # Increment by 20000 for noticeable differences | |
| for work_factor in work_factors: | |
| cpu_load = [] | |
| stop_thread = False | |
| thread = threading.Thread(target=monitor_cpu) | |
| thread.start() | |
| try: | |
| if algorithm in ['bcrypt', 'pbkdf2']: | |
| hash_password(algorithm, work_factor) | |
| elif algorithm == 'argon2': | |
| hash_password(algorithm, work_factor, memory_cost) | |
| else: | |
| raise Exception(f"algorithm '{algorithm}' not configured") | |
| finally: | |
| stop_thread = True | |
| thread.join() | |
| all_max = [] | |
| all_avg = [] | |
| for index, cpu in enumerate(cpu_load): | |
| all_max.append(max(cpu)) | |
| all_avg.append(sum(cpu) / len(cpu)) | |
| print(f"Max single CPU core usage: {max(all_max):.2f}%") | |
| print(f"Average usage all cores during test: {(sum(all_avg) / len(all_avg)):.2f}%\n") |
Author
Author
added pbkdf2 -- example output on a 4-core machine:
Hashing with pbkdf2 work factor of 700000 took 0.256 seconds.
Max single CPU core usage: 18.70%
Average usage all cores during test: 2.59%
Hashing with pbkdf2 work factor of 720000 took 0.264 seconds.
Max single CPU core usage: 24.70%
Average usage all cores during test: 6.14%
Hashing with pbkdf2 work factor of 740000 took 0.288 seconds.
Max single CPU core usage: 20.20%
Average usage all cores during test: 7.15%
Hashing with pbkdf2 work factor of 760000 took 0.280 seconds.
Max single CPU core usage: 20.90%
Average usage all cores during test: 2.99%
Hashing with pbkdf2 work factor of 780000 took 0.289 seconds.
Max single CPU core usage: 22.80%
Average usage all cores during test: 3.23%
Hashing with pbkdf2 work factor of 800000 took 0.292 seconds.
Max single CPU core usage: 23.70%
Average usage all cores during test: 3.21%
Hashing with pbkdf2 work factor of 820000 took 0.298 seconds.
Max single CPU core usage: 23.10%
Average usage all cores during test: 3.26%
Hashing with pbkdf2 work factor of 840000 took 0.310 seconds.
Max single CPU core usage: 29.60%
Average usage all cores during test: 4.09%
Hashing with pbkdf2 work factor of 860000 took 0.316 seconds.
Max single CPU core usage: 24.20%
Average usage all cores during test: 3.27%
Hashing with pbkdf2 work factor of 880000 took 0.326 seconds.
Max single CPU core usage: 25.00%
Average usage all cores during test: 3.75%
Hashing with pbkdf2 work factor of 900000 took 0.331 seconds.
Max single CPU core usage: 23.90%
Average usage all cores during test: 3.24%
Hashing with pbkdf2 work factor of 920000 took 0.338 seconds.
Max single CPU core usage: 25.80%
Average usage all cores during test: 3.73%
Hashing with pbkdf2 work factor of 940000 took 0.345 seconds.
Max single CPU core usage: 26.70%
Average usage all cores during test: 3.73%
Hashing with pbkdf2 work factor of 960000 took 0.355 seconds.
Max single CPU core usage: 28.60%
Average usage all cores during test: 4.33%
Hashing with pbkdf2 work factor of 980000 took 0.363 seconds.
Max single CPU core usage: 31.20%
Average usage all cores during test: 4.29%
Hashing with pbkdf2 work factor of 1000000 took 0.364 seconds.
Max single CPU core usage: 27.60%
Average usage all cores during test: 4.08%
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
argon2with 5-30 work factor, using256 MiBof memory on a 4-core machine: