codegirl
Posts: 1
Joined: Fri Nov 24, 2017 6:48 am
Occupation: Student

Python Password Guesser

Postby codegirl » Fri Nov 24, 2017 6:54 am

I'm doing a code project for a class and decided this one sounded like fun. Python is new for me so I had hoped to get some questions answered. Now that I see the project has so many issues I'm going to try something else. I like the idea so maybe I'll write it in C. I see there are no Python programers here. Any C programmers? If I get stuck Id like to ask questions other than asking my teacher.

bfinio
Expert
Posts: 302
Joined: Mon Aug 12, 2013 2:41 pm
Occupation: Science Buddies Staff

Re: Python Password Guesser

Postby bfinio » Sun Nov 26, 2017 7:08 pm

Hi codegirl,

Unfortunately, since we cater to a very broad audience in all areas of science, there are not a ton of programmers on the Science Buddies forums. There are programming-specific forums out there like https://stackoverflow.com/, but you have to be careful because sometimes they cater to professional programmers and not students. So if you do ask a question, you need to explain your background and be very specific about your question (they get mad when kids just copy and paste homework questions into the forum hoping for an easy answer).

For what it's worth - we have figured out that the errors with the Python program are related to indentation and spacing being different on different computers for some reason. Not sure how familiar you are with Python, but it uses indentations for nested code, like this:

if x==1:
print("Hello world!")
else:
print("Goodbye!")



where, to be properly nested inside the if/else statement, those "print" statements need to be indented 4 spaces [edit: I just noticed that the print statements above don't display as indented in the forum! each print statement should be indented 4 spaces]. For some reason, when some students download the code, the spacing in those lines is messed up, and this causes an error in Python.

If you are familiar with C then you probably know that it uses curly braces {} for nested code, and while most people probably still indent the code to make it more readable, technically the spacing doesn't matter. So, I guess you could argue that this is an advantage that C has over Python in this case - if the spacing in a file gets messed up somehow between different machines, it should still run fine as long as the braces are in the right place (I believe there are Python fans out there who will vehemently argue that Python's spacing-only approach is better, I'm not a programmer so I won't take a side in that argument).

Hope that helps!

Ben

anasira
Posts: 5
Joined: Tue Oct 31, 2017 5:04 am
Occupation: Parent

Re: Python Password Guesser

Postby anasira » Wed Nov 29, 2017 6:50 am

Codegirl, my son is working on this project and he's having a lot of fun. Science Buddies messed up the code on their site somehow, but between my son talking with his teacher and my emailing the author we were able to get things working. I'd share his working code with you if there was a way.

HowardE
Posts: 495
Joined: Thu Nov 20, 2014 1:35 pm
Occupation: Science Buddies content developer

Re: Python Password Guesser

Postby HowardE » Mon Dec 04, 2017 7:29 pm

anasira, I'm glad you and your son got his project working. For the benefit of codegirl and anyone else who still can't download the code from the website, I've attached the one I sent you. This is very similar to the original that was part of the project. A student I worked with last year made some changes that improve the program a great deal. She was running an online Python interpreter that couldn't handle having the password text file, so I included it in the source code. She then changed the startup so that if you wanted to enter a password (password0) you could just type it in when you run. In this version, you tell it to use password 0 and it asks you to type in a password.

You should be able to copy and paste the code from here:

Code: Select all

#!/usr/bin/python

# This program is offered for use with the Science Buddies project idea
# "How Easily Can Your Password Be Hacked?" which lets you explore the
# makeup of a good password. This program will help you understand some
# methods that people use to guess other people's passwords.
#
# the program begins execution at 'main' after the helper programs and functions
# are defined. You'll also notice that several functions have places where
# print() functions have been turned into comments. When debugging a program, it's
# helpful to add in more descriptive screen output than you might want later on.
# Once the program is working, you can remove the extra outputs, as we've done here,
# 'comment it out' so that someone else can use it again later on if they decide to
# modify your program.

#Tell Python we want to use some functions it doesn't always use
import sys, time, hashlib
from array import *

#--------------- global variables we expect will be used by any function -----------
#
# a number from 1 to 6 selects which password we'll be trying to guess from
# a selection below.
which_password = 0

# the user names and password we're trying to 'crack'. These will get written
password0 = ""
password1 = ""
password2 = ""
password3 = ""
password4 = ""
password5 = ""
password6 = ""


# total number of guesses we had to make to find it
totalguesses = 0


#--------------- extra helper functions -------------------
# These will be used by our search routines later on. We'll get these defined and out
# of the way. The actual search program is called "main" and will be the last one
# defined. Once it's defined, the last statement in the file runs it.
#
#


## Convert a string into MD5 hash
def MD5me(s):
    result = s.encode("utf-8")
    result = hashlib.md5(result).hexdigest()
    return result

# Takes a number from 0 on up and the number of digits we want it to have. It uses that
# number of digits to make a string like "0000" if we wanted 4 or "00000" if we wanted
# 5, converts our input number to a character string, sticks them together and then returns
# the number we started with, with extra zeroes stuck on the beginning.
def leading_zeroes(n, zeroes):
    t=("0"*zeroes)+str(n)
    t=t[-zeroes:]
    return t

# check_userpass
def check_userpass(which_password, password):
    global password0, password1, password2, password3
    global password4, password5, password6
   
    result = False

    if (0 == which_password):
        if password == password0:
            result = True

    if (1 == which_password):
        if MD5me(password) == password1:
            result = True

    if (2 == which_password):
        if (MD5me(password) == password2):
            result = True

    if (3 == which_password):
        if (MD5me(password) == password3):
            result = True

    if (4 == which_password):
        if (MD5me(password) == password4):
            result = True
           
    if (5 == which_password):
        if (MD5me(password) == password5):
            result = True
           
    if (6 == which_password):
        if (MD5me(password) == password6):
            result = True
           
    return result

# This displays the results of a search including tests per second when possible
def report_search_time(tests, seconds):
    if (seconds > 0.000001):
        print ("The search took "+make_human_readable(seconds)+" seconds for "+make_human_readable(tests)+" tests or "+make_human_readable(tests/seconds)+" tests per second.")
    else:
        print ("The search took "+make_human_readable(seconds)+" seconds for "+make_human_readable(tests)+" tests.")
    return

# search method 1 will try using digits as the password.
def search_method_1(num_digits):
    global totalguesses
    result = False
    a=0
    #num_digits = 3    # How many digits to try. 1 = 0 to 9, 2 = 00 to 99, etc.
    starttime = time.time()
    tests = 0
    still_searching = True
    print("Using method 1 and searching for "+str(num_digits)+" digit numbers.")
    while still_searching and a<(10**num_digits):
        ourguess = leading_zeroes(a,num_digits)
        tests = tests + 1
        totalguesses = totalguesses + 1
        if (check_userpass(which_password, ourguess)):
            print ("Success! Password "+str(which_password)+" is " + ourguess)
            still_searching = False   # we can stop now - we found it!
            result = True
        #else:
            #print ("Darn. " + ourguess + " is NOT the password.")
        a=a+1

    seconds = time.time()-starttime
    report_search_time(tests, seconds)
    return result

# search method 2 is a simulation of a letter-style combination lock. Each'wheel' has the
# letters A-Z, a-z and 0-9 on it as well as a blank. The idea is that we have a number of
# wheels for a user name and password and we try each possible combination.
def search_method_2(num_pass_wheels):
    global totalguesses
    result = False
    starttime = time.time()
    tests = 0
    still_searching = True
    print("Using method 2 and searching with "+str(num_pass_wheels)+" password wheels.")
    wheel = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    # we only allow up to 8 wheels for each password for now
    if (num_pass_wheels > 8):
        print("Unable to handle the request. No more than 8 characters for a password")
        still_searching = False
    # set all of the wheels to the first position
    pass_wheel_array=array('i',[1,0,0,0,0,0,0,0,0])
       
    while still_searching:
        ourguess_pass = ""
        for i in range(0,num_pass_wheels):  # once for each wheel
            if pass_wheel_array[i] > 0:
                ourguess_pass = wheel[pass_wheel_array[i]] + ourguess_pass
        #print ("trying ["+ourguess_pass+"]")
        if (check_userpass(which_password, ourguess_pass)):
            print ("Success! Password  "+str(which_password)+" is " + ourguess_pass)
            still_searching = False   # we can stop now - we found it!
            result = True
        #else:
            #print ("Darn. " + ourguess + " is NOT the password.")
        tests = tests + 1
        totalguesses = totalguesses + 1
# spin the rightmost wheel and if it changes, spin the next one over and so on
        carry = 1
        for i in range(0,num_pass_wheels): # once for each wheel
            pass_wheel_array[i] = pass_wheel_array[i] + carry
            carry = 0
            if pass_wheel_array[i] > 62:
                pass_wheel_array[i] = 1
                carry = 1
                if i == (num_pass_wheels-1):
                    still_searching = False

    seconds = time.time()-starttime
    report_search_time(tests, seconds)
    return result

# This function takes in numbers, rounds them to the nearest integer and puts
# commas in to make it more easily read by humans
def make_human_readable(n):
    if n>=1:
        result = ""
        temp=str(int(n+0.5))
        while temp != "":
            result = temp[-3:] + result
            temp = temp[:-3]
            if temp != "":
                result = "," + result
    else:
        temp = int(n*100)
        temp = temp /100
        result = str(temp)
    return result
       
## A little helper program to remove any weird formatting in the file
def cleanup (s):
    s = s.strip()
    return s

## A little helper program that capitalizes the first letter of a word
def Cap (s):
    s = s.upper()[0]+s[1:]
    return s


# search method 3 uses a list of dictionary words. In this case, we have a list
# of the 500 most commonly used passwords in 2005 as collected by Mark Burnett
# for his book "Perfect Passwords" (ISBN 978-1597490412). Because the list comes
# from so many people around the world, we had to remove some of the passwords.
# People like to use passwords that they think will shock other people, so
# sometimes they're not fit for polite company.
def search_method_3(file_name):
    global totalguesses
    global words
   
    result = False
   
    # Instead of reading the file, call the function fill_in_words_array()
    #### Start by reading the list of words into a Python list
    ###f = open(file_name)
    ###words = f.readlines()
    ###f.close
    fill_in_words_array()
    # We need to know how many there are
    number_of_words = len(words)
    print("Using method 3 with "+str(number_of_words)+" in the list")
   
    ## Depending on the file system, there may be extra characters before
    ## or after the words.
    for i in range(0, number_of_words):
        words[i] = cleanup(words[i])

    # Let's try each one as the password and see what happens
    starttime = time.time()
    tests = 0
    still_searching = True
    word1count = 0           # Which word we'll try next

    while still_searching:
        ourguess_pass = words[word1count]
        #print("Guessing: "+ourguess_pass)
        # Try it the way it is in the word list
        if (check_userpass(which_password, ourguess_pass)):
            print ("Success! Password "+str(which_password)+" is " + ourguess_pass)
            still_searching = False   # we can stop now - we found it!
            result = True
        #else:
            #print ("Darn. " + ourguess_pass + " is NOT the password.")
        tests = tests + 1
        totalguesses = totalguesses + 1
        # Now let's try it with the first letter capitalized
        if still_searching:
            ourguess_pass = Cap(ourguess_pass)
            #print("Guessing: "+ourguess_pass)
            if (check_userpass(which_password, ourguess_pass)):
                print ("Success! Password "+str(which_password)+" is " + ourguess_pass)
                still_searching = False   # we can stop now - we found it!
                result = True
            #else:
                #print ("Darn. " + ourguess_pass + " is NOT the password.")
            tests = tests + 1
            totalguesses = totalguesses + 1

        word1count = word1count + 1
        if (word1count >=  number_of_words):
            still_searching = False

    seconds = time.time()-starttime
    report_search_time(tests, seconds)
    return result
           
## Search method 4 is similar to 3 in that it uses the dictionary, but it tries two
## two words separated by a punctuation character
def search_method_4(file_name):
    global totalguesses
    result = False
   
    # Start by reading the list of words into a Python list
    f = open(file_name)
    words = f.readlines()
    f.close
    # We need to know how many there are
    number_of_words = len(words)
   
    ## Depending on the file system, there may be extra characters before
    ## or after the words.
    for i in range(0, number_of_words):
        words[i] = cleanup(words[i])

    # Let's try each one as the password and see what happens
    starttime = time.time()
    tests = 0
    still_searching = True
    word1count = 0           # Which word we'll try next
    punc_count = 0
    word2count = 0

    punctuation="~!@#$%^&*()_-+={}[]:<>,./X"  # X is a special case where we omit
                                              # the punctuation to run the words together

    number_of_puncs = len(punctuation)
    print("Using method 4 with "+str(number_of_puncs)+" punc chars and "+str(number_of_words)+" in the list")

    while still_searching:
        if ("X" == punctuation[punc_count]):
            # If we're at the end of the string and found the 'X', leave it out
            ourguess_pass = words[word1count] + words[word2count]
        else:
            ourguess_pass = words[word1count] + punctuation[punc_count] + words[word2count]
        #print("Guessing: "+ourguess_pass)
        # Try it the way they are in the word list
        if (check_userpass(which_password, ourguess_pass)):
            print ("Success! Password "+str(which_password)+" is " + ourguess_pass)
            still_searching = False   # we can stop now - we found it!
            result = True
        #else:
            #print ("Darn. " + ourguess_pass + " is NOT the password.")
        tests = tests + 1
        totalguesses = totalguesses + 1
        # Now let's try it with the first letter of the first word capitalized
        if still_searching:
            ourguess_pass = Cap(words[word1count]) + punctuation[punc_count] + words[word2count]
            #print("Guessing: "+ourguess_pass)
            if (check_userpass(which_password, ourguess_pass)):
                print ("Success! Passwword "+str(which_password)+" is " + ourguess_pass)
                still_searching = False   # we can stop now - we found it!
                result = True
            #else:
                #print ("Darn. " + ourguess_pass + " is NOT the password.")
            tests = tests + 1
            totalguesses = totalguesses + 1
        # Now let's try it with the first letter of the second word capitalized
        if still_searching:
            ourguess_pass = words[word1count] + punctuation[punc_count] + Cap(words[word2count])
            #print("Guessing: "+ourguess_pass)
            if (check_userpass(which_password, ourguess_pass)):
                print ("Success! Password "+str(which_password)+" is " + ourguess_pass)
                still_searching = False   # we can stop now - we found it!
                result = True
            #else:
                #print ("Darn. " + ourguess_pass + " is NOT the password.")
            tests = tests + 1
            totalguesses = totalguesses + 1
        # Now let's try it with the both words capitalized
        if still_searching:
            ourguess_pass = Cap(words[word1count]) + punctuation[punc_count] + Cap(words[word2count])
            #print("Guessing: "+ourguess_pass)
            if (check_userpass(which_password, ourguess_pass)):
                print ("Success! Password "+str(which_password)+" is " + ourguess_pass)
                still_searching = False   # we can stop now - we found it!
                result = True
            #else:
                #print ("Darn. " + ourguess_pass + " is NOT the password.")
            tests = tests + 1
            totalguesses = totalguesses + 1

        word1count = word1count + 1
        if (word1count >=  number_of_words):
            word1count = 0
            punc_count = punc_count + 1
            if (punc_count >= number_of_puncs):
                punc_count = 0
                word2count = word2count + 1
                if (word2count >= number_of_words):
                    still_searching = False

    seconds = time.time()-starttime
    report_search_time(tests, seconds)
    return result


def main(argv=None):
    global password0, password1, password2, password3
    global password4, password5, password6, totalguesses
    global which_password

    # This is a place for you to set a password of your own
    password0 = "314"
    # Set up the passwords we want to crack. These must be MD5 hash
    # data blocks. Set them up using MD5me like:
    #     'password1=MD5me("ScienceBuddies")'
    #
    password1="202cb962ac59075b964b07152d234b70"
    password2="570a90bfbf8c7eab5dc5d4e26832d5b1"
    password3="f78f2477e949bee2d12a2c540fb6084f"
    password4="09408af74a7178e95b8ddd4e92ea4b0e"
    password5="2034f6e32958647fdff75d265b455ebf"
    password6="9b3af42d61cde121f40b96097fb77d3e"

    # start searching
    which_password = 1
    which_password = int(input("Which password (0-6)? "))
    if (0 == which_password):
        password0 = input("You want to enter one? Type it in here:")
    overallstart = time.time()
    foundit = False
    print("Trying to guess password "+str(which_password))
    # Look through our list of common passwords first
    if not foundit:
        foundit = search_method_3("passwords.txt")
    # Still looking? Let's combine the common passwords 2 at a time
    if not foundit:
        foundit = search_method_4("passwords.txt")
    # Still looking? See if it's a single digit
    if not foundit:
        foundit = search_method_1(1)
    # Still looking? See if it's a 2 digit number
    if not foundit:
        foundit = search_method_1(2)
    # Still looking? See if it's a 3 digit number
    if not foundit:
        foundit = search_method_1(3)
    # Still looking? See if it's a 4 digit number
    if not foundit:
        foundit = search_method_1(4)
    # Still looking? Use our rotary wheel simulation up to 6 wheels.
    # This should take care of any 5 digit number as well as letter
    # combinations up to 6 characters
    if not foundit:
        foundit = search_method_2(6)
    # Still looking? Try 7 digit numbers
    if not foundit:
        foundit = search_method_1(7)
    # Still looking? Try 8 digit numbers
    if not foundit:
        foundit = search_method_1(8)
    seconds = time.time()-overallstart
    # When testing this project, some users reported that the next lines of code reported
    # an error when Python tried to divide by zero. On those machines, the clock seems
    # to think that the seconds calculation just above gave us "zero" seconds which doesn't
    # make any sense. To avoid the crash though, we'll test for that case and avoid the
    # problem.
    if (seconds < 0.00001):
        print ("The total search for all methods took "+make_human_readable(seconds)+" seconds and "+make_human_readable(totalguesses)+" guesses.")
        print ("(on some machines, Python doesn't know how long things actually took)")
    else:
        print ("The total search for all methods took "+make_human_readable(seconds)+" seconds and "+make_human_readable(totalguesses)+" guesses.("+make_human_readable(totalguesses/seconds)+" guesses per second)")

    if foundit:
        if (6 == which_password):
            print("Wow! Be sure to confirm your find at http://www.sciencebuddies.org/science-fair-projects/project_ideas/CompSci_p046/PasswordCrack.shtml")
        elif (0 == which_password):  # The Science Buddies website can't confirm passwords you added yourself
            print ("Your algorithm correctly guessed the password you entered. Try some others or see if you can make it guess faster.")
        else:
            print("You can confirm your find at http://www.sciencebuddies.org/science-fair-projects/project_ideas/CompSci_p046/PasswordCrack.shtml")


def fill_in_words_array():
    global words
    words = ["123456","password","12345678","1234","12345","dragon","qwerty","mustang","baseball","master","michael","football",
             "shadow","monkey","abc123","pass","jordan","harley","ranger","jennifer","hunter","2000","test","batman","trustno1",
             "thomas","tigger","robert","access","love","buster","1234567","soccer","hockey","killer","george","andrew","charlie",
             "superman","dallas","jessica","pepper","1111","austin","william","daniel","golfer","summer","heather","hammer",
             "yankees","joshua","maggie","enter","ashley","thunder","cowboy","silver","richard","orange","merlin","michelle","corvette",
             "bigdog","cheese","matthew","121212","patrick","martin","freedom","ginger","nicole","sparky","yellow","camaro","secret",
             "falcon","taylor","111111","131313","123123","hello","scooter","please","porsche","guitar","chelsea","black","diamond",
             "nascar","jackson","cameron","654321","computer","amanda","wizard","xxxxxxxx","money","phoenix","mickey","bailey","knight",
             "iceman","tigers","purple","andrea","dakota","aaaaaa","player","sunshine","morgan","starwars","boomer","cowboys","edward",
             "charles","girls","booboo","coffee","bulldog","ncc1701","rabbit","peanut","john","johnny","gandalf","winter","brandy",
             "compaq","carlos","tennis","james","mike","brandon","fender","anthony","ferrari","cookie","chicken","maverick","chicago",
             "joseph","diablo","666666","willie","welcome","chris","panther","yamaha","justin","banana","driver","marine","angels",
             "fishing","david","maddog","wilson","dennis","captain","chester","smokey","xavier","steven","viking","snoopy","blue",
             "eagles","winner","samantha","house","miller","flower","jack","firebird","butter","united","turtle","steelers","tiffany",
             "zxcvbn","tomcat","golf","bond007","bear","tiger","doctor","gateway","gators","angel","junior","thx1138","boys","debbie",
             "spider","melissa","burger","1212","flyers","fish","matrix","teens","scooby","jason","walter","boston","braves","yankee",
             "barney","victor","tucker","princess","mercedes","5150","doggie","zzzzzz","gunner","bubba","2112","fred","johnson",
             "member","donald","bigdaddy","bronco","voyager","rangers","birdie","trouble","white","topgun","green","super","qazwsx",
             "magic","lakers","rachel","slayer","scott","2222","asdf","video","london","7777","marlboro","srinivas","internet","action",
             "carter","jasper","monster","teresa","jeremy","11111111","bill","crystal","peter","beer","rocket","theman","oliver","prince",
             "beach","amateur","7777777","muffin","redsox","star","testing","shannon","murphy","frank","hannah","dave","eagle1","11111",
             "mother","nathan","raiders","steve","forever","angela","viper","ou812","jake","gregory","buddy","whatever","young","nicholas",
             "lucky","helpme","jackie","monica","midnight","college","baby","brian","mark","startrek","sierra","leather","232323","4444",
             "beavis","happy","sophie","ladies","giants","blonde","golden","fire","sandra","pookie","packers","einstein","dolphins","chevy",
             "winston","warrior","sammy","8675309","zxcvbnm","power","victoria","asdfgh","toyota","travis","hotdog","paris","rock","extreme",
             "redskins","ford","freddy","arsenal","access14","wolf","iloveyou","alex","florida","eric","legend","movie","success","rosebud",
             "jaguar","great","cool","cooper","1313","scorpio","mountain","madison","987654","brazil","lauren","japan","stars","apple",
             "alexis","aaaa","bonnie","peaches","jasmine","kevin","matt","qwertyui","danielle","4321","4128","runner","swimming","dolphin",
             "gordon","casper","saturn","gemini","apples","august","3333","canada","blazer","hunting","kitty","rainbow","112233","arthur",
             "calvin","surfer","samson","kelly","paul","mine","king","racing","5555","eagle","newyork","little","redwings","smith","sticky",
             "cocacola","animal","broncos","private","skippy","marvin","blondes","enjoy","girl","apollo","parker","qwert","time","sydney",
             "women","voodoo","juice","abgrtyu","777777","dreams","maxwell","music","rush2112","russia","scorpion","rebecca","tester",
             "mistress","phantom","billy","6666","albert"]

print ("Science Buddies: How Easily Can Your password Be Hacked?")
if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))



Return to “Grades 6-8: Math and Computer Science”