Security in Python

Síguenos / Follow us!
Facebooktwitterlinkedinrssyoutubeinstagram

A password vault

A vault is your home base for all your passwords. The idea is to save, access, and manage passwords in one, secure place. The following code is based on How to create a password vault from scratch with Python by NewsCred Dhaka, but it has been modified quite a lot.

import os, subprocess, string, json
from beefish import encrypt_file, decrypt_file
from random import choice, shuffle

class PasswordVault:
    def __init__(self, root_pass=None, filename='secrets'):
        # This is the vault's master key
        self.root_pass = root_pass
        self.filename = filename
        # These are the encripted and decrypted files
        self.encrypted_fp = PasswordVault.get_file_path(self.filename, '.enc', True)
        self.decrypted_fp = PasswordVault.get_file_path(self.filename, '.dec', False)

    @staticmethod
    def get_file_path(filename, extension, encrypted):
        """ It returns the file's path. Observe that the encripted file is hidden (macOS, GNU/Linux)."""
        if encrypted:
            return os.path.join(os.getcwd(), "." + filename + extension)
        else:
            return os.path.join(os.getcwd(), filename + extension)

    @staticmethod
    def secure_password():
        """ It generates a secure password with uppercase and lowercase letters, symbols, and numbers."""
        password = ''.join([choice(string.ascii_lowercase) for i in range(4)])
        password += ''.join([choice(string.ascii_uppercase) for i in range(4)])
        password += ''.join([choice(string.digits) for i in range(2)])
        password += ''.join([choice(string.punctuation) for i in range(2)])
        my_password = list(password)
        shuffle(my_password)
        return ''.join(my_password)
   
    def read(self):
        """ It reads all passwords and stores them in a dictionary. """
        try:
            # decrypt_file returns the encrypted file "encrypted_fp" back to its original unencrypted format "decrypted_fp".
            decrypt_file(self.encrypted_fp, self.decrypted_fp, self.root_pass)
            # We read the unencrypted file.
            content = open(self.decrypted_fp, "r",
                           encoding="ISO-8859-1").read()
            # Once we have already read the unencrypted file, we delete it for security reasons.
            os.remove(self.decrypted_fp)
            # We save the unencrypted file's content in a dictionary. json.loads() takes the file's content and returns the json object which contains data in the form of key/value pairs.
            return json.loads(content)
        except FileNotFoundError:
            return {}

The library beefish does the heavy lifting for us. It provides a simple file encryption using pycrypto: pip install beefish pycrypto.

    def write(self, data={}):
        """ It writes the dictionary "data" with all its key/value pairs (account/password) in the encrypted file "encrypted_fp"."""
        with open(self.decrypted_fp, 'w') as f:
            # json.dump(obj, file) converts the dictionary data to a JSON object and write it into the decrypted file. An indent argument is used to pretty-print JSON to make it more readable. 
            json.dump(data, f, indent=4, separators=(',', ': '))
            f.close()

        # encrypt_file encrypts the file "decrypted_fp" using the master password.
        encrypt_file(self.decrypted_fp, self.encrypted_fp, self.root_pass)
        # Obviously, we need to remove the unencrypted file.
        os.remove(self.decrypted_fp)
    
    def get_password(self, account):
        """ It returns the password of the account, site, app or service given as an argument."""
        data = self.read()

        # If account is not in our dictionary, it generates a new random password and saves it.""" 
        if account not in data:
            password = PasswordVault().secure_password()
            data[account] = password
            self.write(data)

        return data[account]

    def get_all_passwords(self):
        """ It returns all the (account, password) pairs store in our vault."""
        data = self.read()
        return data

    def set_password(self, account, password):
        """ It updates the account, site, app or service's password with a new one. If the account does not exist, it creates a new one."""
        data = self.read()
        data[account] = password
        self.write(data)

    def useSublime(self):
        """ It uses sublime as an editor for managing our passwords."""
        try:
            # decrypt_file returns the encrypted file "encrypted_fp" back to its original unencrypted format "decrypted_fp".
            decrypt_file(self.encrypted_fp, self.decrypted_fp, self.root_pass)
            # We open the unencrypted file with sublime.
            os.system("subl " + self.decrypted_fp)
            # It allows the external program to work.
            input()
            # encrypt_file encrypts the file "decrypted_fp" using the master password.
            encrypt_file(self.decrypted_fp, self.encrypted_fp, self.root_pass)
            # Once we have finished editing the unencrypted file, we delete it for security reasons.
            os.remove(self.decrypted_fp)

        except FileNotFoundError:
            return {}  

    def changeRootPassword(self, nuevaPassword):
    """ It updates the Vault's master key."""
        try:
            # decrypt_file returns the encrypted file "encrypted_fp" back to its original unencrypted format "decrypted_fp".
            decrypt_file(self.encrypted_fp, self.decrypted_fp, self.root_pass)
            # We delete the encrypted file.
            os.remove(self.encrypted_fp)
            # It updates the vault's master pass.
            self.root_pass = nuevaPassword
            # encrypt_file encrypts the file "decrypted_fp" using the new master password.
            encrypt_file(self.decrypted_fp, self.encrypted_fp, self.root_pass)
            # And delete the unencrypted file.
            os.remove(self.decrypted_fp)
        except FileNotFoundError:
            return {} 

if __name__ == '__main__':
    root_pass = subprocess.check_output(['pass', 'MasterPass']) # subprocess.check_output() runs commands with arguments and return their outputs as byte strings. We run "pass MasterPass" that uses Pass.
    root_pass = root_pass.decode("utf-8").rstrip() # We need to decode the byte string to produce a string. We could have just asked the user to introduce the master pass: root_pass = input('Enter the Vault's master password').

Pass is the standard GNU/Linux password manager, a lightweight password manager. We can retrieve our passwords by typing: pass nameAccount, e.g., pass MasterPass.

One of the safest ways to handle your secret keys or passwords is saving them in environment variables. Open your .bash_profile (macOS and GNU/Linux), add: export ROOTPASSWORD="SecretPassword", and type the following command for the changes to take effect: source .bash_profile. On Windows, you need to navigate to Control Panel, System and Security, Advanced System Settings, Environment Variables... To access your variable in your Python code, you need to import the os module and write: print(os.environ.get('ROOTPASSWORD')).

Another alternative is to save your keys and passwords in a separate .env file in your project: ROOTPASSWORD=SecretPassword. Next, we are going to use the python-dotenv library (pip install python-dotenv). It reads key-value pairs from a .env file and can set them as environment variables:
from dotenv import load_dotenv
load_dotenv() # It takes environment variables from .env.
root_pass = os.environ.get('ROOTPASSWORD')

You need to make sure to add it in your .gitignore file (.env). It specifies intentionally untracked files that Git should ignore.

    vault = PasswordVault(root_pass) # We create an instance of PasswordVault.
    not_end = True
    while not_end:
        print("Exit. Show (all vault). New (get a random password)")
        inputUser = input("Sublime. Get [account]/Update [account] [new_password]: ").split(" ")

        option = inputUser[0].upper()
        if option == "EXIT":
            not_end = False
        elif option == "SHOW":
            print("It shows all the entries of your personal vault.")
            print(json.dumps(vault.get_all_passwords(), indent=4, sort_keys=True))
        elif option == "NEW":
            print("This is your new secure random password: " + PasswordVault().secure_password())
        elif option == "SUBLIME":
            vault.useSublime()
        elif option == "GET": # The user input is: GET [account]
            account = inputUser[1]
            print(f"The password of {account} is {vault.get_password(account)}")
        elif option == "UPDATE": # The user input is: UPDATE [account] [password]
            account = inputUser[1]
            password = inputUser[2]
            vault.set_password(account, password)

Password generator

Strong passwords are more important than ever. Let's create a password generator. It creates unique and random passwords.

Password reuse is a problem where people try to remember multiple passwords for everything they interact with on a regular basis. Many people reuse the same password for multiple or all accounts. You can take a "Master Key", add the name of the service, app, or social media, and create a unique password for every account.

import passwordmeter, sys, subprocess, string
from rich import print
from random import choice

substitutions = (('s', '$'), ('and', '&'), ('b', '8'), ('S', '$'), ('and', '&'), ('B', '8'), ('A', '@'), ('O', '0'), ('I', '1'), ('E', '3'), ('l', '1'), ('L', '1'), ('a', '@'), ('o', '0'), ('i', '1'), ('e', '3'))
misEmojis = [":-(", ":)", ":')", ";(", ":-*", ">:‑)"]

# It adds a random emoji to the password.
def add_emoji(password):
    return password + choice(misEmojis)

# It replaces characters with different replacement characters.
def common_substitutions(password):
    for a, b in substitutions:
        password = password.replace(a, b)
    return password

# Credits: @amillerrhodes, Georgy from stackoverlflow.com
# Caesar is a substitution cypher. It shifts all the characters of the word ("text") by a certain number of places ("shift").
def caesar(text, shift, alphabets):
    def shift_alphabet(alphabet): # This function is defined inside the "caesar" function. It shifts all the characters of the alphabet.
        return alphabet[shift:]+alphabet[:shift]

    shifted_alphabets = tuple(map(shift_alphabet, alphabets)) # Read our article about Functional Programming in Python. map applies the function shift_alphabet() to each alphabet in alphabets.
    final_alphabet = ''.join(alphabets)
    final_shifted_alphabets = ''.join(shifted_alphabets)
    table = str.maketrans(final_alphabet, final_shifted_alphabets) # The maketrans() function creates a translation table, i.e., a one-to-one mapping of a character to its replacement.
    return text.translate(table)

# It checks the security of our password.
def check_password(myPassword):
    strength, improvements = passwordmeter.test(myPassword) # The main function provided by the passwordmeter package is the Meter.test() method. It returns a tuple of (float, dict).  
    print("It strength is: " + str(strength)) # The float is the strength of the password in the range 0 to 1, where 0 is extremely weak and 1 is extremely strong. 
    print("Its length is: " + str(len(myPassword)))
    print(improvements) # The second parameter is a dictionary of ways the password could be improved.

It uses passwordmeter, a configurable, extensible password strength measuring library.

# It adds a root or master key to the password.
def add_rootKey(myPassword):
    root_pass = subprocess.check_output(['pass', 'MasterPass']) # subprocess.check_output() runs commands with arguments and return their outputs as byte strings. We run "pass MasterPass" that uses Pass.
    clave = root_pass.decode("utf-8").rstrip() # We need to decode the byte string to produce a string.
    password = myPassword + clave
    return password

Pass is the standard GNU/Linux password manager, a lightweight password manager. We can retrieve our passwords by typing: pass namePassword, e.g., pass MasterPass.

# If the password is too long, it shrinks its size.
def cut_password(myPassword, limitSize=24):
    if (len(myPassword) > limitSize):
        too_long = len(myPassword) - limitSize
        myPassword = myPassword[:-too_long]
    return myPassword

def create_secure(weakPassword, shift=7, alphabets=[string.ascii_lowercase, string.ascii_uppercase]):
    """ It creates unique and random passwords."""   
    password = caesar(
        sys.argv[1], shift, alphabets)
    print("0. Caesar 7. Your secure password is: [orange]" + password + "[/orange]") 
    password = common_substitutions(password)
    print("1. Replacement. Your secure password is: [yellow]" + password + "[/yellow]") 
    password = str(len(password)) + password[1:-1]
    print("2. Replace the first character by the word's length and remove the last character: [yellow]" + password + "[/yellow]") 
    password = add_rootKey(password)
    print("3. Include the root key: [red]" + password + "[/red]") 
    password = add_emoji(password)
    print("4. Add a random emoji: [pink]" + password + "[/pink]") 
    password = cut_password(password)
    print("5. Reduce the password to 24 characters: [blue]" + password + "[/blue]")
    check_password(password)

if __name__ == "__main__":
    create_secure(sys.argv[1]) # It takes one argument, e.g., "youaretoosweet"

0. Caesar 7. Your secure password is: fvbhylavvzdlla
1. Replacement. Your secure password is: fv8hy1@vvzd11@
2. Replace the first character by the word's length and remove the last character: 14v8hy1@vvzd11
3. Include the root key: 14v8hy1@vvzd11mySecurePassword7
4. Add a random emoji: 14v8hy1@vvzd11mySecurePassword7>:‑)
5. Reduce the password to 24 characters: 14v8hy1@vvzd11mySecurePa
It strength is: 0.8598353623924001
It length is: 24
{'phrase': 'Passphrases (e.g. an obfuscated sentence) are better than passwords'}

Credentials

Storing credentials inside a credentials.py file is the simplest way to store your passwords safely. You can use environment variables, too.

You need to make sure to add it in your .gitignore file (credentials.py). It specifies intentionally untracked files that Git should ignore.

# It contains the user credentials to access WolframAlpha API
WolframAlpha_app_id = = "myPrivateApiKey"

import wolframalpha, requests, credentials
from colorama import Back, Fore, init, Style
# pip install wolframalpha

# It searches in WolfranAlpha.
def wolframAlpha(keyword=''):
  client = wolframalpha.Client(credentials.WolframAlpha_app_id)
  # We send a query, which returns Results objects: 
  res = client.query(keyword)
  # Result objects have pods (a Pod is an answer group from Wolfram Alpha).
  if res['@success'] == 'false':
    print('Question cannot be resolved')
  else: # To query simply for the pods that have ‘Result’ titles or are marked as ‘primary’ using Result.results:
    print(next(res.results).text)

learn Python

 if __name__ == '__main__':
  searchInfo("what is the capital of Italy")

Rome, Lazio, Italy

Adding Salt to Hashing

The best way to protect passwords is to employ salted password hashing. Typically, a user creates an account. Next, his or her password is hashed (a hash algorithm is a function that converts a data string into a numeric string output of fixed length) and stored in a database. When the user comes back, the hash of the password he or she introduces is compared against the hash of the saved password. Obviously, if the hashes match, the user is granted access.

Some password cracking techniques only work because each password is hashed the exact same way. Salting hashes refers to adding random data to the input of a hash function to guarantee a unique output, i.e., a random string is generated and combined with the password and then hashed.

def hash_password(password):
    # uuid is used to generate a random UUID, uuid.uuid4().hex converts a UUID to a 32-character hexadecimal string.
    salt = uuid.uuid4().hex
    # It hashes a password with a salt. encode() returns an utt8-encoded version of the string. hexdigest() returns the encoded data in hexadecimal format.
    return hashlib.sha256(salt.encode() + password.encode()).hexdigest(), salt

def check_encryption(password, salt, user_password):
    try:
        if (password == hashlib.sha256(salt.encode() + user_password.encode()).hexdigest()):
            return "Success"
        else:
            return "Failure"
    except Exception as e:
        print(e)

if __name__ == "__main__":
    password, salt = hash_password("bananas")
    print("Password: ", password)
    print("Salt: ", salt)
    print(check_encryption(password, salt, "bananas"))

Privacy

PhoneInfoga is one of the most advanced tools to scan phone numbers using only free resources and it is written in Python.
1. Installation. # Download latest release in the current directory
curl -sSL https://raw.githubusercontent.com/sundowndev/phoneinfoga/master/support/scripts/install | bash
2. Use. phoneinfoga scan -n "telephone_number", python3 phoneinfoga.py -n "(+42)837544833".
Compártelo / Share it!
Facebooktwitterredditpinterestlinkedinmail

Author: Anawim

I am a social activist. I have two Bachelor's degrees, Maths and Computer & Software Engineering. I also have a Ph.D. in Psychology. I have written nine published books, four scientific articles, and five scientific presentations. I simply want to contribute to making a difference where it counts, so that we make the world a better, more sustainable, prosperous, and fairer place. I am always willing to give free talks and lectures about the social problems that exist in our world today.

Leave a Reply

Your email address will not be published. Required fields are marked *