Compare commits

...

3 Commits

Author SHA1 Message Date
Johannes Marbach 5316255985 Fix heading levels 4 weeks ago
Johannes Marbach b4bdf44c49 Fix typos 4 weeks ago
Johannes Marbach f78d36b899 Incorporate feedback 4 weeks ago

@ -1,13 +1,36 @@
# MSC4114: Matrix as a password manager
Password managers are used in abundance in both the personal and corporate
space to securely and conveniently store and share secrets. This proposal
outlines a scheme for storing a hierarchy of secrets in Matrix by borrowing
from standard concepts such as rooms and spaces.
space to securely and conveniently store and share secrets. A whole ecosystem
of apps and services has sprouted and users have come to trust them for
their advanced security features.
Matrix, in turn, is a generalized protocol for securely storing and exchanging
data in a federated network, the primary use case being encrypted messaging.
This proposal outlines a scheme for extending Matrix to act as a password
manager by borrowing from built-in concepts such as encryption, rooms and
spaces. The underlying premise of this is that if it's secure enough to handle
personal communication, it should be secure enough to store passwords. Or put
another way, if you cannot trust Matrix to store your passwords, how can you
trust it to store your potentially equally sensitive private communication? The
truthiness of this assumption is underpinned later in this proposal by
comparing the cryptographic primitives used in Matrix and Bitwarden.
## Proposal
### Secret hierarchy
On a high level, vaults and secrets are represented as encrypted spaces and
rooms, respectively. Both use the existing encryption mechanics without
introducing further layers.
Home servers that support storing secrets can generally also allow messaging
via normal rooms and spaces. However, from a client perspective, it's
undesirable to have vaults constantly unlocked. Therefore, the messaging
capabilities should only be used for things like service announcements
and not for general chatting.
Federation is explicitly excluded from this proposal to reduce its scope.
### Vaults as spaces / secrets as rooms
Two new room types `m.vault` and `m.vault.secret` are introduced. Vault-rooms
work similar to [spaces] and can group other vault-rooms or secret-rooms.
@ -26,7 +49,7 @@ sharing.
To include a secret (or another vault) in a vault, an `m.vault.child` state
event is introduced. The state key of the event is the room ID of the secret
(or other vault) to include. In `content`, the event has a single field `via`
(or vault) to include. In `content`, the event has a single field `via`
that lists servers to try and join through.
```
@ -47,11 +70,11 @@ No rooms other than those of type `m.vault` and `m.vault.secret` are allowed to
be stored in `m.vault.child` events.
Unlike with spaces, there is no corresponding `m.vault.parent` event, meaning a
vault or secret does not know which parent vaults contain it. While in spaces
this backlink exists to aid discoverability, this feature appears unessential
for secret hierarchies.
vault or secret does not know which parent vaults it is contained in. While
this backlink exists in spaces to aid discoverability, this feature appears
unessential for secret hierarchies.
### Storing secrets
### Secret events
To store secrets, a new room event type `m.secret` is introduced. Building upon
[MSC1767], secret-events contain a single `m.secret.sections` content block that
@ -78,7 +101,7 @@ Fields in turn have the following properties:
- `value` The content stored (required). For fields of type `date`, this is an
integer, otherwise a string.
- `conceal` Display hint indicating whether or not clients should obscure the value
by default (optional). Defaults to `false` for all field type except `password`.
by default (optional). Defaults to `false` for all field types except `password`.
```
{
@ -104,10 +127,10 @@ Fields in turn have the following properties:
}
```
Clients can choose to use the order of sections and fields in the event for
Clients may choose to use the order of sections and fields in the event for
sorting data in the UI but are not required to do so.
`m.secret` events are not meant to be used in rooms other than those of type
`m.secret` events are not allowed to be used in rooms other than those of type
`m.vault.secret` and should always be encrypted.
When updating secrets, clients should use [event replacements] which allows
@ -129,11 +152,81 @@ once [MSC3414] lands. While exposing vault and secret names is not considered a
security concern by other password managers such as [pass], it can still be a
privacy concern. Therefore, clients should warn users appropriately in the meantime.
## Potential issues
### Matrix vs. Bitwarden
#### Login
[Bitwarden's protocol] uses key stretching on several levels to make it harder
to brute-force a login. The client uses PBKDF2 with 600,000 iterations to
derive a 256-bit master key from the account password and email. The account
password and master key are then turned into a master password hash using
PBKDF-SHA256. This hash is sent to the server where it is hashed again using
PBKDF2-SHA256 with 600,000 iterations before verifying the login.
Matrix, on the other hand, doesn't mandate the use of key derivation functions
during login and instead makes this aspect an implementation detail. Synapse,
for instance, uses [bcrypt] with a default of [12 iterations][^1] for
`m.login.password` flows. Keycloak, as an exemplary OIDC provider, uses
[PBKDF2-SHA512 with 210,000 iterations] by default.
It's important to note here that login to a Matrix account doesn't actually
give access to the Megolm keys required to decrypt historic events. The keys
have to either be shared from another existing device or retrieved from the
server-side key backup. The latter is encrypted using AES-256 CBC where the
[256-bit curve25519 private key] is commonly stored in 4S. The key that
unlocks 4S itself can be derived from a passphrase using PBKDF2 where the
number of iterations is [configurable].
In summary, Matrix can be configured to provide a similar level of brute-force
login protection as Bitwarden using key stretching on multiple levels.
#### Encryption
Bitwarden uses a single 512-bit key, consisting of a 256-bit encryption key
and a 256-bit MAC key, to symmetrically encrypt all vault items using
[AES-256 CBC]. To protect this key, it is encrypted with the HKDF-stretched
master key using AES-256 and a random 128-bit initialization vector. The
encrypted key is then synced across clients via the server.
Matrix, on the other hand, employs [Megolm] which also uses AES-256 CBC for
symmetric encryption but obtains the key differently. Megolm is session-based
where each session uses a ratchet that is initialized with 1024-bit
cryptographically secure random data. The ratchet is wound forward through
hashing on each encrypted message and the symmetric encryption key is derived
by hashing the ratchet value. Additionally Megaolm uses Ed25519 to provide
message authenticity through signatures. Megolm keys are synced among clients
via either key requests in encrypted to-device messages or the server-side key
backup.
To sum up, the main difference here is that Bitwarden uses a single symmetric
key to encrypt everything whereas Matrix uses per-event keys.
#### Sharing
Bitwarden only allows sharing vault items through organizations. Like users,
organizations have a single symmetric key that is used to encrypt all vault
items. The symmetric key is encrypted with the public part of the organization
creator's RSA key and synced across the creator's devices via Bitwarden's
servers. Each user's RSA key pair is generated upon account creation using
RSA-2048 which, interestingly, is below what the NSA [recommends]. When another
user is invited into the organization, the inviter encrypts the symmetric key
with the invitee's public RSA key and shares it via Bitwarden's servers.
Bitwarden doesn't appear to detail what happens when a user leaves an
organization.
In Matrix, users are invited into rooms to share future encrypted events with
them but clients don't currently share keys for past events with other users.
For rooms that use the `shared` history visibility setting, the accepted
[MSC3061] defines a way for the inviter to share keys for past messages with
the invitee even without a key share request. The sharing is done via
[`m.forwarded_room_key`] to-device messages that are encrypted using Olm which
uses Curve25519.
In summary, there are no material differences here other than the RSA vs.
Curve25519 discrepancy and the already known fact that Bitwarden relies on a
single key while Matrix uses per-message keys.
When sharing _and_ federating, secrets can end up being stored on different home
servers over time. However, federation is probably not a desirable feature of
password managers anyway.
## Potential issues
When not sharing, UTDs on encrypted secrets would be fatal and result in loss
of access to the secret. Clients might be able to mitigate this by offering
@ -177,10 +270,23 @@ Until this proposal is accepted into the spec implementations should refer to:
None.
[12 iterations]: https://github.com/element-hq/synapse/blob/develop/synapse/config/registration.py?rgh-link-date=2024-03-07T20%3A31%3A39Z#L79
[256-bit curve25519 private key]: https://spec.matrix.org/v1.10/client-server-api/#recovery-key
[AES-256 CBC]: https://bitwarden.com/help/what-encryption-is-used
[Bitwarden's protocol]: https://bitwarden.com/help/bitwarden-security-white-paper/
[bcrypt]: https://github.com/element-hq/synapse/blob/develop/synapse/handlers/auth.py?rgh-link-date=2024-03-07T20%3A31%3A39Z#L1642
[configurable]: https://spec.matrix.org/v1.10/client-server-api/#deriving-keys-from-passphrases
[event replacements]: https://spec.matrix.org/latest/client-server-api/#event-replacements
[join rule]: https://spec.matrix.org/v1.3/client-server-api/#mroomjoin_rules
[Megolm]: https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/megolm.md
[MSC1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
[MSC3061]: https://github.com/matrix-org/matrix-spec-proposals/pull/3061
[MSC3414]: https://github.com/matrix-org/matrix-spec-proposals/pull/3414
[`m.forwarded_room_key`]: https://spec.matrix.org/v1.10/client-server-api/#mforwarded_room_key
[pass]: https://www.passwordstore.org/
[PBKDF2-SHA512 with 210,000 iterations]: https://www.keycloak.org/docs/latest/server_admin/#hashing-iterations
[recommends]: https://en.wikipedia.org/wiki/Commercial_National_Security_Algorithm_Suite
[redactions]: https://spec.matrix.org/latest/client-server-api/#redactions
[spaces]: https://spec.matrix.org/v1.3/client-server-api/#spaces
[^1]: For a high-level comparison of bcrypt and PBKDF2 performance, see https://security.stackexchange.com/questions/4781/do-any-security-experts-recommend-bcrypt-for-password-storage/6415#6415.

Loading…
Cancel
Save