How Google Chrome Stores Passwords

September 15th, 2008 by Dev Team in Uncategorized

Every browser released in the last decade has some sort of password management system, and Google Chrome is no different. Sift through the Chrome source code, released under the open source project Chromium, and you’ll found out how they do it.

Let’s start at the top and work our way down. Any time a password is saved, you’re first prompted with the save password bar.

Google Chrome save password prompt

In Chrome, this object is called PasswordManager. This object is responsible for a lot of stuff, but what we really care about is what happens when you click “Save Password”.

Google Chrome save password buttons

When you click the save button, it calls the following function:

void PasswordManager::SavePasswordBar::OKButtonPressed() {
form_manager is another object, PasswordFormManager, that sits between the user interface and the database. All this function does is call that object’s Save method. It then instructs the save password prompt to close. Here’s what the Save function looks like.
void PasswordFormManager::Save() {

if (IsNewLogin())

Again, pretty straight forward. The first two items will log information for debugging purposes and aren’t compiled in release mode. It then checks if it is adding a new password or updating an existing one. For the purposes of this tutorial, let’s look at adding a new password.

void PasswordFormManager::SaveAsNewLogin() {
// The new_form is being used to sign in, so it is preferred.
// new_form contains the same basic data as observed_form_ (because its the
// same form), but with the newly added credentials.


WebDataService* web_data_service =
if (!web_data_service) {
pending_credentials_.date_created = Time::Now();

Most of this function is debug code. What we care about is the call to AddLogin. The WebDataService object is responsible for meta data associated with a web page.

void WebDataService::AddLogin(const PasswordForm& form) {
GenericRequest<PasswordForm>* request =
new GenericRequest<PasswordForm>
(this, GetNextRequestHandle(), NULL, form);
(this, &WebDataService::AddLoginImpl, request));

Now we’re getting a little more complicated. Adding a password is done asynchronously and this function handles scheduling that task. It seemed to be very important that nothing interrupt Chrome’s user interface – this keeps it feeling fast and responsive. Now let’s take a look at what happens when this task is run.

void WebDataService::AddLoginImpl(
GenericRequest<PasswordForm>* request) {
if (db_ && !request->IsCancelled()) {
if (db_->AddLogin(request->GetArgument()))

We’re almost at the heart of it all. The important call here is AddLogin, so let’s dive into that.

bool WebDatabase::AddLogin(const PasswordForm& form) {
SQLStatement s;
std::string encrypted_password;
if (s.prepare(db_,
“(origin_url, action_url, username_element, username_value, “
” password_element, password_value, submit_element, “
” signon_realm, ssl_valid, preferred, date_created, “
” blacklisted_by_user, scheme) “
“VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)”) != SQLITE_OK) {
NOTREACHED() <<“Statement prepare failed”;
return false;

s.bind_string(0, form.origin.spec());
s.bind_string(1, form.action.spec());
s.bind_wstring(2, form.username_element);
s.bind_wstring(3, form.username_value);
s.bind_wstring(4, form.password_element);
Encryptor::EncryptWideString(form.password_value, &encrypted_password);
s.bind_wstring(6, form.submit_element);
s.bind_string(7, form.signon_realm);
s.bind_int(8, form.ssl_valid);
s.bind_int(9, form.preferred);
s.bind_int64(10, form.date_created.ToTimeT());
s.bind_int(11, form.blacklisted_by_user);
s.bind_int(12, form.scheme);
if (s.step() != SQLITE_DONE) {
return false;
return true;

We’ve finally reached the end of the line. This function actually builds the SQL statement for adding a new password to Chrome’s SQLite database. Of course, the password isn’t stored in plain text so Chrome has an Encryptor object responsible for encrypting the password first. Let’s take a look at that.

bool Encryptor::EncryptString(const std::string& plaintext,
std::string* ciphertext) {
DATA_BLOB input;
input.pbData = const_cast<BYTE*>(
reinterpret_cast<const BYTE*>(;
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
(output.pbData), output.cbData);

return true;

The important piece here is CryptProtectData, which is a Windows API function for encrypting data. Data encrypted with this function is pretty solid. It can only be decrypted on the same machine and by the same user that encrypted it in the first place.

So what’d we learn by investigating Chrome’s password management system? Well, we learned that Google uses SQLite as the storage mechanism for passwords and other web page related data. We also see that Google has done a great job extracting Windows specific code from the cross-platform stuff. The only Windows specific code here is the encryption function, which can easily be ported by creating a different Encryptor object for each OS.

Credits to:

3 Responses to ' How Google Chrome Stores Passwords '

Subscribe to comments with RSS or TrackBack to ' How Google Chrome Stores Passwords '.

  1. film fan said,

    on September 16th, 2008 at 3:54 am

    i keep learning about more and more little advantages and features with Chrome, with privacy, for example; now if only they would take care of it’s cookie management glitches…

  2. on October 6th, 2008 at 10:48 am

    […] take on this matter is to encrypt your passwords on the hard drive, but it doesn’t offer you the option to protect them from prying eyes. For […]

  3. derek said,

    on August 9th, 2009 at 12:34 pm

    Thanks, exactly the information I was searching for.

Leave a reply