Rot256 : Cryptography & Other Random Bits.

The security of the "Pass" password manager

Pass

What is Pass?

What is “Pass; the standard unix password manager”?

Password management should be simple and follow Unix philosophy. With pass, each password lives inside of a gpg encrypted file whose filename is the title of the website or resource that requires the password. These encrypted files may be organized into meaningful folder hierarchies, copied from computer to computer, and, in general, manipulated using standard command line file management utilities.

https://www.passwordstore.org/

The Pass password manager is often recommended, particularly on the more “tech-savvy” parts of the internet (e.g. Hacker News [1] [2] [3], /r/crypto, /r/netsec, “Netsec/Crypto twitter”). This is not surprising: Pass requires that its user has some grasp of PGP, as a result relatively few people use Pass, however those that do are necessarily “tech-savvy”.

But does the use of public key encryption (PGP) in the way that it is applied in “Pass” give rise to a “good” password manager? In this post I would like to argue that “Pass” has a number of of anti-features. I call them “anti-features” because they cannot really be classified as vulnerabilities. A vulnerability necessitates a (semi-formal) notion of security (which is violated) and it is not abundantly clear to me what security users expect from their password managers…

What do we expect?

Before we look at Pass, let us start by getting a rough idea about what we expect a password manager to accomplish in the presence of an adversary (with varying degrees of power). There are broadly two classes of adversaries that seem to apply:

Passive Security / Passive Adversary

Passive Security (informally): “privacy” is ensured when the adversary can only read the encrypted contents.

Here the informal weasel-word “privacy” covers a wide variety of security notions, e.g.

Clearly we expect that people might be able to read the encrypted state of your password manager: otherwise we might as well not encrypt at all.

Passive adversaries can be further subdivided by considering e.g. snapshot adversaries which only receive a single instance of the encrypted contents, vs, adversaries who can observe the entire history of the encrypted contents.

Active Security / Active Adversary

Active Security (informally): The adversary cannot violate “privacy” or modify entries, even when allowed to tamper with the encrypted password vault contents.

A desirable property is that the adversary cannot manipulate or reveal your passwords, even if he is allowed to modify the encrypted contents. Here there is also a variety of different properties one can strive to achieve:

I believe that considering active adversaries is reasonable and that most users implicitly assume some protection against active adversaries: most users back up their password vault with some third party, e.g. Github, Gitlab, Google Drive or Dropbox. These parties may modify the contents bestowed to them at will without allowing the user to detect the modification (the exception being e.g. signed commits). Hence if e.g. you store your “Pass” directory in e.g. Dropbox, you rely on active security.

Further justification for considering active security is the fact that qtpass (a pass front-end) supports loading passwords over WebDAV and that gopass is touting itself as “git by default”. Clearly some users expect to store their encrypted passwords on servers on the internet (a place of notorious mischief).

The Trouble

So let us look at some of these “anti-features” of Pass, starting roughly with the most obvious ones:

No Service Privacy

Since the file names are not encrypted in Pass a passive adversary can read the directory structure to learn which services you have accounts on.

Passive Attack:

Read the directory structure of the password vault.

Leaks Changes

Furthermore the adversary can learn when (and which) entries are created / deleted / modified. This problem is particularly pronounced when the Pass directory is stored in e.g. Git, where the entire history is stored indefinitely.

Passive Attack:

Observe the updates made to the encrypted files in the directory over time (or download the VCS history).

No Post-Quantum security

If sufficiently large quantum computers are ever constructed, RSA (and all other public key crypto systems supported by PGP) will be broken by Shor’s algorithm.

Passive Attack:

  1. Store the victims encrypted password vault.
  2. Wait for quantum computers to become available.
  3. Decrypt his password vault with ease.

This is in contrast to symmetric encryption which suffer a square speedup from the generic Grovers algorithm (although future bespoke quantum algorithms could conceivable break particular symmetric constructions in polynomial time). In other words: choosing e.g. a uniformly random 40 character alpha-numeric Keepass password is sufficient for > 100 bits of post-quantum security with AES-256, while “Pass” will be utterly broken regardless of what password you chose to encrypt your PGP private key.

Do you really need the features provided by asymmetric crypto in Pass? The primary feature provided by the use of public key crypto in Pass is the ability to add credentials to the password store without needing to unlocking the store.

PGP: A 90ties horror show.

PGP was concocted in the 90ties and it shows. For starters there is no proof that PGP containers are IND-CCA. Roughly speaking, IND-CCA means that given an encrypted message it is impossible to modify the encrypted message such that the resulting ciphertext successfully decrypts to a different message than the original plaintext. In fact in the last 20 years, there has been practical chosen-ciphertext attacks against the PGP standard and implementations:

The retort from the “PGP community” is usually some tirade about the impracticality of the attacks in practical scenarios. However the main take-away is that PGP is 90ties ad-hoc crypto (cryptography without even the semblance of a security proof), that you should only use if you have no other choice. For a more in-depth post on the maladies of PGP see What’s the matter with PGP?.

So what happens to Pass if we assume that PGP containers are completely malleable?

Active Attack:

If we assume that an active adversary can modify PGP encrypted message at will (worst case but still IND-CPA scenario), numerous things break e.g. storing private keys in Pass would allow the adversary to learn the private key if the user authenticates against him (e.g. SSH into a compromised server), by setting all but a few bits of the key to a known constant, then recovering the unknown bits by brute force.

Sure PGP is not yet known to be this broken. On the other hand: it is known to not have the cryptographic property (IND-CCA) that ensures that this will never happen. This is not an architectural problem of Pass and can simply be avoided by using better crypto.

No binding between keys/values.

Pass provides no cryptographically binding between keys (services / domains) and values (passwords / cryptographic keys). This is catastrophic if you consider active adversaries who may compromise one of the services (malicious-site.com below) used by the victim. Consider the example where the victim has an account on “malicious-site.com” and her SSH private key stored in “Pass”. The .password-store directory might look something like this:

.
|-- Personal
|   |
|   |-- malicious-site.com
|
|-- Work
    |
    |-- id_ed25519

And the attack proceeds as follows:

Active Attack:

  1. Adversary replaces the contents of ./Personal/malicious-site.com with the contents of ./Work/id_ed25519
  2. Victim decrypts ./Personal/malicious-site.com and the decrypted contents is placed in her clipboard automatically.
  3. Victim logs into malicious-site.com.

The victim just uploaded her work SSH private key to malicious-site.com

The SSH private key example can of course be extended to recover any value inside the vault (e.g. passwords for other services) in the scenario above.

No authentication of values

Since Pass uses PGP, it is reasonable to assume that the adversary knows the public key used. This allows her to replace the password ciphertexts (unknown plaintext) with a ciphertext which has a known plaintext. This is also potentially a problem and can e.g. be used to deanonymize people:

Active Attack

  1. Adversary picks a random string rnd
  2. Adversary computes ct = Enc(pk, rnd)
  3. Adversary replace malicious-site.com entry with ct
  4. The victim later logs into malicious-site.com inadvertently using rnd as password.
  5. The adversary observes that someone is logging in with the password rnd.

The adversary has now linked the victims identity on malicious-site.com to his identity on the cloud storage service (where the encrypted passwords are stored).

My passwords are emails?

If you insist on using Pass, I highly recommend using a separate PGP key just for Pass. Here is why:

If you use PGP encrypted mail I can send you one of the encrypted passwords and your email client will gleefully decrypt it and attempt to parse it. Which means that you email client can act as a decryption oracle for your password vault. Cue the full insanity of all the ways that your email client might attempt to “parse” your passwords as emails and all the potential ways this can end badly (perhaps by e.g. by exploiting CBC malleability and lax checks to inject HTML).

In the other direction: The adversary can take an encrypted email and insert it into the .password-store directory:

Active Attack

  1. The adversary intercepts an encrypted mail with ciphertext ct.
  2. Adversary replace the entry for malicious-site.com with ct.
  3. The victim later logs into malicious-site.com inadvertently sending the plaintext of the mail to malicious-site.com

A clear separation between my encrypted passwords and emails seem like a desirable feature.

What should I use instead?

If you absolutely need the CLI interface, I do not really have any good recommendations for you.

If you do not care, then I suggest KeepassXC with very conservative Argon parameters and KDBX 4.0 (which supports encrypt-then-mac), without browser integration. Why? Because it:

  1. Only uses symmetric cryptography (feasibly post-quantum secure).
  2. Encrypts every key/value pairs together into single encrypted blob which does not leak which services you use or which entries are updated.
  3. Provides symmetric IND-CCA security: by decrypting your vault, you know that who encrypted it also knew the password you used to unlock the vault.

This still leaves the issue of an adversary rolling back the entire state of your password manager (essentially a replay attack, hence IND-CCA security by itself is not sufficient). Which is an issue if e.g. the adversary wishes to recover a previously used password on a service which has subsequently been compromised:

Active Attack

  1. Copy the encrypted state of the password vault.
  2. The user updates his password.
  3. Adversary compromises “trusty-site.com” at a later point.
  4. Restore the encrypted state of the password vault to the value saved in step 1.
  5. The user decrypts the password vault and is tricked into logging in which his old password.

However, overall the attack surface and the general shenanigans is greatly reduced.

Conclusion

Is Pass broken by design?

In theory? Yes, except for the weakest meaningful security notion (secrecy only for the passwords) against the weakest possible class of adversaries (passive pre-quantum adversaries). In practice? Perhaps not, but this is not a sane way to think about security in general and there exists less-weird alternatives with better security guarantees, why not use those?

The alluring apparent simplicity of “Pass” is a result of giving up on certain notions of security and shifting the complexity to GPG. The wider security implications of the resulting construction are non-obvious: particularly because it provides very little integrity and hence security is hard to reason about in the presence of active adversaries.