Python crypt module
Asked Answered
I

2

6

I was looking up on python modules, when I found something called 'crypt'. I do not understand. I have tried reading up on this, what is this 'salt' thing, what is the use of this crypt module, and is there some sort of way that I can apply 'crypt' to this piece of python code?:

import crypt

max_attempts = 3     
attempt = 0          

try:


    while attempt < max_attempts:

        uname = input('Username: ')  
        password = input('pass: ')   

        if uname == 'admin' and password == 'Khs9':
            print('Welcome Admin')
            break
        else:
            attempt += 1
            if attempt == max_attempts:
                raise RuntimeError("\nYou've reached the maximum number of attempts allowed.")

            else:
                print('Wrong credentials.\n Try again or press <ctrl+c> to exit.\n')
                continue


except KeyboardInterrupt:
    print('Terminated by the user.\nGood-bye.')

except RuntimeError as e:
    print("Goodbye")
Interoceptor answered 10/2, 2016 at 21:22 Comment(1)
Check docs.python.org/2/library/crypt.htmlFootcloth
B
3

Now that I've seen you code, I know the password is 'Khs9' and I can log into your box.

You could have run the following in private.

>>> crypt.crypt('Khs9', 'aa')
'aa0GPiClW35DQ

Now you update you code as such:

import crypt

max_attempts = 3     
attempt = 0          
stored_pw_hash = 'aa0GPiClW35DQ'

try:


     while attempt < max_attempts:

        uname = input('Username: ')  
        entered_pw_hash = crypt.crypt(input('pass: '), stored_pw_hash)

        if uname == 'admin' and entered_pw_hash == stored_pw_hash:
            print('Welcome Admin')
            break
        else:
            attempt += 1
            if attempt == max_attempts:
                raise RuntimeError("\nYou've reached the maximum number of attempts allowed.")

            else:
                print('Wrong credentials.\n Try again or press <ctrl+c> to exit.\n')
                continue


except KeyboardInterrupt:
    print('Terminated by the user.\nGood-bye.')

except RuntimeError as e:
    print("Goodbye")

Now if your code gets leaked, they don't have access right away. You should have enough time to realise you were hacked and then change your password.

Here's the background info...

crypt.crypt(password) will return the hash of password. You store the hash instead of the clear text password. That way, you can't lose the password to a hacker because you don't have it. Losing a hash is not a big problem because it doesn't guarantee access (if you follow best practice, which includes using a salt).

Next time someone provides a password, you calculate it's hash, compare it to hash you stored from before and if they match, you know they gave you the correct password.

Why do you need to use a salt? Because someone took the long ass time needed to generate a table with commonly used passwords and there hashes. Once done, it's a quick check to crack the hash. By using a salt you ensure that a different lookup table applies, one that probably isn't available and the average hacker doesn't have the time to generate it.

crypt.crypt() needs two chars to use as a salt. You can either pass it a two char string OR use the previous output of the function. (crypt.crypt() returns a string with first two chars being the salt and the rest being the hash)

I looked at https://docs.python.org/3.4/library/crypt.html to answer this.

Boettcher answered 11/2, 2016 at 0:30 Comment(1)
The old crypt() is grossly insufficient these days, as is a two byte salt, unfortunately.Overshoot
O
1

First, please read Thomas Pornin's canonical answer to How to securely hash passwords. This will answer your questions about what a 'salt' is.

Second, crypt is an ancient, ancient algorithm - don't use it. Even the Python SHA-512 based crypt is probably not something to use, because you cannot control the iteration count (what BCrypt might call a work factor), and thus you don't get to make it more secure by increasing the iteration count.

Third, Python as of 3.4 has fast PBKDF2 based on OpenSSL built in.

So does Python 2.7.8.

Both of these support reasonable hash types built into hashlib! Use these instead! One example of how to use these is something like:

import hashlib

BinaryOutput = hashlib.pbkdf2_hmac('sha512',password, salt, args.iterations, args.outputBytes)

where

  • args.iterations is in the low hundreds of thousands to high tens of thousands

  • args.outputBytes is no more than 64 assuming SHA-512 is being used (less for other algorithms), and no less than 20.

  • Store the number of iterations in your storage (whether it's hardcoded, in a file, or in a database) in cleartext, so you can easily make it bigger later.

  • To get the salt, you should generate at least 12, preferably at least 16, cryptographically random bytes. Have a different salt for each username, and store it in cleartext in your storage (whether it's hardcoded, in a file, or in a database).

Using PBKDF2-HMAC-SHA-512 uses 64-bit operations which can reduce the advantage a GPU based attacker has on you.

If you're worried about a timing attack, you can use one of a variety of constant time comparisons. One that doesn't cost much of anything compared to a high iteration PBKDF2-HMAC-SHA-512 would be something like:

if hashlib.sha256(args.expectedBinary).hexdigest() == hashlib.sha256(BinaryOutput).hexdigest():
Overshoot answered 11/2, 2016 at 6:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.