Introducing: The Google Chrome Password Recovery Tool

Today, I wanted to backup all my passwords stored in Google Chrome. I thought that would be an easy task, but it turns out, that this is not supported, at least as far as I can tell. There is an option to view the shared passwords one-by-one, but that was not really an option for me.

So, I decided to write a small program to extract the passwords from Chrome. Since Chrome (or Chromium, to be exact), is open source, I pulled the source from http://dev.chromium.org/getting-involved, compiled it, and starting looking around trying to figure out how passwords are stored. The setup and build experience was much nicer than what I have tried with other open source projects I have looked at; there are detailed build instructions with only a few steps available, and after setting up, it just works, in a Visual Studio 2008 solution. A full recompile does take some time however (45 minutes on my machine).

I quickly found out that Chrome stores most of its user and configuration data in small SQLite databases stored on disk in the AppData/Local/Google/Chrome/User Data directory. So, reading the data was no problem after grabbing a copy of the ADO .NET Provider for SQLite, as well as the sqlite3.dll binary from http://www.sqlite.org/. The data I was after (user names and passwords) is stored in the file named Web Data. This contains a table named logins, which contains the URL for which the login is valid, some details about the html form where the password has been used (in order to allow Chrome to auto-fill password boxes for you), and the username and password. It also contains a "preferred" and "blacklisted_by_user" column.

Decrypting the passwords

The passwords is, obviously for security reasons, not stored in plain text. Rather, they are encrypted, so I needed to figure out how they are encrypted and how to decrypt them. The answer lies in the Chromium source, where the Encryptor class contains the following method:

bool Encryptor::EncryptString(const std::string& plaintext,
                              std::string* ciphertext) {
  DATA_BLOB input;
  input.pbData = const_cast<BYTE*>(
    reinterpret_cast<const BYTE*>(plaintext.data()));
  input.cbData = static_cast<DWORD>(plaintext.length());

  DATA_BLOB output;
  BOOL result = CryptProtectData(&input, L"", NULL, NULL, NULL,
                                 0, &output);
  if (!result)
    return false;

  // this does a copy
  ciphertext->assign(reinterpret_cast<std::string::value_type*>(output.pbData),
                     output.cbData);

  LocalFree(output.pbData);
  return true;
}

As it turns out, the Windows Data Protection (DPAPI) is used to encrypt the data, namely the CryptProtectData function as shown above. Therefore, I can relatively easy decrypt the data, using the CryptUnprotectData function, as long as I do not try to decrypt the password of other users - the DPAPI encrypts with a key based on the current user's login credentials. I first tried to do the decrypting in C# using P/Invoke the the CryptUnprotect function, but for some reason, I could not get that to work. I kept getting a credentials dialog from Windows when trying it, which is not what i want. Luckily, after googling a bit, I found out that there already exist a managed wrapper for doing this, namely the ProtectedData class. After switching to using this, there were no problems decrypting the passwords.

The password recovery tool

I wrote a tiny C# console program to dump the passwords. They can be dumped to the console (default) or to an XML file. Running the program without parameters will try to dump all the passwords to the console. You might need to have Chrome closed while doing this. Run the program with the -help switch to display a short usage information message.

I am including the program for download here - both in a precompiled form and the C# source. It requires .NET Framework 3.5. The program as well as it's source is free for use non-commercially and is provided without any warranty or obligations for me, neither explicit or implied. It probably won't kill your cat, but don't come to me crying about it if it does ;-). If you wish to use the source or derivate thereof in a commercial product, contact me for permission first.

Download:

What is missing ?
It would be nice to have an option to import the exported passwords into a new Chrome installation on another computer. I am considering adding it, but don't really need it at this time. It should be relatively easy - if you happen to develop the feature based on my work, please email me the source.