Chrome 80 如何解码cookies

Chrome 80 how to decode cookies

我有一个用于打开和解密 Google Chrome cookie 的工作脚本,它看起来像:

decrypted = win32crypt.CryptUnprotectData(enctypted_cookie_value, None, None, None, 0)

更新80后似乎不再是有效的解决方案

根据此博客 post https://blog.nirsoft.net/2020/02/19/tools-update-new-encryption-chrome-chromium-version-80/ 看来我需要从本地状态文件 encrypted_key 上 CryptUnprotectData,而不是使用解密密钥以某种方式解密 cookie。

第一部分我得到了 encrypted_key

path = r'%LocalAppData%\Google\Chrome\User Data\Local State'
path = os.path.expandvars(path)
with open(path, 'r') as file:
    encrypted_key = json.loads(file.read())['os_crypt']['encrypted_key']
encrypted_key = bytearray(encrypted_key, 'utf-8')

然后我尝试解密

decrypted_key = win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)

出现异常:

pywintypes.error: (13, 'CryptProtectData', 'The data is invalid.')

我不知道如何修复它

还有第二部分的加密,看来我应该使用pycryptodome,像这样的片段:

cipher = AES.new(encrypted_key, AES.MODE_GCM, nonce=nonce)
plaintext = cipher.decrypt(data)

但我不知道我应该从哪里获得 nonce 值

有人可以解释一下,如何正确解密 Chrome cookies 吗?

自 Chrome 版本 80 及更高版本以来,cookie 在 GCM 模式下使用 AES-256 加密。应用的密钥使用 DPAPI 加密。详情描述 here, section Chrome v80.0 and higher.

加密密钥以DPAPI(即0x4450415049)的ASCII编码开头,采用Base64编码,即密钥必须先进行Base64解码,并去除前5个字节。之后可以使用 win32crypt.CryptUnprotectData 进行解密。解密returns一个元组,其第二个值包含解密密钥:

import os
import json
import base64 
import win32crypt
from Crypto.Cipher import AES

path = r'%LocalAppData%\Google\Chrome\User Data\Local State'
path = os.path.expandvars(path)
with open(path, 'r') as file:
    encrypted_key = json.loads(file.read())['os_crypt']['encrypted_key']
encrypted_key = base64.b64decode(encrypted_key)                                       # Base64 decoding
encrypted_key = encrypted_key[5:]                                                     # Remove DPAPI
decrypted_key = win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1]  # Decrypt key

使用 AES-256 in GCM mode 对 cookie 进行加密。这是经过身份验证的加密,可以保证机密性和authenticity/integrity。在加密过程中会生成一个认证标签,用于解密过程中的完整性验证。 GCM 模式基于 CTR 模式并使用 IV(随机数)。除了 32 字节密钥外,解密还需要 nonce 和身份验证标记。

加密数据以v10的ASCII编码开始(即0x763130),接着是12字节的随机数,实际的密文,最后是16字节的认证标签。各个组件可以按如下方式分开:

data = bytes.fromhex('763130...') # the encrypted cookie
nonce = data[3:3+12]
ciphertext = data[3+12:-16]
tag = data[-16:]

其中 data 包含加密数据。解密本身是使用 PyCryptodome 完成的:

cipher = AES.new(decrypted_key, AES.MODE_GCM, nonce=nonce)
plaintext = cipher.decrypt_and_verify(ciphertext, tag) # the decrypted cookie

注意:一般也有存储的cookie是用Chromev80以下版本保存的,因此是DPAPI加密的。 DPAPI 加密的 cookie 可以通过它们分别以 0x01000000D08C9DDF0115D1118C7A00C04FC297EBhere and here, section About DPAPI. These cookies can of course not be decrypted as described above, but with the former procedure for DPAPI encrypted cookies. Tools to view cookies in unencrypted or encrypted form are ChromeCookiesView or DB Browser for SQLite 序列开始的事实来识别。

可能您已经从 Windows 上的一个用户帐户复制了 DPAPI 加密密钥值,并试图在以另一用户身份登录时调用 CryptUnprotectData WinAPI。根据 DPAPI 的性质,这将不起作用。