Make password/hash verification algorithm more efficient I am trying to guess the paswords from the etc/shadow file(it has 43 user/passwords). And I have been given some hits about the passwords:


Length is between 4 and 8 characters
There can be only 2 numbers and only at the end
Capital letters only in the beginning


So I started just with a small group composed by 4 character with 2 digits in it. But it takes so much time to process:

import crypt
import string
import itertools
import datetime

dir = "shadow3"
file = open(dir, 'r').readlines() #Read all the 43 hashes

username = []
hashed = []
c = 0
cc = 0

for x in file: #Split the hash and the username
    usr, hshd, wtf, iss, this, thing, here, doing, example = x.split(':')
    username.append(usr)
    hashed.append(hshd)
#GRUPO1 4 caracteres 2 numeros
letters = string.ascii_lowercase
digits = string.digits
grupo1=[]
group1=itertools.product(letters,repeat=2)
group1b=itertools.product(digits,repeat=2)
for x in itertools.product(group1,group1b):  #Join the possible iterations
  string=''.join([''.join(k) for k in x])
  grupo1.append(string)
print(len(grupo1))
for y in grupo1:#Get the one of the iterations and try it 
  prueba=y
  for x in hashed: #Verify if that iteration is the password to any of the 43 users
    rehashed = crypt.crypt(prueba, x)
    if rehashed == x: #Password is found
        print('La contraseña del usuario ' + username[c] + ' es ' + prueba)
        cc = 1
    c = c + 1
if cc == 0: #after all iterations password is not found
    print('Lo sentimos "' + prueba + '" no es la contraseña de ningun usuario')


How can I improve the efficiency of this? I have a GTX 1070 if it helps for any kind of GPU processing.(I have no idea of this)

Just this small part of 4 characters is taking me for hours, it has still not finished.
Starting with the code in my answer to your related question, we can factor out the source of the words being guessed and encapsulate it all in functions:

def get_users_to_crack(file_name):
    users = {}
    with open(file_name) as file:
        for line in file:
            username, hashed_password, *_ = line.split(':')
            users[username] = hashed_password
    return users

def crack(users, words):
    cracked_users = {}
    for password in words:
        if not users:
            print("Cracked all passwords")
            return cracked_users, {}
        for username, hashed_password in users.items():
            if crypt.crypt(password, hashed_password) == hashed_password:
                print(f'La contraseña del usuario {username} es {password}')
                cracked_users[username] = password
                del users[username]
    return cracked_users, users


Now we just need a supplier of words. This can be either from a file, similar to your other question:

def dictionary_attack(file_name):
    with open(file_name) as file:
        for line in file:
            word = line.rstrip('\n').capitalize()
            if 4 &lt;= len(word) &lt;= 8:
                yield word


Or you build it yourself, according to the scheme you supplied here:

from string import ascii_lowercase as a_z, ascii_uppercase as A_Z, digits
from itertools import product

def get_chars(length):
    """Produces the allowed chars according to the scheme given
       [a-zA-Z][a-z]*(0-5)[a-z0-9]*2"""
    assert length &gt; 2
    return [a_z + A_Z] + [a_z] * (length - 3) + [a_z + digits] * 2

def brute_force(min_length, max_length, get_chars):
    for length in range(min_length, max_length + 1):
        for word in product(*get_chars(length)):
            yield "".join(word)


You can then combine them into one nice tool:

if __name__ == "__main__":
    users = get_users_to_crack("shadow3")
    n = len(users)

    users_cracked_1, users = crack(users, dictionary_attack('out68.lst'))
    print(f"Cracked {len(users_cracked_1)} out of {n} users passwords using a dictionary attack")

    users_cracked_2, users = crack(users, brute_force(4, 8, get_chars))
    print(f"Cracked {len(users_cracked_2)} out of {n} users passwords using brute force")

    if users:
        print(f"{len(users)} users passwords not cracked")