Cryptography Decryption Problems - python-3.x

My script is a password manager which uses SQLITE3. I am having problems decrypting the data which I have recieved from my database.
The error:
cryptography.exceptions.InvalidSignature: Signature did not match digest,
raise InvalidToken,
cryptography.fernet.InvalidToken
comes up when I try to decode the data. My code is down below and I need help understanding and fixing the problem with decoding. (just focus on the find_password() function, load_key() function, and decode_data() functions)
#The Dependicies and Packages required for this script
import sqlite3
from cryptography.fernet import Fernet
def generate_key():
"""
Generates a key and save it into a file
"""
key = Fernet.generate_key()
with open("secret.key", "wb") as key_file:
key_file.write(key)
def load_key():
"""
Loads the key named `secret.key` from the current directory.
"""
return open("secret.key", "rb").read()
#These are the keys for encryption
key = load_key()
f = Fernet(key)
def decode_data(datas):
new_name = f.decrypt(datas)
final_name = new_name.decode()
return final_name
def create_password():
"""
This function is used for gathering the user's data about the website, their username to that site, and their password.
This data in then encrypted using the key generated at lines 5 and 6.
Finally, the data is pushed to the sql database using bind parameters so that there is no risk of sql injection attacks
"""
#Each of these variables asks for a input which is then encoded into bytes so that it can be encrypted.
#The user input is then encrypted using the keys generated on lines 5,6
encrypted_website = f.encrypt(input("What is the website that you have made a password for?>").encode())
encrypted_username = f.encrypt(input("What is the username for the website you are making a password for?>").encode())
encrypted_password = f.encrypt(input("What is the password for the website you are making?>").encode())
#This is the command which uses bind parameters to insert the encrypted data into the database. The type of data being inserted is a blob
c.execute("INSERT INTO passwords (website, username, password) VALUES (?, ?, ?)",
(encrypted_website, encrypted_username, encrypted_password))
def find_password():
"""
This function is to get the password of the website that the user expected
"""
website_name = input("What is the website's name for which you need a password>")
c.execute("SELECT * FROM passwords")
data = c.fetchall()
for row in data:
print(row[0])
name = decode_data(row[0])
if name == website_name:
password = decode_data(row[2])
print(f'The password to {website_name} is {password}')
def main():
go_on = True
while go_on:
direction_question = input("This is your password manager. Press 1 to create a new pasword, Press 2 to search for a password, or Press 3 to exit the program>")
if direction_question.lower() == "1":
create_password()
if direction_question.lower() == "2":
find_password()
if direction_question.lower() == "3":
go_on = False
else:
print("Invalid response")
db.commit()
db.close()
if __name__ == "__main__":
db = sqlite3.connect('password.db')
c = db.cursor()
# generate_key()
#This is the code to create the table
# c.execute("""CREATE TABLE passwords (
# website blob,
# username blob,
# password blob
# )""")
main()

Related

Writing data in a CSV file everytime a function is called

I'm building an employee management system in which I've to write employees' data onto a file everytime the register system is called.
Below I wrote it onto a text file. And it's working fine.
class Employee:
def __init__(self, name, ID, password=None):
self.name = name
self.ID = ID
self.password = password
def register(self):
self.password = input("Enter your password: ")
database = open("Employees_data.txt", "a")
database.write("\n"+self.name+","+self.ID+","+self.password)
database.close()
return "Registration successfully!"
But I've to write data on a CSV file instead. I tried the following code but everytime I call the function, the previous line of data is overwritten.
def register(self):
self.password = input("Enter your password: ")
lst = [self.name, self.ID, self.password]
with open("Database.csv", "w", newline="") as data_file:
csv_writer = csv.writer(data_file, delimiter=",")
csv_writer.writerow(lst)
data_file.close()
return "Registration successfully!"
What do I do about it?
At first just delete this line. You don't need it.
data_file.close()
When you are using context manager in python it closes the file when writing in the file is finished.
after that, if you want to append your result to the file just instead of 'w' use 'a'

How to do validation in python?

I am making a gui for employee management system using python tkinter and sqlite3.
In this gui user can add, view, delete amd update employee info.
def save():
con = None
try:
con = connect("pro.db")
cursor = con.cursor()
sql = "insert into Employee values('%d', '%s', '%f')"
id = int(aw_ent_id.get())
name = aw_ent_name.get()
lenstring = False
while not lenstring:
if len(name) >= 2:
lenstring = True
else:
showerror("error","Enter atleast 2 letters")
break
salary = float(aw_ent_salary.get())
cursor.execute(sql%(id, name, salary))
con.commit()
showinfo("success", "record added")
aw_ent_id.delete(0, END)
aw_ent_name.delete(0, END)
aw_ent_salary.delete(0, END)
aw_ent_id.focus()
except Exception as e:
con.rollback()
showerror("issue", e)
finally:
if con is not None:
con.close()
the code is running but i am getting some errors in validating name and salary.
for name i have done validating but its not working. I am getting an error
the data is getting saved even after getting error.
What should i do to make it right?
It is better to:
validate the inputs before saving to database
raise exception if len(name) is less than 2 instead of using while loop checking (actually the while loop is meaningless)
use placeholders to avoid SQL injection
Below is updated save():
# avoid using wildcard import
import tkinter as tk
from tkinter.messagebox import showinfo, showerror
import sqlite3
...
def save():
con = None
try:
# validate inputs
# use emp_id instead of id because id is built-in function
emp_id = int(aw_ent_id.get().strip()) # raise ValueError if not a valid integer
name = aw_ent_name.get().strip()
if len(name) < 2:
raise Exception('Name too short, at least 2 letters')
salary = float(aw_ent_salary.get().strip()) # raise ValueError if not a valid float number
# validations on inputs are passed, try saving to database
sql = 'insert into Employee values (?, ?, ?)' # use placeholders to avoid SQL injection
con = sqlite3.connect('pro.db')
cursor = con.cursor()
cursor.execute(sql, (emp_id, name, salary))
con.commit()
showinfo('Success', 'Employee added')
aw_ent_id.delete(0, tk.END)
aw_ent_name.delete(0, tk.END)
aw_ent_salary.delete(0, tk.END)
aw_ent_id.focus_set()
except Exception as e:
if con:
con.rollback()
showerror("Error", e)
finally:
if con:
con.close()
...

Displaying an image in python from SQLite BLOB [duplicate]

I have a CRUD form with entries and 4 button for deleting, updating, creating, getting values from my database, I want to implement another button to open an imagen which is binded to my id entry also able to works with my deleting, updating, creating, getting buttons, I've been trying to use BLOB and I'm able to save an image in my database as BLOB. Actually I understand that I need to create textvariables for my entries like 'idvar = StringVar() , namevar = Stringvar()..., etc', So I'm not sure how to do it for an image label in order to work with my CRUD buttons deleting, updating, creating, getting
This is my code I got so far and it's working well saving images into my photos columns:
from tkinter import *
import sqlite3
top = Tk()
top.configure(width='444', heigh='400')
conn = sqlite3.connect('test.db')
c = conn.cursor()
def enterdata():
id = 'hello'
photo = convert_pic()
c.execute('INSERT INTO test (id, photo) VALUES (?, ?)', (id, photo)) #Here my id has integer value and my photo has BLOB value in my database
conn.commit()
def convert_pic():
filename = 'images/image6.jpg'
with open(filename, 'rb') as file:
photo = file.read()
return photo
btn = Button(top, text='save photo', command=enterdata)
btn.place(x='100', y='111')
mainloop()
Now that you have the BLOB you can use io.BytesIO. I will create an example to demonstrate, like:
from PIL import Image, ImageTk
from io import BytesIO
def show(data):
img_byte = BytesIO(data)
img = ImageTk.PhotoImage(Image.open(img_byte))
Label(root,image=img).pack()
root.image = img # Keep a reference
So now you can query the database and fetch the value:
def fetch():
c = con.cursor()
id = 1 # Any id
c.execute('SELECT photo FROM test where id=?',(id,))
data = c.fetchall()[0][0] # Get the blob data
show(data) # Call the function with the passes data
This will show the image in a label in the root window for the entered id.

Python cryptograpy.fernet doesn't decrypt symbols properly as expected

Folks, I'm writing a simple cli tool to encrypt a text and decrypt based on the passed arguments.
It works fine when I use only text. But It behaves strange when I pass some symbols.
MY SOURCE CODE
import argparse
from cryptography.fernet import Fernet
def generate_key():
"""
Generates a key and save it into a file
"""
key = Fernet.generate_key()
with open("secret.key", "wb") as key_file:
key_file.write(key)
return key
def load_key():
"""
Loads the key named 'secret.key' from current directory
"""
return open("secret.key", "rb").read()
def encrypt_message(message):
"""
Encrypts a message
"""
key = load_key()
encoded_msg = message.encode()
f = Fernet(key)
encrypted_message = f.encrypt(encoded_msg)
with open("encrypted.txt", "wb") as encrypted_file:
encrypted_file.write(encrypted_message)
return encrypted_message
def decrypt_message(encrypted_msg):
"""
Decrypt an encrypted message
"""
key = load_key()
f = Fernet(key)
decrypted_message = f.decrypt(encrypted_msg)
return decrypted_message.decode()
def Main():
parser = argparse.ArgumentParser()
parser.add_argument("-e", "--en_crypt", help="Pass the text to encrypt as an argument")
parser.add_argument("-d", "--de_crypt", help="Pass the text to decrypt as an argument", action="store_true")
parser.add_argument("-k", "--key", help="Generate the 'secret.key' file", action="store_true")
args = parser.parse_args()
if args.en_crypt:
enc = encrypt_message(args.en_crypt)
print(enc)
if args.de_crypt:
with open("encrypted.txt", "rb") as file:
txt = file.read()
print(decrypt_message(txt))
if args.key:
result = generate_key()
print("Key Generated -> " + str(result))
if __name__ == "__main__":
Main()
MY TEST-CASE 1 - (This is successfully decrypting the text passed)
$ python3 01_crypt.py -k
Key Generated -> b'N5Ll6414I8nvcMlBytk8VwdFC4oVZZZMTCVTLpQ9big='
$ python3 01_crypt.py -e "Some Sample Text to Encrypt"
b'gAAAAABfVMU3JxZOrwLIudKLAqzq5IhivhhkyvJ6TMDxM-MmVQywo4AiZ1zGK5F5gO5JFXfHznV5zPjz6sD8qhOpIR_60Hq4_YLVIV0ztPAWBjln6reg1S0='
$ python3 01_crypt.py -d
Some Sample Text to Encrypt
MY TEST-CASE 2 - (This is not working as expected)
$ python3 01_crypt.py -k
Key Generated -> b'UDUpsIP-Ltjz8XGm-BUSwApXYE_L8eFl6rmE1yBbYW4='
$ python3 01_crypt.py -e "P#$$w0rD"
b'gAAAAABfVMX4tSIU4T1CM5Sw9jGR_O2cuIhccEM4htVTkerQD0YxWuCoUZeDWOeMIfpcP4HV7vYKmrxD22sf7yk27hGCdx0jQA=='
$ python3 01_crypt.py -d
P#4103w0rD
As per the test-case 2, My expected output should be same as the encrypted one P#$$w0rD but instead it shows as P#4103w0rD
I'm clueless why this happen. Am I missing something important? Please advice.
Thanks in Advance!
ADDITIONAL NOTE
When I try the same facility without argparse It works as expected. Please review the code below,
from cryptography.fernet import Fernet
def key_generate():
"""
Generates a key and save it into a file
"""
key = Fernet.generate_key()
with open("secret.key", "wb") as key_file:
key_file.write(key)
return key
def load_keys():
"""
Loads the generated key named 'secret.key' from current directory
"""
return open("secret.key", "rb").read()
def encrypt_message(message):
"""
Encrypts a message
"""
key = load_keys()
encoded_msg = message.encode()
f = Fernet(key)
encrypted_message = f.encrypt(encoded_msg)
return encrypted_message
def decrypt_message(encrypted_msg):
"""
Decrypt an encrypted message
"""
key = load_keys()
f = Fernet(key)
decrypted_message = f.decrypt(encrypted_msg)
# print(type(encrypted_msg))
return decrypted_message.decode()
if __name__ == "__main__":
key_generate()
load_keys()
PLAINTEXT = "P#$$w0rD"
print("Plain Text", PLAINTEXT)
ENCRYPTED_TEXT = encrypt_message(PLAINTEXT)
print("Encrypted Text", ENCRYPTED_TEXT)
DECRYPTED_TEXT = decrypt_message(ENCRYPTED_TEXT)
print("Decrypted Text", DECRYPTED_TEXT)
OUTPUT
$python3 02_decrypt.py
Plain Text P#$$w0rD
Encrypted Text b'gAAAAABfVMfzv7H--aTCaUBdHVs05VRbFmuqpnrt-7k1NCTY9FrGMZKH8y2pkKqZsu5oxRqRgp5DzyRHZhfmA9p_cgNniWfsNw=='
Decrypted Text P#$$w0rD
The above behaviour makes me suspect, argparse could be culprit. Please advice.
Argparse is not at fault, your usage of your shell is.
python3 01_crypt.py -e "P#$$w0rD"
has your Unix shell substitute the current PID for $$ (which happened to be 4103).
Use single quotes to avoid the substitution.
python3 01_crypt.py -e 'P#$$w0rD'

How to modify the PostgreSQL psycopg to accept variables instead of values

I am creating a dictionary attacking tool on PostgreSQL. The tool is inspired by the work of m8r0wn - enumdb tool. Mikes tool is aimed at MySQL and MSSQL. I aim to use the same approach he used but modify the actions and output file. The script should
1) Read a CSV file that contains targets and ports, one per line 127.0.0.1,3380.
2) when provided a list of usernames and/or passwords, it will cycle through each targeted host looking for valid credentials. By default, it will use newly discovered credentials to search for sensitive information in the host's databases via keyword searches on the table or column names.
3) This information can then be extracted and reported to a JSON, .csv or .xlsx output file.
I have a semi functional code, but I suspect the PostgreSQL connection function is not working due to the logic behind passing parameters. I am interested in suggestions on how best I could present the tools results as a JSON file.
I understand that in Python, we have several modules available to connect and work with PostgreSQL which include:
Psycopg2
pg8000
py-postgresql
PyGreSQL
ocpgdb
bpgsql
SQLAlchemy
see also https://www.a2hosting.co.za/kb/developer-corner/postgresql/connecting-to-postgresql-using-python
The connection methods I have tried include:
import psycopg2
from psycopg2 import Error
conn = psycopg2.connect(host=host, dbname=db_name, user=_user, password=_pass, port=port)
import pg
conn = pg.DB(host=args.hostname, user= _user, passwd= _pass)
sudo pip install pgdb
import pgdb
conn = pgdb.connect(host=args.hostname, user= _user, passwd= _pass)
I am not sure how to pass the different _user and _pass guesses into the pyscopg2 for instance, without breaking the code.
I have imported the following libraries
import re
import psycopg2
from psycopg2 import Error
import pgdb
#import MySQLdb
import pymssql
import argparse
from time import sleep
from sys import exit, argv
from getpass import getpass
from os import path, remove
from openpyxl import Workbook
from threading import Thread, activeCount
The PgSQL block is as follows:
##########################################
# PgSQL DB Class
##########################################
class pgsql():
def connect(self, host, port, user, passwd, verbose):
try:
con = pgdb.connect(host=host, port=port, user=user, password=passwd, connect_timeout=3)
con.query_timeout = 15
print_success("[*] Connection established {}:{}#{}".format(user,passwd,host))
return con
except Exception as e:
if verbose:
print_failure("[!] Login failed {}:{}#{}\t({})".format(user,passwd,host,e))
else:
print_failure("[!] Login failed {}:{}#{}".format(user, passwd, host))
return False
def db_query(self, con, cmd):
try:
cur = con.cursor()
cur.execute(cmd)
data = cur.fetchall()
cur.close()
except:
data = ''
return data
def get_databases(self, con):
databases = []
for x in self.db_query(con, 'SHOW DATABASES;'):
databases.append(x[0])
return databases
def get_tables(self, con, database):
tables = []
self.db_query(con, "USE {}".format(database))
for x in self.db_query(con, 'SHOW TABLES;'):
tables.append(x[0])
return tables
def get_columns(self, con, database, table):
# database var not used but kept to support mssql
columns = []
for x in self.db_query(con, 'SHOW COLUMNS FROM {}'.format(table)):
columns.append(x[0])
return columns
def get_data(self, con, database, table):
# database var not used but kept to support mssql
return self.db_query(con, 'SELECT * FROM {} LIMIT {}'.format(table, SELECT_LIMIT))
The MSSQL is as follows:
# MSSQL DB Class
class mssql():
def connect(self, host, port, user, passwd, verbose):
try:
con = pymssql.connect(server=host, port=port, user=user, password=passwd, login_timeout=3, timeout=15)
print_success("[*] Connection established {}:{}#{}".format(user,passwd,host))
return con
except Exception as e:
if verbose:
print_failure("[!] Login failed {}:{}#{}\t({})".format(user,passwd,host,e))
else:
print_failure("[!] Login failed {}:{}#{}".format(user, passwd, host))
return False
def db_query(self, con, cmd):
try:
cur = con.cursor()
cur.execute(cmd)
data = cur.fetchall()
cur.close()
except:
data = ''
return data
def get_databases(self, con):
databases = []
for x in self.db_query(con, 'SELECT NAME FROM sys.Databases;'):
databases.append(x[0])
return databases
def get_tables(self, con, database):
tables = []
for x in self.db_query(con, 'SELECT NAME FROM {}.sys.tables;'.format(database)):
tables.append(x[0])
return tables
def get_columns(self, con, database, table):
columns = []
for x in self.db_query(con, 'USE {};SELECT column_name FROM information_schema.columns WHERE table_name = \'{}\';'.format(database, table)):
columns.append(x[0])
return columns
def get_data(self, con, database, table):
return self.db_query(con, 'SELECT TOP({}) * FROM {}.dbo.{};'.format(SELECT_LIMIT, database, table))
The main function block:
def main(args):
try:
for t in args.target:
x = Thread(target=enum_db().db_main, args=(args, t,))
x.daemon = True
x.start()
# Do not exceed max threads
while activeCount() > args.max_threads:
sleep(0.001)
# Exit all threads before closing
while activeCount() > 1:
sleep(0.001)
except KeyboardInterrupt:
print("\n[!] Key Event Detected...\n\n")
exit(0)
if __name__ == '__main__':
version = '1.0.7'
try:
args = argparse.ArgumentParser(description=("""
{0} (v{1})
--------------------------------------------------
Brute force Juggernaut is a PgSQL brute forcing tool.**""").format(argv[0], version), formatter_class=argparse.RawTextHelpFormatter, usage=argparse.SUPPRESS)
user = args.add_mutually_exclusive_group(required=True)
user.add_argument('-u', dest='users', type=str, action='append', help='Single username')
user.add_argument('-U', dest='users', default=False, type=lambda x: file_exists(args, x), help='Users.txt file')
passwd = args.add_mutually_exclusive_group()
passwd.add_argument('-p', dest='passwords', action='append', default=[], help='Single password')
passwd.add_argument('-P', dest='passwords', default=False, type=lambda x: file_exists(args, x), help='Password.txt file')
args.add_argument('-threads', dest='max_threads', type=int, default=3, help='Max threads (Default: 3)')
args.add_argument('-port', dest='port', type=int, default=0, help='Specify non-standard port')
args.add_argument('-r', '-report', dest='report', type=str, default=False, help='Output Report: csv, xlsx (Default: None)')
args.add_argument('-t', dest='dbtype', type=str, required=True, help='Database types currently supported: mssql, pgsql')
args.add_argument('-c', '-columns', dest="column_search", action='store_true', help="Search for key words in column names (Default: table names)")
args.add_argument('-v', dest="verbose", action='store_true', help="Show failed login notices & keyword matches with Empty data sets")
args.add_argument('-brute', dest="brute", action='store_true', help='Brute force only, do not enumerate')
args.add_argument(dest='target', nargs='+', help='Target database server(s)')
args = args.parse_args()
# Put target input into an array
args.target = list_targets(args.target[0])
# Get Password if not provided
if not args.passwords:
args.passwords = [getpass("Enter password, or continue with null-value: ")]
# Define default port based on dbtype
if args.port == 0: args.port = default_port(args.dbtype)
# Launch Main
print("\nStarting enumdb v{}\n".format(version) + "-" * 25)
main(args)
except KeyboardInterrupt:
print("\n[!] Key Event Detected...\n\n")
exit(0)
I am aware that documentation states here http://initd.org/psycopg/docs/module.html states about how connection parameters can be specified. I would like to pass password guesses into the brute class and recursively try different combinations.
PEP-8 asks that you please give classes a name
starting with a capital letter, e.g. Pgsql.
You mentioned that the pgsql connect() method is not working properly,
but didn't offer any diagnostics such as a stack trace.
You seem to be working too hard, given that the sqlalchemy layer
has already addressed the DB porting issue quite nicely.
Just assemble a connect string starting with
the name of the appropriate DB package,
and let sqlalchemy take care of the rest.
All your methods accept con as an argument.
You really want to factor that out as the object attribute self.con.
The db_query() method apparently assumes that
arguments for WHERE clauses already appear, properly quoted, in cmd.
According to Little Bobby's mother,
it makes sense to accept query args according to the API,
rather than worrying about potential for SQL injection.

Resources