Hash brute forcing

solo

In [1]:
from hashlib import md5
from itertools import product
from string import ascii_lowercase

def all_words(alphabet, length):
    return (''.join(letters) for letters in product(alphabet, repeat=length))

def is_collision(passwd, hash_value):
    return md5(passwd.encode('ascii')).hexdigest() == hash_value

def brute_force(hash_value, alphabet, length, begin=0, end=None):
    end = len(alphabet) if end is None else end
    for first_letter in alphabet[begin:end]:
        for word in all_words(alphabet, length - 1):
            passwd = first_letter + word
            if is_collision(passwd, hash_value):
                return passwd

%time print(brute_force('95ebc3c7b3b9f1d2c40fec14415d3cb8', ascii_lowercase, 5))
zzzzz
CPU times: user 33.5 s, sys: 34.8 ms, total: 33.5 s
Wall time: 33.6 s

threading

In [1]:
import threading
from hashlib import md5
from itertools import product, tee, islice
from string import ascii_lowercase

def all_words(alphabet, length):
    return (''.join(letters) for letters in product(alphabet, repeat=length))

def is_collision(passwd, hash_value):
    return md5(passwd.encode('ascii')).hexdigest() == hash_value

def brute_force(hash_value, alphabet, length, begin=0, end=None):
    end = len(alphabet) if end is None else end
    for first_letter in alphabet[begin:end]:
        for word in all_words(alphabet, length - 1):
            passwd = first_letter + word
            if is_collision(passwd, hash_value):
                print(passwd)
                return passwd

def pairs(iterable):
    items, nexts = tee(iterable, 2)
    nexts = islice(nexts, 1, None)
    return zip(items, nexts)

def parallel_brute_force(hash_value, alphabet, length):
    pool = []
    partition = [0, 13, 26]
    for p in pairs(partition):
        worker = threading.Thread(target=brute_force, args=(hash_value, alphabet, length, p[0], p[1]))
        worker.start()
        pool.append(worker)
    for worker in pool:
        worker.join()

%time print(parallel_brute_force('95ebc3c7b3b9f1d2c40fec14415d3cb8', ascii_lowercase, 5))
zzzzz
None
CPU times: user 42.1 s, sys: 468 ms, total: 42.6 s
Wall time: 42.7 s

multiprocessing

In [1]:
import multiprocessing
from hashlib import md5
from itertools import product, tee, islice
from string import ascii_lowercase

def all_words(alphabet, length):
    return (''.join(letters) for letters in product(alphabet, repeat=length))

def is_collision(passwd, hash_value):
    return md5(passwd.encode('ascii')).hexdigest() == hash_value

def brute_force(hash_value, alphabet, length, begin=0, end=None):
    end = len(alphabet) if end is None else end
    for first_letter in alphabet[begin:end]:
        for word in all_words(alphabet, length - 1):
            passwd = first_letter + word
            if is_collision(passwd, hash_value):
                print(passwd)
                return passwd

def pairs(iterable):
    items, nexts = tee(iterable, 2)
    nexts = islice(nexts, 1, None)
    return zip(items, nexts)

def parallel_brute_force(hash_value, alphabet, length):
    pool = []
    partition = [0, 13, 26]
    for p in pairs(partition):
        worker = multiprocessing.Process(target=brute_force, args=(hash_value, alphabet, length, p[0], p[1]))
        worker.start()
        pool.append(worker)
    for worker in pool:
        worker.join()

%time print(parallel_brute_force('95ebc3c7b3b9f1d2c40fec14415d3cb8', ascii_lowercase, 5))
None
CPU times: user 3.5 ms, sys: 7.96 ms, total: 11.5 ms
Wall time: 18.6 s
zzzzz

concurrent.futures

In [1]:
from concurrent.futures import ProcessPoolExecutor
from hashlib import md5
from itertools import product, tee, islice
from string import ascii_lowercase

def all_words(alphabet, length):
    return (''.join(letters) for letters in product(alphabet, repeat=length))

def is_collision(passwd, hash_value):
    return md5(passwd.encode('ascii')).hexdigest() == hash_value

def brute_force(hash_value, alphabet, length, begin=0, end=None):
    end = len(alphabet) if end is None else end
    for first_letter in alphabet[begin:end]:
        for word in all_words(alphabet, length - 1):
            passwd = first_letter + word
            if is_collision(passwd, hash_value):
                return passwd

def pairs(iterable):
    items, nexts = tee(iterable, 2)
    nexts = islice(nexts, 1, None)
    return zip(items, nexts)

def parallel_brute_force(hash_value, alphabet, length):
    futures = []
    with ProcessPoolExecutor(max_workers=2) as executor:
        partition = range(len(alphabet) + 1)
        for p in pairs(partition):
            future = executor.submit(brute_force, hash_value, alphabet, length, p[0], p[1]) 
            futures.append(future)
    results = [future.result() for future in futures]
    collisions = [r for r in results if r is not None]
    if collisions:
        return collisions[0]
    
%time print(parallel_brute_force('95ebc3c7b3b9f1d2c40fec14415d3cb8', ascii_lowercase, 5))
zzzzz
CPU times: user 22.7 ms, sys: 12.5 ms, total: 35.2 ms
Wall time: 19.4 s