I am struggling to decrypt Chrome cookies in local storage on Windows. I used this code below that was working fine for me some time ago but now I am just getting the error:
decrypt.py”, line 24, in decrypt_cookies
query_res = cursor.fetchall()
^^^^^^^^^^^^^^^^^ sqlite3.OperationalError: Could not decode to UTF-8 column ‘encrypted_value’ with text
After googling this problem I tried to change text_factory
:
<code>conn = sqlite3.connect(cookies_db)
conn.text_factory = bytes
<code>conn = sqlite3.connect(cookies_db)
conn.text_factory = bytes
</code>
conn = sqlite3.connect(cookies_db)
conn.text_factory = bytes
But this leads to a new error:
Libsite-packagesCryptodomeCipher_mode_gcm.py”, line 508, in verify
raise ValueError(“MAC check failed”) ValueError: MAC check failed
This is the whole code I used:
Decrypt module:
from Cryptodome.Cipher.AES import new, MODE_GCM # pip install pycryptodomex
from win32.win32crypt import CryptUnprotectData # pip install pywin32
def decrypt_dpapi_blob(encrypted_blob):
encrypted_blob = base64.b64decode(encrypted_blob)[5:] # Leading bytes "DPAPI" need to be removed
decrypt_res = CryptUnprotectData(encrypted_blob, None, None, None, 0)
def decrypt_cookies(cookies_db, key):
sqlite3.enable_callback_tracebacks(True)
conn = sqlite3.connect(cookies_db)
conn.text_factory = bytes
query = "SELECT name, encrypted_value FROM cookies"
cursor = conn.execute(query)
query_res = cursor.fetchall()
cookie_name, encrypted_value = row
if encrypted_value is None or len(encrypted_value) == 0:
verification_tag = encrypted_value[-16:]
aes_cipher = new(key=key, mode=MODE_GCM, nonce=encrypted_value[3:15])
decrypted_value = aes_cipher.decrypt_and_verify(ciphertext=encrypted_value[15: -16], received_mac_tag=verification_tag)
# if cookie_name == "BITBUCKETSESSIONID":
# print(f"Decrypted cookie (bitbucket):n {decrypted_value.decode()}")
# print(f"Verification tag (bitbucket):n {bytes_to_hex(verification_tag)}")
# print(f"Nonce (bitbucket):n {bytes_to_hex(nonce)}")
query = f"UPDATE cookies SET encrypted_value = ? WHERE name = '{cookie_name}'"
params = [decrypted_value]
cursor.execute(query, params)
if __name__ == "__main__":
decrypted_key = encrypt.get_local_state_key()
print("Decryption failed:", str(e))
# C:UsersUserAppDataLocalGoogleChromeUser DataDefaultNetwork
parser = argparse.ArgumentParser()
parser.add_argument("--cookies", help="Name of the cookies database file", default="Cookies")
args = parser.parse_args()
cookies_db = os.path.join(os.getcwd(), args.cookies)
decrypt_cookies(cookies_db, decrypted_key)
<code># decrypt.py
import argparse
import base64
import os
import sqlite3
import sys
from Cryptodome.Cipher.AES import new, MODE_GCM # pip install pycryptodomex
from win32.win32crypt import CryptUnprotectData # pip install pywin32
import encrypt
def decrypt_dpapi_blob(encrypted_blob):
encrypted_blob = base64.b64decode(encrypted_blob)[5:] # Leading bytes "DPAPI" need to be removed
decrypt_res = CryptUnprotectData(encrypted_blob, None, None, None, 0)
return decrypt_res
def decrypt_cookies(cookies_db, key):
sqlite3.enable_callback_tracebacks(True)
conn = sqlite3.connect(cookies_db)
conn.text_factory = bytes
query = "SELECT name, encrypted_value FROM cookies"
cursor = conn.execute(query)
query_res = cursor.fetchall()
for row in query_res:
cookie_name, encrypted_value = row
if encrypted_value is None or len(encrypted_value) == 0:
continue
verification_tag = encrypted_value[-16:]
aes_cipher = new(key=key, mode=MODE_GCM, nonce=encrypted_value[3:15])
decrypted_value = aes_cipher.decrypt_and_verify(ciphertext=encrypted_value[15: -16], received_mac_tag=verification_tag)
# if cookie_name == "BITBUCKETSESSIONID":
# print(f"Decrypted cookie (bitbucket):n {decrypted_value.decode()}")
# print(f"Verification tag (bitbucket):n {bytes_to_hex(verification_tag)}")
# print(f"Nonce (bitbucket):n {bytes_to_hex(nonce)}")
query = f"UPDATE cookies SET encrypted_value = ? WHERE name = '{cookie_name}'"
params = [decrypted_value]
cursor.execute(query, params)
conn.commit()
conn.close()
if __name__ == "__main__":
try:
decrypted_key = encrypt.get_local_state_key()
except Exception as e:
print("Decryption failed:", str(e))
sys.exit(1)
# C:UsersUserAppDataLocalGoogleChromeUser DataDefaultNetwork
# Arg: cookies_db
parser = argparse.ArgumentParser()
parser.add_argument("--cookies", help="Name of the cookies database file", default="Cookies")
args = parser.parse_args()
cookies_db = os.path.join(os.getcwd(), args.cookies)
decrypt_cookies(cookies_db, decrypted_key)
</code>
# decrypt.py
import argparse
import base64
import os
import sqlite3
import sys
from Cryptodome.Cipher.AES import new, MODE_GCM # pip install pycryptodomex
from win32.win32crypt import CryptUnprotectData # pip install pywin32
import encrypt
def decrypt_dpapi_blob(encrypted_blob):
encrypted_blob = base64.b64decode(encrypted_blob)[5:] # Leading bytes "DPAPI" need to be removed
decrypt_res = CryptUnprotectData(encrypted_blob, None, None, None, 0)
return decrypt_res
def decrypt_cookies(cookies_db, key):
sqlite3.enable_callback_tracebacks(True)
conn = sqlite3.connect(cookies_db)
conn.text_factory = bytes
query = "SELECT name, encrypted_value FROM cookies"
cursor = conn.execute(query)
query_res = cursor.fetchall()
for row in query_res:
cookie_name, encrypted_value = row
if encrypted_value is None or len(encrypted_value) == 0:
continue
verification_tag = encrypted_value[-16:]
aes_cipher = new(key=key, mode=MODE_GCM, nonce=encrypted_value[3:15])
decrypted_value = aes_cipher.decrypt_and_verify(ciphertext=encrypted_value[15: -16], received_mac_tag=verification_tag)
# if cookie_name == "BITBUCKETSESSIONID":
# print(f"Decrypted cookie (bitbucket):n {decrypted_value.decode()}")
# print(f"Verification tag (bitbucket):n {bytes_to_hex(verification_tag)}")
# print(f"Nonce (bitbucket):n {bytes_to_hex(nonce)}")
query = f"UPDATE cookies SET encrypted_value = ? WHERE name = '{cookie_name}'"
params = [decrypted_value]
cursor.execute(query, params)
conn.commit()
conn.close()
if __name__ == "__main__":
try:
decrypted_key = encrypt.get_local_state_key()
except Exception as e:
print("Decryption failed:", str(e))
sys.exit(1)
# C:UsersUserAppDataLocalGoogleChromeUser DataDefaultNetwork
# Arg: cookies_db
parser = argparse.ArgumentParser()
parser.add_argument("--cookies", help="Name of the cookies database file", default="Cookies")
args = parser.parse_args()
cookies_db = os.path.join(os.getcwd(), args.cookies)
decrypt_cookies(cookies_db, decrypted_key)
Encrypt module:
from os.path import expandvars
from Cryptodome.Cipher.AES import new, MODE_GCM # pip install pycryptodomex
from win32.win32crypt import CryptProtectData # pip install pywin32
def encrypt_dpapi_blob(decrypted_blob):
encrypted_blob = CryptProtectData(decrypted_blob, DataDescr="Google Chrome", OptionalEntropy=None, Reserved=None, PromptStruct=None, Flags=0)
encrypted_blob = b'DPAPI' + encrypted_blob
encrypted_blob_base64 = base64.b64encode(encrypted_blob)
return encrypted_blob_base64
def encrypt_cookies(cookies_db, key):
sqlite3.enable_callback_tracebacks(True)
conn = sqlite3.connect(cookies_db)
query = "SELECT name, encrypted_value FROM cookies"
cursor = conn.execute(query)
query_res = cursor.fetchall()
cookie_name, decrypted_value = row
if decrypted_value is None or len(decrypted_value) == 0:
aes_cipher = new(key=key, mode=MODE_GCM, nonce=nonce)
encrypted_value, verification_tag = aes_cipher.encrypt_and_digest(decrypted_value)
encrypted_cookie = b'x76x31x30' +
query = f"UPDATE cookies SET encrypted_value = ? WHERE name = '{cookie_name}'"
params = [encrypted_cookie]
cursor.execute(query, params)
def get_local_state_key():
local_state = json.load(open(expandvars('%LOCALAPPDATA%/Google/Chrome/User Data/Local State')))
encrypted_key = local_state['os_crypt']['encrypted_key']
decrypted_key = decrypt.decrypt_dpapi_blob(encrypted_key)[1]
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--cookies", help="Name of the cookies database file", default="Cookies")
args = parser.parse_args()
cookies_db = os.path.join(os.getcwd(), args.cookies)
key = get_local_state_key()
encrypt_cookies(cookies_db, key)
<code>#encrypt.py
import argparse
import json
import os
import base64
import sqlite3
from os.path import expandvars
from Cryptodome.Cipher.AES import new, MODE_GCM # pip install pycryptodomex
from win32.win32crypt import CryptProtectData # pip install pywin32
import decrypt
def encrypt_dpapi_blob(decrypted_blob):
encrypted_blob = CryptProtectData(decrypted_blob, DataDescr="Google Chrome", OptionalEntropy=None, Reserved=None, PromptStruct=None, Flags=0)
encrypted_blob = b'DPAPI' + encrypted_blob
encrypted_blob_base64 = base64.b64encode(encrypted_blob)
return encrypted_blob_base64
def encrypt_cookies(cookies_db, key):
sqlite3.enable_callback_tracebacks(True)
conn = sqlite3.connect(cookies_db)
query = "SELECT name, encrypted_value FROM cookies"
cursor = conn.execute(query)
query_res = cursor.fetchall()
for row in query_res:
cookie_name, decrypted_value = row
if decrypted_value is None or len(decrypted_value) == 0:
continue
nonce = os.urandom(12)
aes_cipher = new(key=key, mode=MODE_GCM, nonce=nonce)
encrypted_value, verification_tag = aes_cipher.encrypt_and_digest(decrypted_value)
encrypted_cookie = b'x76x31x30' +
nonce +
encrypted_value +
verification_tag
query = f"UPDATE cookies SET encrypted_value = ? WHERE name = '{cookie_name}'"
params = [encrypted_cookie]
cursor.execute(query, params)
conn.commit()
conn.close()
def get_local_state_key():
local_state = json.load(open(expandvars('%LOCALAPPDATA%/Google/Chrome/User Data/Local State')))
encrypted_key = local_state['os_crypt']['encrypted_key']
decrypted_key = decrypt.decrypt_dpapi_blob(encrypted_key)[1]
return decrypted_key
if __name__ == "__main__":
# Arg: cookies_db
parser = argparse.ArgumentParser()
parser.add_argument("--cookies", help="Name of the cookies database file", default="Cookies")
args = parser.parse_args()
cookies_db = os.path.join(os.getcwd(), args.cookies)
key = get_local_state_key()
encrypt_cookies(cookies_db, key)
</code>
#encrypt.py
import argparse
import json
import os
import base64
import sqlite3
from os.path import expandvars
from Cryptodome.Cipher.AES import new, MODE_GCM # pip install pycryptodomex
from win32.win32crypt import CryptProtectData # pip install pywin32
import decrypt
def encrypt_dpapi_blob(decrypted_blob):
encrypted_blob = CryptProtectData(decrypted_blob, DataDescr="Google Chrome", OptionalEntropy=None, Reserved=None, PromptStruct=None, Flags=0)
encrypted_blob = b'DPAPI' + encrypted_blob
encrypted_blob_base64 = base64.b64encode(encrypted_blob)
return encrypted_blob_base64
def encrypt_cookies(cookies_db, key):
sqlite3.enable_callback_tracebacks(True)
conn = sqlite3.connect(cookies_db)
query = "SELECT name, encrypted_value FROM cookies"
cursor = conn.execute(query)
query_res = cursor.fetchall()
for row in query_res:
cookie_name, decrypted_value = row
if decrypted_value is None or len(decrypted_value) == 0:
continue
nonce = os.urandom(12)
aes_cipher = new(key=key, mode=MODE_GCM, nonce=nonce)
encrypted_value, verification_tag = aes_cipher.encrypt_and_digest(decrypted_value)
encrypted_cookie = b'x76x31x30' +
nonce +
encrypted_value +
verification_tag
query = f"UPDATE cookies SET encrypted_value = ? WHERE name = '{cookie_name}'"
params = [encrypted_cookie]
cursor.execute(query, params)
conn.commit()
conn.close()
def get_local_state_key():
local_state = json.load(open(expandvars('%LOCALAPPDATA%/Google/Chrome/User Data/Local State')))
encrypted_key = local_state['os_crypt']['encrypted_key']
decrypted_key = decrypt.decrypt_dpapi_blob(encrypted_key)[1]
return decrypted_key
if __name__ == "__main__":
# Arg: cookies_db
parser = argparse.ArgumentParser()
parser.add_argument("--cookies", help="Name of the cookies database file", default="Cookies")
args = parser.parse_args()
cookies_db = os.path.join(os.getcwd(), args.cookies)
key = get_local_state_key()
encrypt_cookies(cookies_db, key)