This post elaborates on my question on the Information Security Stack Exchange and further lists information of my concern. In Chromium version 80 and up, rather than passing cookies to Windows Data Protection API (DPAPI) directly they’re encrypted with a stronger encryption algorithm and only the encryption key is protected through the API. This post is additionally notes of mine and what I’ve found so far.
How cookie encryption in Chromium version 80 and up works…
A stronger encryption algorithm is used and Windows Data Protection API encrypts the key that’s stored in the local state file.
Starting Chrome 80 version, cookies are encrypted using the AES256-GCM algorithm, and the AES encryption key is encrypted with the DPAPI encryption system, and the encrypted key is stored inside the ‘Local State’ file.Arun (https://stackoverflow.com/questions/60230456/dpapi-fails-with-cryptographicexception-when-trying-to-decrypt-chrome-cookies/60611673#60611673)
Based on my testing and what I have read (Encrypted cookies in Chrome) (DPAPI fails with CryptographicException when trying to decrypt Chrome cookies), the protection scope appears to of changed from CurrentUser to LocalMachine. My concern here is that another user on the machine, if they were to either bypass file system permissions, or simply take out the hard drive and copy another user’s Chrome Profile Folder, they’d be able to use their Windows Credentials and access to DPAPI to access another users cookie and password storage. My blog post How to read encrypted Google Chrome cookies in C# shows the process of decryption of cookies in Chromium 80 as well as how it contrasted in version 79 and lower.
How the Windows Data Protection API works with scopes…
The Windows Data Protection API (DPAPI) takes a byte array and encrypts it using a key derived from your Windows Credentials. You can pass the byte array back to DPAPI later on when you need to access the encrypted contents. As the data is encrypted, another user on the system (or someone who pulled the hard drive from your computer) cannot access your encrypted cookie and password data. There are two scopes of note. The CurrentUser scope is your account, meaning that only your account has permission to decrypt data. The LocalMachine scope is more open, any account on your computer has permission to decrypt the data. (See DataProtectionScope Enum)
The Microsoft Windows API Docs has the following to say about how the Windows Data Protection API treats data protection scopes.
Typically, only a user with logon credentials that match those of the user who encrypted the data can decrypt the data. In addition, decryption usually can only be done on the computer where the data was encrypted. However, a user with a roaming profile can decrypt the data from another computer on the network. If the CRYPTPROTECT_LOCAL_MACHINE flag is set when the data is encrypted, any user on the computer where the encryption was done can decrypt the data. The function creates a session key to perform the encryption. The session key is derived again when the data is to be decrypted.https://docs.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectdata#return-value
Why the encryption process was changed in Chromium version 80…
The Chromium team published a design documented titled DPAPI inside the sandbox, in this document they outline the issue that they’re unable to access DPAPI from within the Chromium sandbox and need an improved solution to keep user data secure. This document outlined their plan on what to change, the risks it poses, and how they would implement it. It’s well worth a read.
After a discussion on Twitter with developers of Brave Browser and a member of the Chromium Security Team I was sent a link to a commit: Rework os_crypt on Windows to not always need access to DPAPI which shows the exact changes made to Chromium (note: you’ll need an understanding of basic programming concepts and C++ to read this commit).
I don’t think the protection scope was intentionally changed but I could be wrong…
If the protection scope was not changed (or not intentionally changed), why did DPAPI require a CurrentUser scope to decrypt data previously but now the LocalMachine scope is used? I do not see anything in that commit which would indicate an intentional change. Implementation details are tricky and I am not a C++ programmer so I could be reading the changes wrong. (Searches with Ctrl+F of the commit for terms such as “current”, “user”, “local”, “machine” didn’t find anything of interest). It’s unclear why it worked the way it did before and I’m still looking for answers.
Further areas of research…
My BraveCookieReaderDemo was only the start of my research. My next steps include the following:
- Setup a Virtual Machine with two restricted users running Chromium 79. Take the profiles and attempt to decrypt each other’s data through Windows Data Protection API. Record the testing and results.
- Setup a Virtual Machine with two restricted users running Chromium 80. Take the profiles and attempt to decrypt each other’s data through Windows Data Protection API.
- Compare differences between cookie and password encryption, also compare when a Google account is vs is not active. Passwords have different treatment and might not have the same issues.
- Put together public code demos that demonstrate risks with encrypted cookies and passwords.