2
\$\begingroup\$

I've been making a brute force program for fun. This program tries to guess a password using brute force. I've tried many things to help increase the efficiency. Here it is: (Sorry for the lack of comments)

from itertools import product
from time import time
def findamount(find):
  constValues = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
                 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
                 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
  dictValues = {constValues[n]:n+1 for n in range(62)}
  value = 0
  for n in range(len(str(find))):
    x = len(str(find)) - (n+1)
    value += dictValues[find[n]] * (62**x)
  return value
def fast(password):
  password = tuple(password)
  origtime = time()
  length = 1
  constValues = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
                 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
                 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
  for a in range(10000000): #More efficient than while True
    for n in product(constValues, repeat=length):
      if n == password:
        amount = findamount(''.join(list(n)))
        amountTime = time() - origtime
        if amountTime == 0:
          print(f"Length = {length}, Amounts = {amount}\nTime elapsed = 0 secs\nAttempts per sec = ? TIME TOO SHORT")
        else:
          print(f"Length = {length}, Amounts = {amount}\nTime elapsed = {amountTime} secs\n Attempts per sec (estimate) = {amount/amountTime}")
        print(f"DONE! PASSWORD: {password}")
        return
    length += 1
    if length > 3:
      amount = findamount(''.join(n))
      amountTime = time() - origtime
      print(f"Length = {length-1}, Amounts = {amount}, Password = {''.join(n)}\nTime elapsed = {amountTime} secs\nAttempts per sec = {amount/amountTime}\nEstimated Time: {findamount(''.join(password))/(amount/amountTime)} secs")
password = input(">>> ")
fast(password)

My current average is 6-16M per sec. However, I want to see how to increase it on my code. I tried using threading and this is the attempt:

from itertools import product
from time import time
from threading import Thread
from more_itertools import divide
def findamount(find):
  constValues = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
                 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
                 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
  dictValues = {constValues[n]:n+1 for n in range(62)}
  value = 0
  for n in range(len(str(find))):
    x = len(str(find)) - (n+1)
    value += dictValues[find[n]] * (62**x)
  return value
def fast(password, amountOfThreads, thread):
  password = tuple(password)
  origtime = time()
  length = 1
  constValues = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
                 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
                 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
  for a in range(10000000): #More efficient than while True (I think)
    for n in divide(amountOfThreads, product(constValues, repeat=length))[thread-1]:
      if n == password:
        amount = findamount(''.join(list(n)))
        amountTime = time() - origtime
        if amountTime == 0:
          print(f"Length = {length}, Amounts = {amount}\nTime elapsed = 0 secs\nAttempts per sec = ? TIME TOO SHORT")
        else:
          print(f"Length = {length}, Amounts = {amount}\nTime elapsed = {amountTime} secs\n Attempts per sec (estimate) = {amount/amountTime}")
        print(f"DONE! PASSWORD: {password}")
        raise SystemExit
    length += 1
    if length > 3:
      amount = findamount(''.join(n))
      amountTime = time() - origtime
      print(f"Length = {length-1}, Amounts = {amount}, Password = {''.join(n)}\nTime elapsed = {amountTime} secs\nAttempts per sec = {amount/amountTime}\nEstimated Time: {findamount(''.join(password))/(amount/amountTime)} secs")
password = input(">>> ")
if __name__ == "__main__":
  amountOfThreads = int(input("How much threads?"))
  for n in range(amountOfThreads):
    Thread(target=fast, args = (password, amountOfThreads, n+1)).start()

It gets much slower. If you input 1 thread it does 2-3M per sec and 2+ threads in total does about 200k per sec (totalling all threads). Is there any way to improve this code to allow threading to be useful, or any other efficient code I should add? Also, is threading the most efficient way to do this?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ The constraint in the program is computation, not IO. Using threads, as you discovered, won't help (search for the Python GIL). Instead see the multiprocessing library. \$\endgroup\$
    – FMc
    Jun 1, 2021 at 6:50

1 Answer 1

1
\$\begingroup\$

I've found a few ways to improve my code:

  1. Instead of doing for a in range(10000000): and length += 1, you can just merge the two and do for length in range(1, 10000000):. This would help increase efficiency because in the previous case, a would be length-1, meaning if I use range(1, 10000000) (meaning a starts at 1 instead of 0), a would be equal to length.

  2. The second improvement is in this code:

if length > 3:  
  amount = findamount(''.join(n))
  amountTime = time() - origtime
  print(f"Length = {length}, Amounts = {amount}, Password = {''.join(n)}\nTime elapsed = {amountTime} secs\nAttempts per sec = {amount/amountTime}\nEstimated Time: {findamount(''.join(password))/(amount/amountTime)} secs")

''.join(n) is calculated twice, I could just do currentPassword = ''.join(n) so ''.join(n) would only be calculated once, and use currentPassword for the two times I used ''.join(n).

  1. This improvement is also on the code above. the print part can be improved. This isnt an efficiency improvement, but a readability improvement. Changing the print function to:
print(f"Length = {length}, Amounts = {amount}, Password = {currentAmount}\nTime elapsed = {amountTime} secs",
"\nAttempts per sec = {amount/amountTime}\nEstimated Time: {findamount(''.join(password))/(amount/amountTime)} secs")

I'll update this every time I find something new.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.