PfP: Pain-free Passwords security review

This is a guest post by Jane Doe, a security professional who was asked to do a security review of PfP: Pain-free Passwords. While publishing the results under her real name would have been preferable, Jane has good reasons to avoid producing content under her own name.

I reviewed the code of the Pain-free Passwords extension. It’s a stateless password manager that generates new passwords based on your master password, meaning that you don’t have to back your password database up (although, you also can import your old passwords, which do need backing up). For this kind of password managers, the most sensitive part is the password generation algorithm. Other possibly vulnerable components include those common for all password managers: autofill, storage and cloud sync.

Password list in PfP: Pain-free Passwords

Password generation

Passwords generated by a password manager have to be unpredictable. For a stateless password manager, there’s another important requirement: it should be impossible to derive the master password back from one of the generated passwords.

PfP satisfies both requirements. Its password derivation algorithm is basically scrypt(N=32768, r=8, p=1), which is an industry standard for key derivation. It generates a binary key based on your master password, website address you’ll use that password for and your login there. (You can also specify revision, in case your password has been stolen and you need a new one.) PfP then translates the binary key to text, using characters from sets you choose. The translation algorithm is designed in a way to include symbols from each of character sets you choose.

The resulting password is completely random for a person who doesn’t know your master password, so they cannot predict what passwords you will use for other websites. Your master password cannot be computed either, as scrypt is a one-way hash function.

scrypt parameters (here we’re talking about N=32768, r=8, p=1) are explained well in this article. It is recommended to use such parameters that key derivation time on the author’s computer will be around 100ms (for cases where the key is used immediately, like in PfP). I run the test on my computer and found out that my computer derives a key in 158ms (average) with the parameters PfP uses, which means it is secure enough.

With this setup, the only attack possible would be brute-forcing the master password, i. e. trying to reverse the one-way hash function, which is prohibitively expensive and time-consuming (we’re talking about tens of years running very expensive computers here). So it’s highly unlikely someone would even try, a much more efficient method would be to install a keylogger on the victim’s computer.

AutoFill

PfP does a good job making sure a password for a specific website can only be filled on that website. I wasn’t able to trick it into autofilling password for one website on another.

But I have discovered a couple of non-security bugs. One of them caused autofill to fail in iframes in Chrome, the other one caused PfP to wait for the submit to appear forever, running code in an endless loop.

Storage

PfP uses the API browsers provide to extensions to store passwords (localStorage for the online version). It encrypts everything using AES256-GCM, using a 256-bit encryption key being derived from your master password and salt. Salt is a random 16-byte value stored together with the encrypted data. It is needed to protect you from rainbow table attacks.

Another thing important for encryption is using random initialization vectors. PfP generates 12 random bytes and stores them concatenated with the ciphertexts.

PfP uses HMAC-SHA256 digests for database keys. It needs the keys for retrieving encrypted data to be deterministic, so it cannot use random values. Just SHA256 hashes can be broken (the passwords could be computed based on them in that case), while using scrypt for each action involving storage is expensive performance-wise. With a random HMAC secret being stored encrypted (with a preset database key), it is completely impossible to calculate the password info only having a HMAC digest.

As wih password generation, there’s one way to break such encryption: brute force, which isn’t viable.

Cloud sync

PfP allows storing data in Dropbox, Google Drive or remoteStorage. It uses the same encryption model as in local storage with clouds. (Salt value has to be the same across all synced instances, so when a new PfP instance connects to a non-empty cloud storage, it re-encrypts local data to use the salt value saved in cloud.)

In addition to that, PfP signs all cloud-saved data using HMAC, with another secret value, stored encrypted in the cloud. This means that if the cloud provider changes PfP data, the extension will detect it and produce an error.

So, there’s no way the cloud provider can tamper with stored data, as it would be easily detectable, nor it can see your passwords, as they’re encrypted. The only thing a malicious cloud provider could do is delete your files or modify them in a way that would result in sync failure.

HTTPS protocol is used for communicating with the cloud providers. Received data is parsed using JSON.parse() or simple string manipulation functions (e. g. for parsing HTTP headers). This way, no remote code execution attacks are possible.

User interface

PfP code doesn’t contain any common mistakes, like listening to keyboard events from a webpage context or otherwise executing sensitive code in an untrusted environment.

I found one minor security vulnerability, namely external links with a target="_blank" attribute (only used in the “online” PfP version on its website). Such links should have a rel="noopener" attribute to prevent attacks where the tab opened after clicking on one of those links could be able to redirect the original tab to a different URL. (A more detailed description can be found here.) It was fixed in PfP 2.2.2 (it is a web-only release, as the issue didn’t affect browser extension users).

Comments

  • NullSense

    Hey! Interesting posts on security & pw managers. Would you do a review of Bitwarden? I have been using it for a few years now and am really happy with it.

    Wladimir Palant

    People keep asking me about this one – maybe at some point. I looked briefly at its codebase some time ago, and I saw quite a few questionable choices. Unfortunately, figuring out whether these are exploitable requires considerable effort.

  • NikitaIT

    Have you seen https://keeweb.info/ using argon2 and KeePass DB? What can you say about this?

    Wladimir Palant

    This blog article wasn’t written by me. But if you ask my opinion: yes, KeePass is generally solid technology if you stay clear of legacy databases. Presumably, same is true for KeeWeb even though I’d strongly recommend a downloaded client rather than the online web application (for the same reasons I discourage the PfP web client). The main issue with these applications is usability however. By itself, they are rather inconvenient. To make filling in passwords more convenient, a range of third-party solutions exist – with questionable security.

  • Ray

    Hi Wladimir, just saw the news about PfP being discontinued. Do you plan on doing a post-mortem article about this?

    Is it simply not having the bandwidth to maintain PfP? Or you see something in KeepassXC that is better than PfP?

    Wladimir Palant

    Yes, I plan to publish an article on it. And – yes, it’s simply about the effort required to develop a good password manager.

    I don’t consider KeePassXC better than PfP. It has a solid development community however. And with some luck I’ll be able to contribute the missing functionality.