-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcrack.py
135 lines (105 loc) · 3.87 KB
/
crack.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# CS50x 2019/Week6/Pset6/Crack
# This solution came from experimentation.
# It checks all points with submit50.
# Imports
import crypt # crypt.crypt(word, salt)
import logging
import os
import sys
import string
import time
from multiprocessing import Process, Queue, Value
# Constants
PW_MAX_LEN = 5 # Password maximum length
HASH_INPUTS = " " + string.ascii_letters
NUM_PHYS_CORES = os.cpu_count()
# Worker Functions
def Worker_PlaintextGen(aninput, producer_queue, sharedmemflag):
"""Produces string permutations to be places in producer queue.
Stops after sharedmemflag value is True/int(1) or after all
possible permutations have been produced.
"""
# PW_MAX_LEN times for loops
for fifth in aninput:
for fourth in aninput:
for third in aninput:
for second in aninput:
for first in aninput[1:]:
if not sharedmemflag.value:
test_pw = f"{first}{second}{third}{fourth}{fifth}".strip()
producer_queue.put(test_pw)
else:
producer_queue.cancel_join_thread() # Prevent join_thread() from blocking.
time.sleep(1)
return # Found
# Failure
if not sharedmemflag.value:
sys.exit("No password cracked")
# 2nd Found exit option due to racing conditions
if sharedmemflag.value:
return # Found.2
def Worker_CrackPw(consumer_queue, user_hash, salt, sharedmemflag):
"""Uses DES-based crypt function to hash inputs in parameter aninput
and compare the hashes to the user_hash. If a pw is cracked,
the sharedmemflag is set to True/int(1)
"""
while not sharedmemflag.value:
test_pw = consumer_queue.get()
test_hash = crypt.crypt(test_pw, salt)
if test_hash == user_hash:
sharedmemflag.value = 1 # Set shared boolean found to True
print(f"password found: {test_pw}")
time.sleep(1)
if sharedmemflag:
# logging.debug(f"exiting with sharedmemflag: {bool(sharedmemflag.value)}")
return
else:
sys.exit("No password could be cracked")
# Main function
def main():
"""Gets input hash and salt from command line,
spawns worker threads, initializes queue,
calls worker function"""
print(os.cpu_count())
# Check user input
if len(sys.argv) != 2:
sys.exit("Usage: python crack.py hash")
# Extract hash and salt from user input
user_hash = sys.argv[1]
salt = user_hash[:2]
# Inputs for Worker_PlaintextGen
inputs = HASH_INPUTS
# Producer/Consumer queue for Worker_PlaintextGen outputs
# and Worker_Crack inputs
hybrid_queue = Queue()
# Initialize memory Value shared between worker processes,
# indicating if password was cracked, to False
found = Value('i', 0) # Boolean found == false
# Spawn processes calling the worker functions
processes = []
# Measure execution time of workers
start_time = time.time()
# PlaintextGen workers
process = Process(name="Worker_PlaintextGen",
target=Worker_PlaintextGen,
args=(inputs, hybrid_queue,
found),
daemon=True)
processes.append(process)
process.start()
# CrackPW workers
for i in range(NUM_PHYS_CORES - 1):
process = Process(name=f"Worker_CrackPW-{i}",
target=Worker_CrackPw,
args=(hybrid_queue, user_hash,
salt, found),
daemon=True)
processes.append(process)
process.start()
# Start and join processes
for process in processes:
process.join()
# Success
sys.exit(0)
if __name__ == "__main__":
main()