Title: The quest for a family-friendly password manager
Date: 2023-01-02 16:30

With LastPass [making a habit of getting
pwned](https://en.wikipedia.org/wiki/LastPass#Security_incidents) and
[generally sucking](https://infosec.exchange/@epixoip/109585049354200263), I
started to look for a proper™ cloud-based password manager that I could
recommend to friends and family.

## Requirements

1. A non-lame security level, by a entity that won't crash and
   burn in 3 months, and whose sole interest is keeping their customer's
   passwords safe: managing passwords can't be a side-hustle.
2. Compromised passwords monitoring: I don't trust people to have used
   proper passwords before, and would like to make sure that they stop doing
   this.
3. Usable in a web browser, as well as on a smartphone: anything more complex
   than "Or I can just put `azerty1234` in the password field and call it a
   day" won't do.
4. Data should be exportable.

Being open-source doesn't really matter, since supply-chain attacks are way
more likely than source-level backdooring. I don't know much about web browser
extension security, so those are off the scope this article. Firefox and Chrome
do offer passwords manager, but those won't autofill smartphone apps. Moreover,
tying all your passwords to your Google account sounds like a recipe for
disaster, given how infamous Google is for closing accounts on a whim without
any kind of possible recourse.

## Cryptographic aparté

To my disappointment (and mild horror), almost all password managers are using
[PBKDF2](https://en.wikipedia.org/wiki/PBKDF2), which is known to be
completely suboptimal to store passwords, and has been for the last 15 years,
but it's apparently the only one without abysmal performance in Javascript.
[Soatok Dreamseeker](https://soatok.com/) wrote [a great blogpost](https://soatok.blog/2022/12/29/what-we-do-in-the-etc-shadow-cryptography-with-passwords/)
on the current state of the art with regard to "cryptography with passwords" if
you want to know more about what all the cool kids are using nowadays.

Anyway, using PBKDF2 is *lame* and has been for more than a decade, but with
the proper difficulty parameters, it might still be considered ok-ish.

Here is what the [OWASP](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2) recommends:

> - PBKDF2-HMAC-SHA512: 120,000 iterations
> - PBKDF2-HMAC-SHA256: 310,000 iterations
> - PBKDF2-HMAC-SHA1: 720,000 iterations

[Sc00bz](https://twitter.com/Sc00bzT), who knows a thing or two about cracking
passwords (and about [LastPass](https://infosec.exchange/@sc00bz/109599415792124027) too),
[recommends]( https://tobtu.com/minimum-password-settings/) as of
today around two times the OWASP's values:

> - PBKDF2-HMAC-SHA512: 210,000 iterations
> - PBKDF2-HMAC-SHA256: 600,000 iterations
> - PBKDF2-HMAC-SHA1: 1,300,000 iterations

But those values are for "Password storage". For "Password-based key derivation", aka what we want here,
[Soatok](https://soatok.blog/2022/12/29/what-we-do-in-the-etc-shadow-cryptography-with-passwords/) has the following numbers:

> - PBKDF2-HMAC-SHA512: 2,100,000 iterations
> - PBKDF2-HMAC-SHA256: 6,000,000 iterations
> - PBKDF2-HMAC-SHA1: 13,000,000 iterations

But this obviously won't fly for smartphones, sigh.

## Candidates

### Bitwarden

This was my first choice, since it's [open-source](https://github.com/bitwarden)
and even has an [alternative server implementation](https://github.com/dani-garcia/vaultwarden).
It [uses PBKDF2](https://bitwarden.com/help/what-encryption-is-used/) with [AES-CBC](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_block_chaining_(CBC)):

> The default iteration count used with PBKDF2 is 100,001 iterations on the
client (client-side iteration count is configurable from your account
settings), and then an additional 100,000 iterations when stored on our servers
(for a total of 200,001 iterations by default).

Moreover,
as Vladimir Palant [said](https://palant.info/2023/01/23/bitwarden-design-flaw-server-side-iterations/#what-this-means-for-decrypting-the-data),
an attacker only has to bruteforce 100k iterations.

This means that someone with read-access to the server before the second
iterations pass only has to bruteforce 100k iterations.
There is an [issue open](https://github.com/bitwarden/server/issues/37)
(continued [here](https://community.bitwarden.com/t/encryption-suggestions-including-argon2/350))
since 2017 about moving from PBKDF2 to Argon2. Moreover, AES-CBC doesn't provide
integrity, which isn't critical here, but is still a worrying practise.

It has [various clients](https://bitwarden.com/download/), but all are written
in Typescript and running in Electron, meaning that they're equivalent to using
the web app, but absolutely worse. There is also a [command-line
interface](https://contributing.bitwarden.com/getting-started/clients/cli),
weighting 80MB, also in TypeScript, also in Electron. Amazing.

There is a bug bounty, but most reports [aren't public](https://hackerone.com/bitwarden/hacktivity)
and there are no payouts. Their
[audits](https://bitwarden.com/help/is-bitwarden-audited/) are either
compliance-related (GDPR, HIPAA, CCPA, …) or "Network Security Assessment", aka
"Run [Nessus](https://en.wikipedia.org/wiki/Nessus_(software)) and generate a
report". So nobody was ever paid to audit the codebase and make the
vulnerabilities public beside some people at Bitwarden Inc.

[edit] They [had an audit](https://bitwarden.com/images/resources/2021-bitwarden-security-assessment-report.pdf) in 2021,
but its scope is unclear: it seems that only the web interface of the server
was audited?

[edit] As for February 2023, Bitwarden [now
supports](https://bitwarden.com/help/releasenotes/#202320) argon2id,
and bumped the number of PBKDF2 iterations from 100k to 600k.

### 1Password

I think that it's LastPass' direct competitor. According to their
[whitepaper]( https://1passwordstatic.com/files/security/1password-white-paper.pdf ),
they're using AES-256-GCM and PBKDF2-HMAC-SHA256 with 100,000 iterations.
Interestingly, to protect against weak passwords, there is also a
device-stored [secret key](https://support.1password.com/secret-key-security/)
mixed with the password. This is a neat trick excusing the low number of
iterations. This adds complexity and I don't trust
people to not lose it; but odds are that everyone has a phone and a computer,
so this could act as a *backup*.

They're [using](https://support.1password.com/secure-remote-password/) [SRP](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol)
for authentication, which is not only [known to be "meh" since 2008](https://blog.cryptographyengineering.com/should-you-use-srp/)
and [deprecated since 2021](https://tobtu.com/blog/2021/10/srp-is-now-deprecated/),
but also kinda useless except if the TLS connection to 1password.com is
compromised. In this case, odds are that you've already lost, but why not.

They have a [substantial bug bounty](https://bugcrowd.com/agilebits) up to
USD 1,000,000, but the reports [aren't public](https://bugcrowd.com/agilebits/crowdstream?filter=all).
They're also doing [regular pentests](https://support.1password.com/security-assessments/)
of their various components by reputable firms.

### Dashlane

Dash is the only one [using]( https://www.dashlane.com/download/whitepaper-en.pdf)
[Argon2d](https://github.com/P-H-C/phc-winner-argon2/blob/master/README.md),
the winner of the [Password Hashing
Competition](https://www.password-hashing.net) held in 2015.

Unfortunately, their [choice of parameters]( https://www.dashlane.com/resources/dashlane-zero-knowledge-security) is 
on the low side:

> We use Argon2d, by default, with the following parameters: iterations = 3,
memory = 32Mo, parallelization = 2  We also support PBKDF2-SHA2 with 200,000
iterations. Then, the data is (en|de)crypted using AES CBC-HMAC mode.

AES CBC-HMAC isn't a thing, what they're doing is AES-256-CBC then HMAC-SHA256
(and not [CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC)), which is perfectly acceptable,
albeit using the same key for AES and HMAC feels shaky: an authenticated mode
should be used like
[AES-GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode), or another key
derivation to produce two subkeys, instead of using the same key for two
different purposes.

The intern who wrote their [whitepaper](https://www.dashlane.com/resources/dashlane-zero-knowledge-security) had a confused
understanding of how https works: [OCSP](https://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol)
doesn't replace trust stores, key exchanges are more complex than "the client encrypts a random number with the server’s public key and sends it to
the server, the server decrypts this number, and both sides use this number to generate a
symmetric key, used to encrypt and decrypt data.", …

Worryingly, their "[benchmark of attempts to decrypt AES files](https://www.dashlane.com/resources/dashlane-zero-knowledge-security)"
is done on a "4 cores Xeon 1.87GHz", which doesn't make sense: cracking a password doesn't mean going
through the whole keyspace of alphanumeric characters of a fixed length,
and nobody uses CPU to crack passwords, let alone a 4 cores one. I would expect
a firm in the business of protecting passwords to be up to date with the
current state of the art of password cracking.

They have a bug bounty with [payouts](https://hackerone.com/dashlane?view_policy=true) up to USD 5,000
and [no public reports](https://hackerone.com/dashlane/hacktivity). The gpg key
that should be used to contact them is an RSA one of 1024 bits (worryingly
small in 2023), and belongs to someone called "anish".

### NordPass

Being from the spammy NordVPN people, I wouldn't put much trust in it.
Their handwavy [whitepaper](https://nordpass.com/nordpass-business-whitepaper.pdf)
says that they're using:

- Argon2id, but without specifying the parameters, not why they chose this
	particular variant over another variant like Argon2d.
- [XChaCha20-Poly1305](https://en.wikipedia.org/wiki/ChaCha20-Poly1305#XChaCha20-Poly1305_%E2%80%93_extended_nonce_variant)
	for encryption instead of AES because "the performance of the latter heavily
	relies on the hardware features (such as the AES instruction set for
	x86 processors), which are rarely available on mobile devices".
	The whitepaper says they're using [NaCl](https://nacl.cr.yp.to),
	but it [doesn't provide XChaCha20](https://nacl.cr.yp.to/valid.html),
	and [XChaCha20-Poly1305-IETF](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha)
	is a draft which expired two years ago. So I thought that maybe they meant XSalsa20-Poly1305,
	which is implemented in NaCl, but apparently they're using xChaCha20
	**and** xSalsa20.

There is also a bunch of public-key cryptography going on for sharing
material that surely isn't susceptible to any kind of MITM, and
metadata are stored in clear-text. Sounds like someone wanted the *very
bestest* cryptography but didn't really understand why.

They have a [bug bounty](https://hackerone.com/nordsecurity) with payouts up to
USD 50,000 and [some reports](https://hackerone.com/nordsecurity/hacktivity) are public.

### Keeper

Their [website](https://docs.keeper.io/enterprise-guide/keeper-encryption-model)
says AES-256-GCM and PBKDF2-SHA-256 (or maybe PBKDF2-SHA-512, it's unclear) with 100,000 rounds.

> All encrypted payloads sent to the Keeper servers are additionally wrapped by
a 256-bit AES transmission key in addition to TLS, to protect against MITM
attacks. The transmission key is generated on the client device and transferred
to the server using ECIES encryption via the server's public EC key.

> A Master Password Key is derived from the Master Password using PBKDF2 and
used to unwrap the Data Key, which is then used to unwrap the Record Keys and
Folder Keys.  Record Keys are then used to decrypt the stored record
information in the vault.

> A second PBKDF2 key is generated locally and then hashed with HMAC_SHA256 to derive an authentication token.

> The vault data stored offline is AES-GCM encrypted with a 256-bit “Client
Key” that is generated randomly and protected by PBKDF2-HMAC-SHA512 with up to
100,000 iterations and a random salt.

> KSI deploys TLS certificates signed by Digicert using the SHA2 algorithm, the
most secure signature algorithm currently offered by commercial certificate
authorities. SHA2 is significantly more secure than the more widely used SHA1,
which could be exploited due to mathematical weakness identified in the
algorithm. SHA2 helps protect against the issuance of counterfeit certificates
that could be used by an attacker to impersonate a website.

> On the Keeper end-user client device, when BreachWatch is activated, a
HMAC_SHA512 hash is generated based on each stored password and sent to the
server.  On the server, a second hash is created using HMAC_SHA512 via the
Hardware Security Module (HSM) using a non-exportable key.  These
Hashes-of-Hashes are compared to determine if a password has been breached.

This all sounds like bullshit/poor design resulting from a confusing threat model and terminology.

Apparently "Keeper works with NCC Group and Cybertest to perform ongoing
vulnerability testing of the browser extension platform, which includes source
code level analysis.", but the reports aren't available.
They have a [bug bounty](https://bugcrowd.com/keepersecurity)
with payouts up to USD 10,000, but there as well, [reports aren't public](https://bugcrowd.com/keepersecurity/crowdstream?filter=disclosures).

### Roboform

According to their [whitepaper](https://www.roboform.com/pdf/RoboForm_Security_White_Paper.pdf)
from 2018:

> Generation of AES encryption keys uses PBKDF2 (Password-Based Key Derivation
Function 2) algorithm with SHA-256 hash function and long random salt
(32-byte). PBKDF2 is an iterative algorithm with a sufficiently large number of
iterations (4,000 by default). A higher number of iterations provides greater protection against brute force
and dictionary attacks by not only slowing them down, but also by making
RoboForm Clients proportionally slower, especially on slow devices (Android,
iOS) or applications (RoboForm Online web site). Intentionally making a slow
algorithm is an accepted practice targeted at preventing dictionary attacks
against compromised authentication stores. This technique is called “key
strengthening” or “key stretching”.

> We recommend increasing the length of the
Master Password instead of increasing the number of iterations as, according to
some researchers, the addition of two characters to the length of the password
is roughly equivalent to multiplying the number of iterations by 1,000 yet it
does not slow down the algorithm. A combination of 10,000 iterations and a
7-letter password is already insecure and it can be brute-forced relatively
quickly, as demonstrated some time ago on one of RoboForm’s competitor
products. Only the password hash derived from Master Password is shared with
the RoboForm Server. It is computationally infeasible to recover the user’s
Master Password or the AES-256 key from that password hash due to the one-way
nature of the algorithm used to generate it.

> By nature, “Read” permission is only different from “Use” permission for the
Login RoboForm Data Objects. Without the “Read” permission, the Limited User
cannot view the contents of the Login type RoboForm Data Object. Combined
with the fact that most applications and websites mask the contents of the
password field, this option provides an additional control to conceal passwords
from the users. 

This is complete nonsensical keyword-oriented garbage. There is also MITM-by-design on the
between-users-data-sharing protocol. I haven't found how one should report
security issues to them.

## Enpass

According to [their website](https://www.enpass.io/security/), they're using 100,000 rounds of PBKDF2-HMAC-SHA512
and [SQLCipher](https://www.zetetic.net/sqlcipher/design/), which uses AES-CBC
and HMAC-SHA512 under the hood, with different derived subkeys. Albeit Enpass'
[documentation](https://support.enpass.io/docs/security-whitepaper-enpass/vault.html)
mentions HMAC-SHA1 instead of HMAC-SHA512. Their threat model is a bit weird,
with [*funky* security things](https://support.enpass.io/docs/security-whitepaper-enpass/browser_extensions.html) for their browser extensions
like:

> When a browser extension tries to connect to main Enpass App, we verify the
origin of the connection, it must be the unique identifier of our browser
extension and browser will not allow installation of any two extensions with
the same ID.

I fail to see against what this is defending.

They also have a "time-based verification code" to prevent MITM for their
[Wi-Fi Sync Server](https://support.enpass.io/docs/security-whitepaper-enpass/Wi-Fi_Sync_Server.html),
which doesn't say much nor inspire confidence.

They had [some security audits](https://www.enpass.io/security-audit-report/)
last year for their Windows App and backend,
in which we discover that their server is written in cpp but with calls to
`malloc`,
with files like `httpserver.cpp` and functions like `file_upload_cb`,
meaning that they implemented their own http stack. Interestingly, they don't
provide synchronisation: it's up to the user to use either iCloud, Dropbox,
Google Drive, OneDrive, or WebDAV, even [for businesses](https://support.enpass.io/business/kb/microsoft_365_integration_with_enpass_business.htm).

Despite the report mentioning that their CSP policy might benefit from some
tightening, it's still useless:

```
curl -s -I https://console.enpass.io | grep -i content-security-policy:
content-security-policy: default-src 'self'; font-src 'self' fonts.gstatic.com; img-src 'self' d1f8f9xcsvx3ha.cloudfront.net enpass.onfastspring.com license-enpass-io.s3.amazonaws.com https://i.ytimg.com/vi_webp/96FY_bKQGrU/mqdefault.webp data: w3.org/svg/2000; script-src 'self' 'unsafe-inline' d1f8f9xcsvx3ha.cloudfront.net;connect-src license.enpass.io enpass.onfastspring.com d1f8f9xcsvx3ha.cloudfront.net;style-src 'self' 'unsafe-inline' fonts.googleapis.com; frame-src 'self' enpass.onfastspring.com youtube.com www.youtube.com;frame-ancestors 'self'
```

They don't seem to have a bug bounty.

## Proton Pass

Yet another [product](https://proton.me/pass) from the [Proton](https://proton.me/) crew.
Given how they market themselves as paragons of [privacy and digital freedom](https://proton.me/about)
yet [routinely hand user data to cops](https://duckduckgo.com/?t=ffab&q=proton+mail+cops&ia=web), I wouldn't recommend it.

From a technical point of view, it's apparently using ["a hardened version of
the Secure Remote Password (SRP) protocol that offers stronger security
guarantees against man-in-the-middle (MITM)
attacks."](https://proton.me/blog/proton-pass-security-model), which is nice
and dandy but not that important in the context of a password manager. "The
bcrypt password hashing implementation used by Proton Pass is more robust and
secure than PBKDF2, which has led to breaches in other password managers."
While bcrypt (1999) is
[alright-ish](https://en.wikipedia.org/wiki/Bcrypt#Criticisms), bragging about
it in 2024 is a bit awkward, especially when using a [cost factor of
10](https://github.com/ProtonMail/WebClients/blob/d1a23fc2c4ab1e1632118baaee6f2531022ae4cf/packages/srp/lib/constants.ts#L27),
which is the [bare minimum recommended for legacy
systems](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#bcrypt),
and can be bruteforced around 1500H/s on a medium-end GPU.
Also, using PBKDF2 never lead to any "breaches." Encryption is done via
AES-GCM-256, providing integrity, yay.

The mobile apps and browser extensions [have been audited](https://drive.proton.me/urls/KXQV3SSGFM#bEm15I8oWA4x) by Cure35
in 2023, and they have a [bug bounty](https://proton.me/security/bug-bounty, offering up to
$10k.

I guess it's a good choice if your'e already using their products.

## Passbolt

From their
[whitepaper](https://www.passbolt.com/docs/files/security_paper.pdf):

> Passbolt clients connect to a server component written in PHP 7 and
more specifically CakePHP 4, following the Model-View-Controller (MVC)
design pattern. This server application relies on a Mariadb database, and
a caching system that can be configured to use either the local file
system or Redis. The server uses a combination of Openpgp-php library
and PHP GnuPG extension, to validate keys and perform cryptographic
operations related to the authentication.

> In practice this means the metadata such as the name, the url, the
comments, the folder it is in, the list of people who have access to the
password are not encrypted, and are stored in plaintext both on the client
and server side.

lolno.

## Conclusion

- [1Password](https://1password.com) if your friends and family are smart enough to not permanently lose their
  "secret key", and/or have multiple devices. They seems to know what
  they're doing crypto-wise with their trick to mitigate their low amount of
  derivation rounds, are spending money doing regular technical audits
  and have a significant bug bounty cash prize. I think it's the right choice
  if you want a ton of features and security.
- [Bitwarden](https://bitwarden.com/) if you prefer open-source, a small
  company, and simple things. Just make sure to [bump the number of
  iterations](https://vault.bitwarden.com/#/settings/security/security-keys).
- [Dashlane](https://www.dashlane.com) if you don't like 1Password.

Everything else is either looking shaky, lacking features that I want, or
simply absolutely horrible.
