-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
458 additions
and
2 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
## diff | ||
```bash | ||
python3 password_cracking_parallel.py | ||
Processing number combinations concurrently | ||
Processing 0 to 9999998 | ||
Processing 9999999 to 19999998 | ||
Processing 19999999 to 29999998 | ||
Processing 29999999 to 39999998 | ||
Processing 39999999 to 49999998 | ||
Processing 49999999 to 59999998 | ||
Processing 59999999 to 69999998 | ||
Processing 69999999 to 79999998 | ||
Processing 79999999 to 89999998 | ||
Processing 89999999 to 99999999 | ||
Waiting for chunks to finish | ||
PASSWORD CRACKED: 87654321 | ||
PROCESS TIME: 9.041890041 | ||
|
||
|
||
python3.11 password_cracking_parallel.py | ||
Processing number combinations concurrently | ||
Processing 0 to 9999998 | ||
Processing 9999999 to 19999998 | ||
Processing 19999999 to 29999998 | ||
Processing 29999999 to 39999998 | ||
Processing 39999999 to 49999998 | ||
Processing 49999999 to 59999998 | ||
Processing 59999999 to 69999998 | ||
Processing 69999999 to 79999998 | ||
Processing 79999999 to 89999998 | ||
Processing 89999999 to 99999999 | ||
Waiting for chunks to finish | ||
PASSWORD CRACKED: 87654321 | ||
PROCESS TIME: 7.3755793329910375 | ||
``` |
33 changes: 33 additions & 0 deletions
33
vs/python/password_cracking_parallel/library_thread_pool.py
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
"""Library thread pool implementation""" | ||
|
||
import time | ||
import os | ||
from concurrent.futures import ThreadPoolExecutor, as_completed | ||
from threading import current_thread | ||
|
||
|
||
def cpu_waster(i: int) -> str: | ||
"""Wasting the processor time, professionally""" | ||
name = current_thread().getName() | ||
print(f"{name} doing Task {i}") | ||
time.sleep(3) | ||
return f"Task {i} completed" | ||
|
||
|
||
def main() -> None: | ||
with ThreadPoolExecutor( | ||
max_workers=os.cpu_count(), | ||
thread_name_prefix="Pool_Thread" | ||
) as pool: | ||
tasks = [] | ||
for i in range(20): | ||
tasks.append(pool.submit(cpu_waster, i)) | ||
|
||
print("All work requests sent") | ||
for task in as_completed(tasks): | ||
print(task.result()) | ||
print("All work completed") | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
"""Using message queues for IPC between threads""" | ||
|
||
import time | ||
from queue import Queue | ||
from threading import Thread, current_thread | ||
|
||
|
||
class Worker(Thread): | ||
def __init__(self, queue: Queue, id: int): | ||
super().__init__(name=str(id)) | ||
self.queue = queue | ||
|
||
def run(self) -> None: | ||
while not self.queue.empty(): | ||
# getting new data for processing from the queue | ||
item = self.queue.get() | ||
print(f"Thread {current_thread().name}: " | ||
f"processing item {item} from the queue") | ||
time.sleep(2) | ||
|
||
|
||
def main(thread_num: int) -> None: | ||
# creating a queue and putting integer number into it to process | ||
q = Queue() | ||
for i in range(10): | ||
q.put(i) | ||
|
||
threads = [] | ||
# running threads to process data from the queue | ||
for i in range(thread_num): | ||
thread = Worker(q, i + 1) | ||
thread.start() | ||
threads.append(thread) | ||
|
||
# block the main thread until the child threads has finished | ||
for thread in threads: | ||
thread.join() | ||
|
||
|
||
if __name__ == "__main__": | ||
thread_num = 4 | ||
main(thread_num) |
93 changes: 93 additions & 0 deletions
93
vs/python/password_cracking_parallel/password_cracking_parallel.py
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
"""Program for cracking the password consisting of only numbers using multi | ||
cores in parallel""" | ||
|
||
import os | ||
import math | ||
import time | ||
import typing as T | ||
import hashlib | ||
from multiprocessing import Pool | ||
|
||
ChunkRange = T.Tuple[int, int] | ||
|
||
|
||
def get_combinations(*, length: int, min_number: int = 0, max_number: int = None) -> T.List[str]: | ||
"""Generate all possible password combinations""" | ||
combinations = [] | ||
if not max_number: | ||
# calculating maximum number based on the length | ||
max_number = int(math.pow(10, length) - 1) | ||
|
||
# go through all possible combinations in a given range | ||
for i in range(min_number, max_number + 1): | ||
str_num = str(i) | ||
# fill in the missing numbers with zeros | ||
zeros = "0" * (length - len(str_num)) | ||
combinations.append("".join((zeros, str_num))) | ||
return combinations | ||
|
||
|
||
def get_crypto_hash(password: str) -> str: | ||
""""Calculating cryptographic hash of the password""" | ||
return hashlib.sha256(password.encode()).hexdigest() | ||
|
||
|
||
def check_password(expected_crypto_hash: str, | ||
possible_password: str) -> bool: | ||
actual_crypto_hash = get_crypto_hash(possible_password) | ||
# compare the resulted cryptographic hash with the one stored on the system | ||
return expected_crypto_hash == actual_crypto_hash | ||
|
||
|
||
def get_chunks(num_ranges: int, | ||
length: int) -> T.Iterator[ChunkRange]: | ||
"""Splitting the passwords into chunks using break points""" | ||
max_number = int(math.pow(10, length) - 1) | ||
chunk_starts = [int(max_number / num_ranges * i) | ||
for i in range(num_ranges)] | ||
chunk_ends = [start_point - 1 | ||
for start_point in | ||
chunk_starts[1:]] + [max_number] | ||
return zip(chunk_starts, chunk_ends) | ||
|
||
|
||
def crack_chunk(crypto_hash: str, length: int, chunk_start: int, | ||
chunk_end: int) -> T.Union[str, None]: | ||
"""Brute force the password combinations""" | ||
print(f"Processing {chunk_start} to {chunk_end}") | ||
combinations = get_combinations(length=length, min_number=chunk_start, | ||
max_number=chunk_end) | ||
for combination in combinations: | ||
if check_password(crypto_hash, combination): | ||
return combination # found it | ||
return # not found | ||
|
||
|
||
def crack_password_parallel(crypto_hash: str, length: int) -> None: | ||
"""Orchestrate cracking the password between different processes""" | ||
# getting number of available processors | ||
num_cores = os.cpu_count() | ||
print("Processing number combinations concurrently") | ||
start_time = time.perf_counter() | ||
|
||
# processing each chunk in a separate process concurrently | ||
with Pool() as pool: | ||
arguments = ((crypto_hash, length, chunk_start, chunk_end) for | ||
chunk_start, chunk_end in | ||
get_chunks(num_cores, length)) | ||
results = pool.starmap(crack_chunk, arguments) | ||
print("Waiting for chunks to finish") | ||
pool.close() | ||
pool.join() | ||
|
||
result = [res for res in results if res] | ||
print(f"PASSWORD CRACKED: {result[0]}") | ||
process_time = time.perf_counter() - start_time | ||
print(f"PROCESS TIME: {process_time}") | ||
|
||
|
||
if __name__ == "__main__": | ||
crypto_hash = \ | ||
"e24df920078c3dd4e7e8d2442f00e5c9ab2a231bb3918d65cc50906e49ecaef4" | ||
length = 8 | ||
crack_password_parallel(crypto_hash, length) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
"""Using pipes for IPC between threads""" | ||
|
||
from threading import Thread, current_thread | ||
from multiprocessing import Pipe | ||
from multiprocessing.connection import Connection | ||
|
||
|
||
class Writer(Thread): | ||
"""Writer thread will write messages into the pipe""" | ||
def __init__(self, conn: Connection): | ||
super().__init__() | ||
self.conn = conn | ||
self.name = "Writer" | ||
|
||
def run(self) -> None: | ||
print(f"{current_thread().name}: Sending rubber duck...") | ||
self.conn.send("Rubber duck") | ||
|
||
|
||
class Reader(Thread): | ||
"""Reader thread will read messages from the pipe""" | ||
def __init__(self, conn: Connection): | ||
super().__init__() | ||
self.conn = conn | ||
self.name = "Reader" | ||
|
||
def run(self) -> None: | ||
print(f"{current_thread().name}: Reading...") | ||
msg = self.conn.recv() | ||
print(f"{current_thread().name}: Received: {msg}") | ||
|
||
|
||
def main() -> None: | ||
# Connections for reading and writing | ||
reader_conn, writer_conn = Pipe() | ||
reader = Reader(reader_conn) | ||
writer = Writer(writer_conn) | ||
|
||
threads = [ | ||
writer, | ||
reader | ||
] | ||
# start threads | ||
for thread in threads: | ||
thread.start() | ||
|
||
# block the main thread until the child threads has finished | ||
for thread in threads: | ||
thread.join() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
"""Using shared memory IPC between threads""" | ||
|
||
import time | ||
from threading import Thread, current_thread | ||
|
||
SIZE = 5 | ||
# setup shared memory | ||
shared_memory = [-1] * SIZE | ||
|
||
|
||
class Producer(Thread): | ||
def run(self) -> None: | ||
self.name = "Producer" | ||
global shared_memory | ||
for i in range(SIZE): | ||
print(f"{current_thread().name}: Writing {int(i)}") | ||
shared_memory[i - 1] = i | ||
|
||
|
||
class Consumer(Thread): | ||
def run(self) -> None: | ||
self.name = "Consumer" | ||
global shared_memory | ||
for i in range(SIZE): | ||
# try reading the data until succession | ||
while True: | ||
line = shared_memory[i] | ||
if line == -1: | ||
# data hasn't change - waiting for a second | ||
print(f"{current_thread().name}: Data not available\n" | ||
f"Sleeping for 1 second before retrying") | ||
time.sleep(1) | ||
continue | ||
print(f"{current_thread().name}: Read: {int(line)}") | ||
break | ||
|
||
|
||
def main() -> None: | ||
threads = [ | ||
Consumer(), | ||
Producer(), | ||
] | ||
|
||
# start threads | ||
for thread in threads: | ||
thread.start() | ||
|
||
# block the main thread until the child threads has finished | ||
for thread in threads: | ||
thread.join() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
""" Using sockets for IPC """ | ||
|
||
import socket | ||
import os.path | ||
import time | ||
from threading import Thread, current_thread | ||
|
||
# in Unix everything is a file | ||
SOCK_FILE = "./mailbox" | ||
BUFFER_SIZE = 1024 | ||
|
||
|
||
class Sender(Thread): | ||
def run(self) -> None: | ||
self.name = "Sender" | ||
# AF_UNIX (Unix domain socket) and SOCK_STREAM are constants | ||
# that represent the socket family and socket type respectively | ||
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | ||
client.connect(SOCK_FILE) | ||
|
||
messages = ["Hello", " ", "world!"] | ||
for msg in messages: | ||
print(f"{current_thread().name}: Send: '{msg}'") | ||
client.sendall(str.encode(msg)) | ||
|
||
client.close() | ||
|
||
|
||
class Receiver(Thread): | ||
def run(self) -> None: | ||
self.name = "Receiver" | ||
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | ||
# bind socket to the file | ||
server.bind(SOCK_FILE) | ||
# let's start listening mode for this socket | ||
server.listen() | ||
|
||
print(f"{current_thread().name}: Listening for incoming messages...") | ||
# accept a connection | ||
conn, addr = server.accept() | ||
|
||
while True: | ||
# receive data from socket | ||
data = conn.recv(BUFFER_SIZE) | ||
if not data: | ||
break | ||
message = data.decode() | ||
print(f"{current_thread().name}: Received: '{message}'") | ||
|
||
server.close() | ||
|
||
|
||
def main() -> None: | ||
# verify if exists the sock file | ||
if os.path.exists(SOCK_FILE): | ||
os.remove(SOCK_FILE) | ||
|
||
# receiver will create a socket and socket file | ||
receiver = Receiver() | ||
receiver.start() | ||
# waiting untill the socket has been created | ||
time.sleep(1) | ||
sender = Sender() | ||
sender.start() | ||
|
||
# block the main thread until the child threads has finished | ||
for thread in [receiver, sender]: | ||
thread.join() | ||
|
||
# cleaning up | ||
os.remove(SOCK_FILE) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Oops, something went wrong.