Python Making Brute Froce Crack Faster












6












$begingroup$


I made an Brute Force Cracker with python, but its extremely slow. How can i make it faster?



import itertools
import string
import time

def guess_password(real):
chars = string.ascii_uppercase + string.digits
password_length = 23
start = time.perf_counter()
for guess in itertools.product(chars, repeat=password_length):
guess = ''.join(guess)
t = list(guess)
t[5] = '-'
t[11] = '-'
t[17] = '-'
tg = ''.join(t)
if tg == real:
return 'Scan complete. Code: '{}'. Time elapsed: {}'.format(tg, (time.perf_counter() - start))

print(guess_password('E45E7-BYXJM-7STEY-K5H7L'))


As I said, its extremely slow. It crackes in at least 9 days.










share|improve this question









$endgroup$








  • 6




    $begingroup$
    For a start you could change password_length to 20, you are needlessly duplicating your searches (each of your proposal passwords is constructed 36^3 different times)
    $endgroup$
    – Russ Hyde
    Feb 12 at 16:27












  • $begingroup$
    @RussHyde thanks for your comment. I compared my old code and your code with AAAAA-AAAAA-AAAAA-FORTN but my old code is faster than yours with 5 seconds. My old code got 25 seconds but your one got 30 seconds. Why? I thought it was going to make it faster.
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 16:40








  • 2




    $begingroup$
    Do it a thousand times, and post the mean and std-dev
    $endgroup$
    – Russ Hyde
    Feb 12 at 16:59










  • $begingroup$
    You could also strip the "-" from a single copy of the real password, rather than mutating every guess
    $endgroup$
    – Russ Hyde
    Feb 12 at 17:14






  • 1




    $begingroup$
    @AkınOktayATALAY Try Russ Hyde's suggested change with a password that extends past the first dash and you'll see the difference much more clearly: AAAAA-AAAAA-AAAAB-AAAAA.
    $endgroup$
    – Daniel Wagner
    Feb 13 at 1:34
















6












$begingroup$


I made an Brute Force Cracker with python, but its extremely slow. How can i make it faster?



import itertools
import string
import time

def guess_password(real):
chars = string.ascii_uppercase + string.digits
password_length = 23
start = time.perf_counter()
for guess in itertools.product(chars, repeat=password_length):
guess = ''.join(guess)
t = list(guess)
t[5] = '-'
t[11] = '-'
t[17] = '-'
tg = ''.join(t)
if tg == real:
return 'Scan complete. Code: '{}'. Time elapsed: {}'.format(tg, (time.perf_counter() - start))

print(guess_password('E45E7-BYXJM-7STEY-K5H7L'))


As I said, its extremely slow. It crackes in at least 9 days.










share|improve this question









$endgroup$








  • 6




    $begingroup$
    For a start you could change password_length to 20, you are needlessly duplicating your searches (each of your proposal passwords is constructed 36^3 different times)
    $endgroup$
    – Russ Hyde
    Feb 12 at 16:27












  • $begingroup$
    @RussHyde thanks for your comment. I compared my old code and your code with AAAAA-AAAAA-AAAAA-FORTN but my old code is faster than yours with 5 seconds. My old code got 25 seconds but your one got 30 seconds. Why? I thought it was going to make it faster.
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 16:40








  • 2




    $begingroup$
    Do it a thousand times, and post the mean and std-dev
    $endgroup$
    – Russ Hyde
    Feb 12 at 16:59










  • $begingroup$
    You could also strip the "-" from a single copy of the real password, rather than mutating every guess
    $endgroup$
    – Russ Hyde
    Feb 12 at 17:14






  • 1




    $begingroup$
    @AkınOktayATALAY Try Russ Hyde's suggested change with a password that extends past the first dash and you'll see the difference much more clearly: AAAAA-AAAAA-AAAAB-AAAAA.
    $endgroup$
    – Daniel Wagner
    Feb 13 at 1:34














6












6








6


3



$begingroup$


I made an Brute Force Cracker with python, but its extremely slow. How can i make it faster?



import itertools
import string
import time

def guess_password(real):
chars = string.ascii_uppercase + string.digits
password_length = 23
start = time.perf_counter()
for guess in itertools.product(chars, repeat=password_length):
guess = ''.join(guess)
t = list(guess)
t[5] = '-'
t[11] = '-'
t[17] = '-'
tg = ''.join(t)
if tg == real:
return 'Scan complete. Code: '{}'. Time elapsed: {}'.format(tg, (time.perf_counter() - start))

print(guess_password('E45E7-BYXJM-7STEY-K5H7L'))


As I said, its extremely slow. It crackes in at least 9 days.










share|improve this question









$endgroup$




I made an Brute Force Cracker with python, but its extremely slow. How can i make it faster?



import itertools
import string
import time

def guess_password(real):
chars = string.ascii_uppercase + string.digits
password_length = 23
start = time.perf_counter()
for guess in itertools.product(chars, repeat=password_length):
guess = ''.join(guess)
t = list(guess)
t[5] = '-'
t[11] = '-'
t[17] = '-'
tg = ''.join(t)
if tg == real:
return 'Scan complete. Code: '{}'. Time elapsed: {}'.format(tg, (time.perf_counter() - start))

print(guess_password('E45E7-BYXJM-7STEY-K5H7L'))


As I said, its extremely slow. It crackes in at least 9 days.







python python-3.x






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Feb 12 at 16:21









Akın Oktay ATALAYAkın Oktay ATALAY

434




434








  • 6




    $begingroup$
    For a start you could change password_length to 20, you are needlessly duplicating your searches (each of your proposal passwords is constructed 36^3 different times)
    $endgroup$
    – Russ Hyde
    Feb 12 at 16:27












  • $begingroup$
    @RussHyde thanks for your comment. I compared my old code and your code with AAAAA-AAAAA-AAAAA-FORTN but my old code is faster than yours with 5 seconds. My old code got 25 seconds but your one got 30 seconds. Why? I thought it was going to make it faster.
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 16:40








  • 2




    $begingroup$
    Do it a thousand times, and post the mean and std-dev
    $endgroup$
    – Russ Hyde
    Feb 12 at 16:59










  • $begingroup$
    You could also strip the "-" from a single copy of the real password, rather than mutating every guess
    $endgroup$
    – Russ Hyde
    Feb 12 at 17:14






  • 1




    $begingroup$
    @AkınOktayATALAY Try Russ Hyde's suggested change with a password that extends past the first dash and you'll see the difference much more clearly: AAAAA-AAAAA-AAAAB-AAAAA.
    $endgroup$
    – Daniel Wagner
    Feb 13 at 1:34














  • 6




    $begingroup$
    For a start you could change password_length to 20, you are needlessly duplicating your searches (each of your proposal passwords is constructed 36^3 different times)
    $endgroup$
    – Russ Hyde
    Feb 12 at 16:27












  • $begingroup$
    @RussHyde thanks for your comment. I compared my old code and your code with AAAAA-AAAAA-AAAAA-FORTN but my old code is faster than yours with 5 seconds. My old code got 25 seconds but your one got 30 seconds. Why? I thought it was going to make it faster.
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 16:40








  • 2




    $begingroup$
    Do it a thousand times, and post the mean and std-dev
    $endgroup$
    – Russ Hyde
    Feb 12 at 16:59










  • $begingroup$
    You could also strip the "-" from a single copy of the real password, rather than mutating every guess
    $endgroup$
    – Russ Hyde
    Feb 12 at 17:14






  • 1




    $begingroup$
    @AkınOktayATALAY Try Russ Hyde's suggested change with a password that extends past the first dash and you'll see the difference much more clearly: AAAAA-AAAAA-AAAAB-AAAAA.
    $endgroup$
    – Daniel Wagner
    Feb 13 at 1:34








6




6




$begingroup$
For a start you could change password_length to 20, you are needlessly duplicating your searches (each of your proposal passwords is constructed 36^3 different times)
$endgroup$
– Russ Hyde
Feb 12 at 16:27






$begingroup$
For a start you could change password_length to 20, you are needlessly duplicating your searches (each of your proposal passwords is constructed 36^3 different times)
$endgroup$
– Russ Hyde
Feb 12 at 16:27














$begingroup$
@RussHyde thanks for your comment. I compared my old code and your code with AAAAA-AAAAA-AAAAA-FORTN but my old code is faster than yours with 5 seconds. My old code got 25 seconds but your one got 30 seconds. Why? I thought it was going to make it faster.
$endgroup$
– Akın Oktay ATALAY
Feb 12 at 16:40






$begingroup$
@RussHyde thanks for your comment. I compared my old code and your code with AAAAA-AAAAA-AAAAA-FORTN but my old code is faster than yours with 5 seconds. My old code got 25 seconds but your one got 30 seconds. Why? I thought it was going to make it faster.
$endgroup$
– Akın Oktay ATALAY
Feb 12 at 16:40






2




2




$begingroup$
Do it a thousand times, and post the mean and std-dev
$endgroup$
– Russ Hyde
Feb 12 at 16:59




$begingroup$
Do it a thousand times, and post the mean and std-dev
$endgroup$
– Russ Hyde
Feb 12 at 16:59












$begingroup$
You could also strip the "-" from a single copy of the real password, rather than mutating every guess
$endgroup$
– Russ Hyde
Feb 12 at 17:14




$begingroup$
You could also strip the "-" from a single copy of the real password, rather than mutating every guess
$endgroup$
– Russ Hyde
Feb 12 at 17:14




1




1




$begingroup$
@AkınOktayATALAY Try Russ Hyde's suggested change with a password that extends past the first dash and you'll see the difference much more clearly: AAAAA-AAAAA-AAAAB-AAAAA.
$endgroup$
– Daniel Wagner
Feb 13 at 1:34




$begingroup$
@AkınOktayATALAY Try Russ Hyde's suggested change with a password that extends past the first dash and you'll see the difference much more clearly: AAAAA-AAAAA-AAAAB-AAAAA.
$endgroup$
– Daniel Wagner
Feb 13 at 1:34










2 Answers
2






active

oldest

votes


















8












$begingroup$

You should exploit the structure of the password, if it has any. Here you have a 20 character password separated into four blocks of five characters each, joined with a -. So don't go on generating all combinations of length 23, only to throw most of them away.



You also str.join the guess, then convert it to a list, then replace the values and str.join it again. You could have saved yourself the first str.join entirely by directly converting to list.



You know the length of the password, so no need to hardcode it. Just get it from the real password (or, in a more realistic cracker, pass the length as a parameter).



With these small changes your code would become:



def guess_password(real):
chars = string.ascii_uppercase + string.digits
password_format = "-".join(["{}"*5] * 4)
password_length = len(real) - 3
for guess in itertools.product(chars, repeat=password_length):
guess = password_format.format(*guess)
if guess == real:
return guess


Here I used some string formatting to get the right format.



Note also that the timing and output string are not in there. Instead make the former a decorator and the latter part of the calling code, which should be protected by a if __name__ == "__main__": guard to allow you to import from this script without running the brute force cracker:



from time import perf_counter
from functools import wraps

def timeit(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = perf_counter()
ret = func(*args, **kwargs)
print(f"Time elapsed: {perf_counter() - start}")
return ret
return wrapper

@timeit
def guess_password(real):
...

if __name__ == "__main__":
real_password = 'E45E7-BYXJM-7STEY-K5H7L'
if guess_password(real_password):
print(f"Scan completed: {real_password}")


On my machine this takes 9.96 s ± 250 ms, whereas your code takes 12.3 s ± 2.87 s for the input string "AAAAA-AAAAA-AAAAA-FORTN".



But in the end you will always be limited by the fact that there are a lot of twenty character strings consisting of upper case letters and digits. Namely, there are $36^{20} = 13,367,494,538,843,734,067,838,845,976,576$ different passwords that need to be checked (well, statistically you only need to check half of them, on average, until you find your real password, but you might get unlucky). Not even writing your loop in Assembler is this going to run in less than days.






share|improve this answer











$endgroup$













  • $begingroup$
    I got output guess = password_format.format(*guess) IndexError: tuple index out of range
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 17:23










  • $begingroup$
    @AkınOktayATALAY: In that case you gave it a password of a different format (or used a previous revision, I had a typo in the password length). It works with the two given strings.
    $endgroup$
    – Graipher
    Feb 12 at 17:26










  • $begingroup$
    I think I should change password_length = len(real) - 5 to password_length = len(real) - 3
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 17:27










  • $begingroup$
    @AkınOktayATALAY: Yes, I already did that (about a minute after posting the answer for the first time), just update the page.
    $endgroup$
    – Graipher
    Feb 12 at 17:31








  • 1




    $begingroup$
    @AkınOktayATALAY: Take your time. It is usually not a bad idea to wait at least 24 hours, so everybody on the globe had a chance to see the question and think about answering. Maybe I missed something.
    $endgroup$
    – Graipher
    Feb 12 at 17:32



















4












$begingroup$

There are other ways beyond improving the code itself.




  1. Beyond changes which reduce allocations a lot, like:


t = list(guess)


instead of:



guess = ''.join(guess)
t = list(guess)


Reduces the runtime 11s -> 6.7s.




  1. You can use a different runtime which will speed up almost any code:


➜  /tmp python3 foo.py
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 6.716003532
➜ /tmp pypy3 foo.py
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 3.135087580012623



  1. Or precompile the existing code into a module which you can load again in your standard python code:


# cythonize -3 -i foo.py
Compiling /private/tmp/foo.py because it changed.
[1/1] Cythonizing /private/tmp/foo.py
running build_ext
building 'foo' extension
...

# ipython3

In [1]: import foo
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 3.846977077





share|improve this answer









$endgroup$













  • $begingroup$
    thanks the cythonize worked but the PyPy is 3x slow for me. Do you know why?
    $endgroup$
    – Akın Oktay ATALAY
    Feb 13 at 14:43










  • $begingroup$
    ¯_(ツ)_/¯ sorry
    $endgroup$
    – viraptor
    Feb 13 at 22:56













Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213313%2fpython-making-brute-froce-crack-faster%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









8












$begingroup$

You should exploit the structure of the password, if it has any. Here you have a 20 character password separated into four blocks of five characters each, joined with a -. So don't go on generating all combinations of length 23, only to throw most of them away.



You also str.join the guess, then convert it to a list, then replace the values and str.join it again. You could have saved yourself the first str.join entirely by directly converting to list.



You know the length of the password, so no need to hardcode it. Just get it from the real password (or, in a more realistic cracker, pass the length as a parameter).



With these small changes your code would become:



def guess_password(real):
chars = string.ascii_uppercase + string.digits
password_format = "-".join(["{}"*5] * 4)
password_length = len(real) - 3
for guess in itertools.product(chars, repeat=password_length):
guess = password_format.format(*guess)
if guess == real:
return guess


Here I used some string formatting to get the right format.



Note also that the timing and output string are not in there. Instead make the former a decorator and the latter part of the calling code, which should be protected by a if __name__ == "__main__": guard to allow you to import from this script without running the brute force cracker:



from time import perf_counter
from functools import wraps

def timeit(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = perf_counter()
ret = func(*args, **kwargs)
print(f"Time elapsed: {perf_counter() - start}")
return ret
return wrapper

@timeit
def guess_password(real):
...

if __name__ == "__main__":
real_password = 'E45E7-BYXJM-7STEY-K5H7L'
if guess_password(real_password):
print(f"Scan completed: {real_password}")


On my machine this takes 9.96 s ± 250 ms, whereas your code takes 12.3 s ± 2.87 s for the input string "AAAAA-AAAAA-AAAAA-FORTN".



But in the end you will always be limited by the fact that there are a lot of twenty character strings consisting of upper case letters and digits. Namely, there are $36^{20} = 13,367,494,538,843,734,067,838,845,976,576$ different passwords that need to be checked (well, statistically you only need to check half of them, on average, until you find your real password, but you might get unlucky). Not even writing your loop in Assembler is this going to run in less than days.






share|improve this answer











$endgroup$













  • $begingroup$
    I got output guess = password_format.format(*guess) IndexError: tuple index out of range
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 17:23










  • $begingroup$
    @AkınOktayATALAY: In that case you gave it a password of a different format (or used a previous revision, I had a typo in the password length). It works with the two given strings.
    $endgroup$
    – Graipher
    Feb 12 at 17:26










  • $begingroup$
    I think I should change password_length = len(real) - 5 to password_length = len(real) - 3
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 17:27










  • $begingroup$
    @AkınOktayATALAY: Yes, I already did that (about a minute after posting the answer for the first time), just update the page.
    $endgroup$
    – Graipher
    Feb 12 at 17:31








  • 1




    $begingroup$
    @AkınOktayATALAY: Take your time. It is usually not a bad idea to wait at least 24 hours, so everybody on the globe had a chance to see the question and think about answering. Maybe I missed something.
    $endgroup$
    – Graipher
    Feb 12 at 17:32
















8












$begingroup$

You should exploit the structure of the password, if it has any. Here you have a 20 character password separated into four blocks of five characters each, joined with a -. So don't go on generating all combinations of length 23, only to throw most of them away.



You also str.join the guess, then convert it to a list, then replace the values and str.join it again. You could have saved yourself the first str.join entirely by directly converting to list.



You know the length of the password, so no need to hardcode it. Just get it from the real password (or, in a more realistic cracker, pass the length as a parameter).



With these small changes your code would become:



def guess_password(real):
chars = string.ascii_uppercase + string.digits
password_format = "-".join(["{}"*5] * 4)
password_length = len(real) - 3
for guess in itertools.product(chars, repeat=password_length):
guess = password_format.format(*guess)
if guess == real:
return guess


Here I used some string formatting to get the right format.



Note also that the timing and output string are not in there. Instead make the former a decorator and the latter part of the calling code, which should be protected by a if __name__ == "__main__": guard to allow you to import from this script without running the brute force cracker:



from time import perf_counter
from functools import wraps

def timeit(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = perf_counter()
ret = func(*args, **kwargs)
print(f"Time elapsed: {perf_counter() - start}")
return ret
return wrapper

@timeit
def guess_password(real):
...

if __name__ == "__main__":
real_password = 'E45E7-BYXJM-7STEY-K5H7L'
if guess_password(real_password):
print(f"Scan completed: {real_password}")


On my machine this takes 9.96 s ± 250 ms, whereas your code takes 12.3 s ± 2.87 s for the input string "AAAAA-AAAAA-AAAAA-FORTN".



But in the end you will always be limited by the fact that there are a lot of twenty character strings consisting of upper case letters and digits. Namely, there are $36^{20} = 13,367,494,538,843,734,067,838,845,976,576$ different passwords that need to be checked (well, statistically you only need to check half of them, on average, until you find your real password, but you might get unlucky). Not even writing your loop in Assembler is this going to run in less than days.






share|improve this answer











$endgroup$













  • $begingroup$
    I got output guess = password_format.format(*guess) IndexError: tuple index out of range
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 17:23










  • $begingroup$
    @AkınOktayATALAY: In that case you gave it a password of a different format (or used a previous revision, I had a typo in the password length). It works with the two given strings.
    $endgroup$
    – Graipher
    Feb 12 at 17:26










  • $begingroup$
    I think I should change password_length = len(real) - 5 to password_length = len(real) - 3
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 17:27










  • $begingroup$
    @AkınOktayATALAY: Yes, I already did that (about a minute after posting the answer for the first time), just update the page.
    $endgroup$
    – Graipher
    Feb 12 at 17:31








  • 1




    $begingroup$
    @AkınOktayATALAY: Take your time. It is usually not a bad idea to wait at least 24 hours, so everybody on the globe had a chance to see the question and think about answering. Maybe I missed something.
    $endgroup$
    – Graipher
    Feb 12 at 17:32














8












8








8





$begingroup$

You should exploit the structure of the password, if it has any. Here you have a 20 character password separated into four blocks of five characters each, joined with a -. So don't go on generating all combinations of length 23, only to throw most of them away.



You also str.join the guess, then convert it to a list, then replace the values and str.join it again. You could have saved yourself the first str.join entirely by directly converting to list.



You know the length of the password, so no need to hardcode it. Just get it from the real password (or, in a more realistic cracker, pass the length as a parameter).



With these small changes your code would become:



def guess_password(real):
chars = string.ascii_uppercase + string.digits
password_format = "-".join(["{}"*5] * 4)
password_length = len(real) - 3
for guess in itertools.product(chars, repeat=password_length):
guess = password_format.format(*guess)
if guess == real:
return guess


Here I used some string formatting to get the right format.



Note also that the timing and output string are not in there. Instead make the former a decorator and the latter part of the calling code, which should be protected by a if __name__ == "__main__": guard to allow you to import from this script without running the brute force cracker:



from time import perf_counter
from functools import wraps

def timeit(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = perf_counter()
ret = func(*args, **kwargs)
print(f"Time elapsed: {perf_counter() - start}")
return ret
return wrapper

@timeit
def guess_password(real):
...

if __name__ == "__main__":
real_password = 'E45E7-BYXJM-7STEY-K5H7L'
if guess_password(real_password):
print(f"Scan completed: {real_password}")


On my machine this takes 9.96 s ± 250 ms, whereas your code takes 12.3 s ± 2.87 s for the input string "AAAAA-AAAAA-AAAAA-FORTN".



But in the end you will always be limited by the fact that there are a lot of twenty character strings consisting of upper case letters and digits. Namely, there are $36^{20} = 13,367,494,538,843,734,067,838,845,976,576$ different passwords that need to be checked (well, statistically you only need to check half of them, on average, until you find your real password, but you might get unlucky). Not even writing your loop in Assembler is this going to run in less than days.






share|improve this answer











$endgroup$



You should exploit the structure of the password, if it has any. Here you have a 20 character password separated into four blocks of five characters each, joined with a -. So don't go on generating all combinations of length 23, only to throw most of them away.



You also str.join the guess, then convert it to a list, then replace the values and str.join it again. You could have saved yourself the first str.join entirely by directly converting to list.



You know the length of the password, so no need to hardcode it. Just get it from the real password (or, in a more realistic cracker, pass the length as a parameter).



With these small changes your code would become:



def guess_password(real):
chars = string.ascii_uppercase + string.digits
password_format = "-".join(["{}"*5] * 4)
password_length = len(real) - 3
for guess in itertools.product(chars, repeat=password_length):
guess = password_format.format(*guess)
if guess == real:
return guess


Here I used some string formatting to get the right format.



Note also that the timing and output string are not in there. Instead make the former a decorator and the latter part of the calling code, which should be protected by a if __name__ == "__main__": guard to allow you to import from this script without running the brute force cracker:



from time import perf_counter
from functools import wraps

def timeit(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = perf_counter()
ret = func(*args, **kwargs)
print(f"Time elapsed: {perf_counter() - start}")
return ret
return wrapper

@timeit
def guess_password(real):
...

if __name__ == "__main__":
real_password = 'E45E7-BYXJM-7STEY-K5H7L'
if guess_password(real_password):
print(f"Scan completed: {real_password}")


On my machine this takes 9.96 s ± 250 ms, whereas your code takes 12.3 s ± 2.87 s for the input string "AAAAA-AAAAA-AAAAA-FORTN".



But in the end you will always be limited by the fact that there are a lot of twenty character strings consisting of upper case letters and digits. Namely, there are $36^{20} = 13,367,494,538,843,734,067,838,845,976,576$ different passwords that need to be checked (well, statistically you only need to check half of them, on average, until you find your real password, but you might get unlucky). Not even writing your loop in Assembler is this going to run in less than days.







share|improve this answer














share|improve this answer



share|improve this answer








edited Feb 12 at 17:25

























answered Feb 12 at 17:15









GraipherGraipher

24.8k53587




24.8k53587












  • $begingroup$
    I got output guess = password_format.format(*guess) IndexError: tuple index out of range
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 17:23










  • $begingroup$
    @AkınOktayATALAY: In that case you gave it a password of a different format (or used a previous revision, I had a typo in the password length). It works with the two given strings.
    $endgroup$
    – Graipher
    Feb 12 at 17:26










  • $begingroup$
    I think I should change password_length = len(real) - 5 to password_length = len(real) - 3
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 17:27










  • $begingroup$
    @AkınOktayATALAY: Yes, I already did that (about a minute after posting the answer for the first time), just update the page.
    $endgroup$
    – Graipher
    Feb 12 at 17:31








  • 1




    $begingroup$
    @AkınOktayATALAY: Take your time. It is usually not a bad idea to wait at least 24 hours, so everybody on the globe had a chance to see the question and think about answering. Maybe I missed something.
    $endgroup$
    – Graipher
    Feb 12 at 17:32


















  • $begingroup$
    I got output guess = password_format.format(*guess) IndexError: tuple index out of range
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 17:23










  • $begingroup$
    @AkınOktayATALAY: In that case you gave it a password of a different format (or used a previous revision, I had a typo in the password length). It works with the two given strings.
    $endgroup$
    – Graipher
    Feb 12 at 17:26










  • $begingroup$
    I think I should change password_length = len(real) - 5 to password_length = len(real) - 3
    $endgroup$
    – Akın Oktay ATALAY
    Feb 12 at 17:27










  • $begingroup$
    @AkınOktayATALAY: Yes, I already did that (about a minute after posting the answer for the first time), just update the page.
    $endgroup$
    – Graipher
    Feb 12 at 17:31








  • 1




    $begingroup$
    @AkınOktayATALAY: Take your time. It is usually not a bad idea to wait at least 24 hours, so everybody on the globe had a chance to see the question and think about answering. Maybe I missed something.
    $endgroup$
    – Graipher
    Feb 12 at 17:32
















$begingroup$
I got output guess = password_format.format(*guess) IndexError: tuple index out of range
$endgroup$
– Akın Oktay ATALAY
Feb 12 at 17:23




$begingroup$
I got output guess = password_format.format(*guess) IndexError: tuple index out of range
$endgroup$
– Akın Oktay ATALAY
Feb 12 at 17:23












$begingroup$
@AkınOktayATALAY: In that case you gave it a password of a different format (or used a previous revision, I had a typo in the password length). It works with the two given strings.
$endgroup$
– Graipher
Feb 12 at 17:26




$begingroup$
@AkınOktayATALAY: In that case you gave it a password of a different format (or used a previous revision, I had a typo in the password length). It works with the two given strings.
$endgroup$
– Graipher
Feb 12 at 17:26












$begingroup$
I think I should change password_length = len(real) - 5 to password_length = len(real) - 3
$endgroup$
– Akın Oktay ATALAY
Feb 12 at 17:27




$begingroup$
I think I should change password_length = len(real) - 5 to password_length = len(real) - 3
$endgroup$
– Akın Oktay ATALAY
Feb 12 at 17:27












$begingroup$
@AkınOktayATALAY: Yes, I already did that (about a minute after posting the answer for the first time), just update the page.
$endgroup$
– Graipher
Feb 12 at 17:31






$begingroup$
@AkınOktayATALAY: Yes, I already did that (about a minute after posting the answer for the first time), just update the page.
$endgroup$
– Graipher
Feb 12 at 17:31






1




1




$begingroup$
@AkınOktayATALAY: Take your time. It is usually not a bad idea to wait at least 24 hours, so everybody on the globe had a chance to see the question and think about answering. Maybe I missed something.
$endgroup$
– Graipher
Feb 12 at 17:32




$begingroup$
@AkınOktayATALAY: Take your time. It is usually not a bad idea to wait at least 24 hours, so everybody on the globe had a chance to see the question and think about answering. Maybe I missed something.
$endgroup$
– Graipher
Feb 12 at 17:32













4












$begingroup$

There are other ways beyond improving the code itself.




  1. Beyond changes which reduce allocations a lot, like:


t = list(guess)


instead of:



guess = ''.join(guess)
t = list(guess)


Reduces the runtime 11s -> 6.7s.




  1. You can use a different runtime which will speed up almost any code:


➜  /tmp python3 foo.py
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 6.716003532
➜ /tmp pypy3 foo.py
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 3.135087580012623



  1. Or precompile the existing code into a module which you can load again in your standard python code:


# cythonize -3 -i foo.py
Compiling /private/tmp/foo.py because it changed.
[1/1] Cythonizing /private/tmp/foo.py
running build_ext
building 'foo' extension
...

# ipython3

In [1]: import foo
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 3.846977077





share|improve this answer









$endgroup$













  • $begingroup$
    thanks the cythonize worked but the PyPy is 3x slow for me. Do you know why?
    $endgroup$
    – Akın Oktay ATALAY
    Feb 13 at 14:43










  • $begingroup$
    ¯_(ツ)_/¯ sorry
    $endgroup$
    – viraptor
    Feb 13 at 22:56


















4












$begingroup$

There are other ways beyond improving the code itself.




  1. Beyond changes which reduce allocations a lot, like:


t = list(guess)


instead of:



guess = ''.join(guess)
t = list(guess)


Reduces the runtime 11s -> 6.7s.




  1. You can use a different runtime which will speed up almost any code:


➜  /tmp python3 foo.py
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 6.716003532
➜ /tmp pypy3 foo.py
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 3.135087580012623



  1. Or precompile the existing code into a module which you can load again in your standard python code:


# cythonize -3 -i foo.py
Compiling /private/tmp/foo.py because it changed.
[1/1] Cythonizing /private/tmp/foo.py
running build_ext
building 'foo' extension
...

# ipython3

In [1]: import foo
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 3.846977077





share|improve this answer









$endgroup$













  • $begingroup$
    thanks the cythonize worked but the PyPy is 3x slow for me. Do you know why?
    $endgroup$
    – Akın Oktay ATALAY
    Feb 13 at 14:43










  • $begingroup$
    ¯_(ツ)_/¯ sorry
    $endgroup$
    – viraptor
    Feb 13 at 22:56
















4












4








4





$begingroup$

There are other ways beyond improving the code itself.




  1. Beyond changes which reduce allocations a lot, like:


t = list(guess)


instead of:



guess = ''.join(guess)
t = list(guess)


Reduces the runtime 11s -> 6.7s.




  1. You can use a different runtime which will speed up almost any code:


➜  /tmp python3 foo.py
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 6.716003532
➜ /tmp pypy3 foo.py
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 3.135087580012623



  1. Or precompile the existing code into a module which you can load again in your standard python code:


# cythonize -3 -i foo.py
Compiling /private/tmp/foo.py because it changed.
[1/1] Cythonizing /private/tmp/foo.py
running build_ext
building 'foo' extension
...

# ipython3

In [1]: import foo
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 3.846977077





share|improve this answer









$endgroup$



There are other ways beyond improving the code itself.




  1. Beyond changes which reduce allocations a lot, like:


t = list(guess)


instead of:



guess = ''.join(guess)
t = list(guess)


Reduces the runtime 11s -> 6.7s.




  1. You can use a different runtime which will speed up almost any code:


➜  /tmp python3 foo.py
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 6.716003532
➜ /tmp pypy3 foo.py
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 3.135087580012623



  1. Or precompile the existing code into a module which you can load again in your standard python code:


# cythonize -3 -i foo.py
Compiling /private/tmp/foo.py because it changed.
[1/1] Cythonizing /private/tmp/foo.py
running build_ext
building 'foo' extension
...

# ipython3

In [1]: import foo
Scan complete. Code: 'AAAAA-AAAAA-AAAAA-FORTN'. Time elapsed: 3.846977077






share|improve this answer












share|improve this answer



share|improve this answer










answered Feb 13 at 0:21









viraptorviraptor

1913




1913












  • $begingroup$
    thanks the cythonize worked but the PyPy is 3x slow for me. Do you know why?
    $endgroup$
    – Akın Oktay ATALAY
    Feb 13 at 14:43










  • $begingroup$
    ¯_(ツ)_/¯ sorry
    $endgroup$
    – viraptor
    Feb 13 at 22:56




















  • $begingroup$
    thanks the cythonize worked but the PyPy is 3x slow for me. Do you know why?
    $endgroup$
    – Akın Oktay ATALAY
    Feb 13 at 14:43










  • $begingroup$
    ¯_(ツ)_/¯ sorry
    $endgroup$
    – viraptor
    Feb 13 at 22:56


















$begingroup$
thanks the cythonize worked but the PyPy is 3x slow for me. Do you know why?
$endgroup$
– Akın Oktay ATALAY
Feb 13 at 14:43




$begingroup$
thanks the cythonize worked but the PyPy is 3x slow for me. Do you know why?
$endgroup$
– Akın Oktay ATALAY
Feb 13 at 14:43












$begingroup$
¯_(ツ)_/¯ sorry
$endgroup$
– viraptor
Feb 13 at 22:56






$begingroup$
¯_(ツ)_/¯ sorry
$endgroup$
– viraptor
Feb 13 at 22:56




















draft saved

draft discarded




















































Thanks for contributing an answer to Code Review Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213313%2fpython-making-brute-froce-crack-faster%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

How to change which sound is reproduced for terminal bell?

Can I use Tabulator js library in my java Spring + Thymeleaf project?

Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents