I am trying to encrypt all possible strings in a defined character set then compare them to a hash given by user input.
This is what I currently have
import string
from itertools import product
import crypt
def decrypt():
hash1 = input("Please enter the hash: ")
salt = input("Please enter the salt: ")
charSet = string.ascii_letters + string.digits
for wordchars in product(charSet, repeat=2):
hash2 = crypt.METHOD_CRYPT((wordchars), (salt))
print (hash2)
Obviously its not finished yet but I am having trouble encrypting "wordchars"
Any help is appreciated
crypt.METHOD_CRYPT
is not callable so the traceback that you provided doesn't correspond to the code in your question. crypt.METHOD_CRYPT
could be used as the second parameter for crypt.crypt()
function.
Also as @martineau pointed out wordchars
is a tuple but you need a string to pass to the crypt.crypt()
function.
From the docs:
Since a few crypt(3) extensions allow different values, with different
sizes in the salt, it is recommended to use the full crypted password
as salt when checking for a password.
To find a plain text from a defined character set given its crypted form: salt plus hash, you could:
from crypt import crypt
from itertools import product
from string import ascii_letters, digits
def decrypt(crypted, charset=ascii_letters + digits):
# find hash for all 4-char strings from the charset
# and compare with the given hash
for candidate in map(''.join, product(charset, repeat=4)):
if crypted == crypt(candidate, crypted):
return candidate
Example
salt, hashed = 'qb', '1Y.qWr.DHs6'
print(decrypt(salt + hashed))
# -> e2e4
assert crypt('e2e4', 'qb') == (salt + hashed)
The assert line makes sure that calling crypt
with the word e2e4
and the salt qb
produces qb1Y.qWr.DHs6
where qb
is the salt.
Hmm may be better use bcrypt?
https://github.com/fwenzel/python-bcrypt
Below is a simple program that does what you asked:
def gen_word(charset, L):
if L == 1:
for char in charset:
yield char
raise StopIteration
for char in charset:
for word in gen_word(charset, L - 1):
yield char + word
def encrypt(word):
'''Your encrypt function, replace with what you wish'''
return word[::-1]
charset = ['1', '2', '3']
user_word = '12'
user_hash = encrypt(user_word)
max_length = 3
for length in range(1, max_length):
for word in gen_word(charset, length):
if encrypt(word) == user_hash:
print 'Word found: %s' % word
Basically, it uses a python generator for generating words from the charset of fixed length. You can replace the encrypt function with whatever you want (in the example is string reversal used as hash).
Note that with actual modern hashing methods, it'll take forever to decrypt an ordinary password, so I don't think you could actually use this.
Here's my completely different answer based on J.F. Sebastian's answer and comment about my previous answer. The most important point being that crypt.METHOD_CRYPT
is not a callable even though the documentation somewhat confusingly calls a hashing method as if it were a method function of a module or an instance. It's not -- just think of it as an id or name of one of the various kinds of encryption supported by the crypt
module.
So the problem with you code is two-fold: One is that you were trying to use wordchars
as a string, when it actually a tuple produced by product()
and second, that you're trying to call the id crypt.METHOD_CRYPT
.
I'm at a bit of a disadvantage answering this because I'm not running Unix, don't have Python v3.3 installed, and don't completely understand what you're trying to accomplish with your code. Given all those caveats, I think something like the following which is derived from you code ought to at least run:
import string
from itertools import product
import crypt
def decrypt():
hash1 = input("Please enter the hash: ")
salt = input("Please enter the salt: ")
charSet = string.ascii_letters + string.digits
for wordchars in product(charSet, repeat=2):
hash2 = crypt.crypt(''.join(wordchars), salt=salt) # or salt=crypt.METHOD_CRYPT
print(hash2)