I want to open the Chrome (Login Data) file and use its password field. But this field is stored in byte/blob mode and can not be converted to text.
I also tried codecs and pickle and bytes.encode and str.decode but it didn't work.
Please look at the code below and help :
import sqlite3
connection_obj = sqlite3.connect('C:/Users/{username}/AppData/Local/Google/Chrome/User
Data/Default/Login Data')
cursor_obj = connection_obj.cursor()
statement = '''SELECT action_url, username_value, password_value FROM logins'''
cursor_obj.execute(statement)
output = cursor_obj.fetchmany(5)
for url,usr,psw in output:
# convert psw blob -> ascii text
# ....
# ....
# for example psw filed:
# b'v10\x7f\xa3\x1a\xd1\x83g\x8c\xc4\x14]\xb6n\xf85\xba\xca\xf5r\x17\xb6D\xed\xf5\x11rM\xbe\xbf\xb1\xc2y\xc5Vr\xc3\xb3NB\xc7J\x14\x95'
#
# convert to below text :
# zarfilm-136342
print(url, usr, psw,sep='------')
print('*'*10)
connection_obj.commit()
connection_obj.close()
That data is encrypted in AES, and further the key is encrypted with CryptProtectData to lock the encryption key to user data. You can decrypt the data with something like this:
import base64, json, os, sqlite3, win32crypt
from Crypto.Cipher import AES
def chrome_key():
local_state_fn = os.path.join(os.environ["USERPROFILE"],"AppData","Local","Google","Chrome","User Data","Local State")
with open(local_state_fn, "r") as f:
local_state = json.load(f)
key = base64.b64decode(local_state["os_crypt"]["encrypted_key"])
key = key[5:]
return win32crypt.CryptUnprotectData(key, None, None, None, 0)[1]
def decrypt_password(password, key):
iv, password = password[3:15], password[15:]
aes = AES.new(key, AES.MODE_GCM, iv)
return aes.decrypt(password)[:-16].decode("utf-8")
def main():
key = chrome_key()
db_fn = os.path.join(os.environ["USERPROFILE"],"AppData","Local","Google","Chrome","User Data","default","Login Data")
db = sqlite3.connect(db_fn)
for origin_url, username, password_crypt in db.execute("SELECT origin_url, username_value, password_value FROM logins;"):
password = decrypt_password(password_crypt, key)
print(f"{origin_url}, {username}, {password}")
db.close()
if __name__ == "__main__":
main()
Are you surprised to learn that this field is encrypted? Google would be in for a world of trouble if it wasn't. Even Chrome doesn't know how to decrypt this. It's done with the Windows cryptography APIs, and involved your Windows login password. You can't get them.
Related
I have a program that decrypts chrome saved info and puts it into a file. I am trying to turn it into an .exe from .py but when run, does not work.
My code is
import base64
import json
import os
import shutil
import sqlite3
from contextlib import redirect_stdout
from datetime import datetime, timedelta
from Crypto.Cipher import AES
from win32crypt import CryptUnprotectData
def get_chrome_datetime(chromedate):
"""Return a `datetime.datetime` object from a chrome format datetime
Since `chromedate` is formatted as the number of microseconds since January, 1601"""
return datetime(1601, 1, 1) + timedelta(microseconds=chromedate)
def get_encryption_key():
local_state_path = os.path.join(os.environ["USERPROFILE"],
"AppData", "Local", "Google", "Chrome",
"User Data", "Local State")
with open(local_state_path, "r", encoding="utf-8") as f:
local_state = f.read()
local_state = json.loads(local_state)
# decode the encryption key from Base64
key = base64.b64decode(local_state["os_crypt"]["encrypted_key"])
# remove DPAPI str
key = key[5:]
# return decrypted key that was originally encrypted
# using a session key derived from current user's logon credentials
# doc: http://timgolden.me.uk/pywin32-docs/win32crypt.html
return CryptUnprotectData(key, None, None, None, 0)[1]
def decrypt_password(password, key):
try:
# get the initialization vector
iv = password[3:15]
password = password[15:]
# generate cipher
cipher = AES.new(key, AES.MODE_GCM, iv)
# decrypt password
return cipher.decrypt(password)[:-16].decode()
except:
try:
return str(CryptUnprotectData(password, None, None, None, 0)[1])
except:
# not supported
return ""
def main():
global origin_url, action_url, username, password
key = get_encryption_key()
db_path = os.path.join(os.environ["USERPROFILE"], "AppData", "Local",
"Google", "Chrome", "User Data", "default", "Login Data")
# copy the file to another location
# as the database will be locked if chrome is currently running
filename = "ChromeData.db"
shutil.copyfile(db_path, filename)
# connect to the database
db = sqlite3.connect(filename)
cursor = db.cursor()
# `logins` table has the data we need
cursor.execute("select origin_url, action_url, username_value, password_value, date_created, date_last_used from logins order by date_created")
# iterate over all rows
for row in cursor.fetchall():
origin_url = row[0]
action_url = row[1]
username = row[2]
password = decrypt_password(row[3], key)
date_created = row[4]
date_last_used = row[5]
with open('out.txt', 'a') as f:
with redirect_stdout(f):
print(f'\nOrigin URL: {origin_url}'
f'\nAction URL: {action_url}'
f'\nUsername: {username}'
f'\nPassword: {password}',
f'\n', '=' * 50)
if username or password:
print(f"Origin URL: {origin_url}")
print(f"Action URL: {action_url}")
print(f"Username: {username}")
print(f"Password: {password}")
else:
continue
if date_created != 86400000000 and date_created:
print(f"Creation date: {str(get_chrome_datetime(date_created))}")
if date_last_used != 86400000000 and date_last_used:
print(f"Last Used: {str(get_chrome_datetime(date_last_used))}")
print("="*50)
cursor.close()
db.close()
try:
os.remove(filename)
except:
pass
if __name__ == "__main__":
main()
When turned from .py to .exe with pyinstaller, the program turns successfully but the exe will not run. I ran it through cmd and got
Traceback (most recent call last):
File "main.py", line 8, in <module>
ModuleNotFoundError: No module named 'Crypto'
[13152] Failed to execute script 'main' due to unhandled exception!
I have crypto installed on pycharm as well with pip to my machine.
I'm really not sure what the problem is. I've tried encoding the cyphertext in the decrypt() method before actually decrypting it, as well. Instead of displaying the proper plaintext message, it displays a garbled mess of characters different from the original cyphertext.
This is all embedded in a Flask app web API, which is why I need to decode the bytes:
########CALLING DECRYPT FROM HERE########
def get(self):
parser = reqparse.RequestParser()
parser.add_argument('mode', required= True)
parser.add_argument('key', required= False)
parser.add_argument('text', required= False)
args = parser.parse_args() # parse args to dict
mode = args['mode']
if mode == 'keygen':
return self.keygen()
elif mode == 'encrypt' and args['key'] != None and args['text'] != None:
return self.encrypt(args['key'], args['text'])
elif mode == 'decrypt' and args['key'] != None and args['text'] != None:
return self.decrypt(args['key'], args['text'])
###########################################
def keygen(self):
key = urandom(16)
dkey = b16encode(key).decode('utf-8')
return {'key': dkey} # return cryptographic key
def encrypt(self, key, raw):
crypt = AES.new(key, AES.MODE_CFB, iv)
ciphertext = crypt.encrypt(raw) # type() yields 'bytes'
# have to decode, flask wont allow bytes in json
ciph = b16encode(ciphertext).decode('utf-8')
return {'secret': ciph}
def decrypt(self, key, cipher):
# TODO not decrypting properly
# have a suspicion that the failed decryption has to do with cipher being a str input
crypt = AES.new(key, AES.MODE_CFB, iv)
plaintext = crypt.decrypt(cipher)
raw = b16encode(plaintext).decode('utf-8')
return {'message': raw}
Any help would be appreciated! I'm not sure if I'm making a stupid mistake here.
I have just finished this script (python 3.9), and all output on it is using the '''print()''' command. I am wondering if there is a way to send my output to a webhook, I am thinking I could do this via the stdout but I am not sure and don't know where to start. Here is the script I am working with.
import os
import json
import base64
import sqlite3
import win32crypt
from Cryptodome.Cipher import AES
import shutil
from datetime import timezone, datetime, timedelta
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:
print(f"Main URL: {main_url}")
print(f"Login URL: {login_page_url}")
print(f"User name: {user_name}")
print(f"Decrypted Password: {decrypted_password}")
else:
continue
if date_of_creation != 86400000000 and date_of_creation:
print(f"Creation date: {str(chrome_date_and_time(date_of_creation))}")
if last_usuage != 86400000000 and last_usuage:
print(f"Last Used: {str(chrome_date_and_time(last_usuage))}")
print("=" * 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()
hello iam using python script to fetch a message from a specific address mail seems everything work fine but i have a problem with the printable result is a base64 code.
i want to decode the result to get the decode message when do the final result with print, pls help!!
already thanks
the code used.
# Importing libraries
import imaplib, email
user = 'USER_EMAIL_ADDRESS'
password = 'USER_PASSWORD'
imap_url = 'imap.gmail.com'
# Function to get email content part i.e its body part
def get_body(msg):
if msg.is_multipart():
return get_body(msg.get_payload(0))
else:
return msg.get_payload(None, True)
# Function to search for a key value pair
def search(key, value, con):
result, data = con.search(None, key, '"{}"'.format(value))
return data
# Function to get the list of emails under this label
def get_emails(result_bytes):
msgs = [] # all the email data are pushed inside an array
for num in result_bytes[0].split():
typ, data = con.fetch(num, 'BODY.PEEK[1]')
msgs.append(data)
return msgs
# this is done to make SSL connnection with GMAIL
con = imaplib.IMAP4_SSL(imap_url)
# logging the user in
con.login(user, password)
# calling function to check for email under this label
con.select('Inbox')
# fetching emails from this user "tu**h*****1#gmail.com"
msgs = get_emails(search('FROM', 'MY_ANOTHER_GMAIL_ADDRESS', con))
# Uncomment this to see what actually comes as data
# print(msgs)
# Finding the required content from our msgs
# User can make custom changes in this part to
# fetch the required content he / she needs
# printing them by the order they are displayed in your gmail
for msg in msgs[::-1]:
for sent in msg:
if type(sent) is tuple:
# encoding set as utf-8
content = str(sent[1], 'utf-8')
data = str(content)
# Handling errors related to unicodenecode
try:
indexstart = data.find("ltr")
data2 = data[indexstart + 5: len(data)]
indexend = data2.find("</div>")
# printtng the required content which we need
# to extract from our email i.e our body
print(data2[0: indexend])
except UnicodeEncodeError as e:
pass
THE RESULT PRINTED
'''
aGVsbG8gd29yZCBpYW0gdGhlIG1lc3NhZ2UgZnJvbSBnbWFpbA==
'''
You could just use the base64 module to decode base64 encoded strings:
import base64
your_string="aGVsbG8gV29ybGQ==" # the base64 encoded string you need to decode
result = base64.b64decode(your_string.encode("utf8")).decode("utf8")
print(result)
Edit: encoding changed from ASCII to utf-8
If you need to find all encoded places (can be Subject, From, To email addresses with names), the code below might be useful. Given contentData is the entire email,
import re, base64
encodedParts=re.findall('(=\?(.+)\?B\?(.+)\?=)', contentData)
for part in encodedParts:
encodedPart = part[0]
charset = part[1]
encodedContent = part[2]
contentData = contentData.replace(encodedPart, base64.b64decode(encodedContent).decode(charset))
i try to encrypt and then decrypt text with Crypto and AWS KMS on Python, i have this code :
import base64
import boto3
from Crypto.Cipher import AES
PAD = lambda s: s + (256 - len(s) % 256) * ' '
def get_arn(aws_data):
return 'arn:aws:kms:{region}:{account_number}:key/{key_id}'.format(**aws_data)
def encrypt_data(aws_data, plaintext_message):
kms_client = boto3.client(
'kms',
region_name=aws_data['region'])
data_key = kms_client.generate_data_key(
KeyId=aws_data['key_id'],
KeySpec='AES_256')
cipher_text_blob = data_key.get('CiphertextBlob')
plaintext_key = data_key.get('Plaintext')
# Note, does not use IV or specify mode... for demo purposes only.
cypher = AES.new(plaintext_key, AES.MODE_CBC)
encrypted_data = base64.b64encode(cypher.encrypt(PAD(plaintext_message).encode("utf-8")))
# Need to preserve both of these data elements
return encrypted_data, cipher_text_blob
def decrypt_data(aws_data, encrypted_data, cipher_text_blob):
kms_client = boto3.client(
'kms',
region_name=aws_data['region'])
decrypted_key = kms_client.decrypt(CiphertextBlob=cipher_text_blob).get('Plaintext')
cypher = AES.new(decrypted_key, AES.MODE_CBC)
return cypher.decrypt(base64.b64decode(encrypted_data)).rstrip()
def main():
# Add your account number / region / KMS Key ID here.
aws_data = {
'region': 'eu-west-1',
'account_number': '7011777xxxxx',
'key_id': 'xxxxxx-83ac-xxxxxx-93d4-xxxxxx',
}
# And your super secret message to envelope encrypt...
plaintext = 'Hello, Worldas!'
# Store encrypted_data & cipher_text_blob in your persistent storage. You will need them both later.
encrypted_data, cipher_text_blob = encrypt_data(aws_data, plaintext)
print(encrypted_data)
decrypted_data = decrypt_data(aws_data, encrypted_data, cipher_text_blob)
print(decrypted_data)
if __name__ == '__main__':
main()
I encrypting for test message 'Hello, Worldas!' my encrypted_data in output looks like : b'ESsdSQv6JxpQptBmj321eX/bVj3gyGJ7AHtrH5qeIfTWbqSzIP7i6URrZFme1PGSNRGzl12B/NBFbK0nHBcCcaj9Wb9Qh+YMYJjeSTnGWOKFWmcIKYAAut9d040xiWG0KKBwHJTdl+41+g8F2ueSWqO1zR9Uuw1qyekF9s/141W7t+Le8IRe60tQKhgMAW5qxDVGluWZGJXLYDLIqFXszN9OhLmjwbMnF4g0ryMq41xbAXH77x0EJODhF1GQ+peHnKuexlhuzRjq1XVAvIgxQ1kYvBSE9AkqqCsO5BwIJuAlwfOWA93gSyTgLmWOg8bPTan4UnQNtTQ3vaRScffPgg=='
But then i try to decrypt i get output : b'-94\xc1\xee\xecF\xfbw9\x81o;\x9d\x1a\x10' instead of 'Hello, Worldas!'
Maybe whom know where is a problem? Why it happen? and how can i encrypt and decrypt my file properly ? please suggest!