-
Notifications
You must be signed in to change notification settings - Fork 379
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] MSC2957: Cryptographically Concealed Credentials #2957
base: old_master
Are you sure you want to change the base?
Changes from 4 commits
4f06250
6f1682b
b7b672a
bf5cda7
6a42dbc
fe27cc0
3809f43
1bd7b15
dc2fac6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,315 @@ | ||
# MSC2957: Cryptographically Concealed Credentials | ||
|
||
When logging in to Matrix using the `POST /login` endpoint, the client | ||
transmits the password to the server, so the server is able to see the user's | ||
password. It is generally expected that the server would handle the password | ||
securely, for example, only storing the password in a salted and hashed | ||
format. However a malicious server could store the user's password. If a user | ||
re-uses their password on other services, the server administrator could then | ||
use the stored password to log in to the user's other accounts. Also, this | ||
means that the user's login password should not be the same as the password | ||
that they use for [Secret | ||
Storage](https://matrix.org/docs/spec/client_server/unstable#storage). | ||
|
||
This proposal defines a way for users to authenticate without sending their | ||
password to the server. Additional goals of this proposal include: | ||
|
||
- relatively simple to implement | ||
- the data stored on the server cannot be used (apart from attacking the | ||
underlying cryptographic operations) to authenticate with the server | ||
- the user can verify that the server that they are authenticating against is | ||
the same as the server where they originally created their account | ||
- a malicious user who unsuccessfully tries to authenticate against the server | ||
does not gain any information about the user's password. For example, an | ||
attacker cannot take any of the server's responses to perform any offline | ||
computations or guesses to try to obtain the user's password. | ||
|
||
|
||
## Proposal | ||
|
||
### Protocol overview | ||
|
||
#### Notation | ||
|
||
- A Curve25519 key pair is denoted <K<sub>priv</sub>,K<sub>pub</sub>>, where | ||
K<sub>priv</sub> is the private key and K<sub>pub</sub> is the public key. | ||
- ECDH(A<sub>priv</sub>,B<sub>pub</sub>): the elliptic curve Diffie-Hellman of | ||
the private key A<sub>priv</sub> and the public key B<sub>pub</sub>. | ||
- HKDF(K, S, I, L): HKDF-SHA-256 where K is the initial key material, S is the | ||
salt, I is the info, and L is the number of bits to generate. | ||
|
||
#### Registration | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you give a less-mathematically cookbook on these (Registration & Login) flows? Like, what is the core idea that is keeping this secure? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can try to do so, though there isn't a single core idea that is keeping this secure, since different aspects provide different parts of the security. If you want a "main" part, it would probably be turning the password into a Curve25519 key pair (the authentication key), which allows the server to verify that you have the password without needing access to the password itself. Using a Curve25519 key also allows us to do more complicated operations (like combining the ephemeral keys), which provide other security properties. But yes, there is certainly room for making this less "mathematically cookbook". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we could easily list a couple of higher level goals that this MSC tries to solve, for example:
And then perhaps how each of these goals is achieved. For example the first stages on how we avoid sending the password.
This could also live besides the math at the start of each such step. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed with the earlier comments here, that a more high-level explanation would help others to digest this. For example, I eventually noticed that the proposal repeatedly uses DH key exchange followed by AES encryption to construct a secure channel within the channel. Giving the reader a heads-up that this is coming (1) makes it easier to understand what's going on when they get there and (2) gives you a place to explain why it's there and what it's doing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have added some words, which hopefully makes things a bit clearer. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's kind of a crazy suggestion, so feel free to take it or leave it. But, reading over the 2nd Bellovin and Merritt EKE paper Augmented Encrypted Key Exchange, there's a lot of similarity between that classic paper and the approach proposed here. On the one hand, duh, they're both trying to do the same thing. But I think it's deeper than that -- the two "feel" much more similar to each other than either one is to, say, SRP, right? (And fortunately all the EKE patents expired years ago, so I don't think you have anything to worry about there.) Here's the crazy part: Are they actually close enough that you could structure your protocol as a fix/update/modernization for AEKE? Then you might be able to borrow a big portion of whatever security analysis has already been done for AEKE. If you could frame it as a series of deltas, and you could show that each delta makes the new protocol strictly better than the old one, then that could save a ton of work. (And remove a ton of uncertainty.) Anyway, like I said this is kind of crazy. I'm not an expert in either protocol, so maybe I'm seeing more than is really there. |
||
|
||
When registering, the client generates an ephemeral Curve25519 key pair <C<sub>priv</sub>,C<sub>pub</sub>>, and | ||
sends to the server: | ||
|
||
- the user's desired Matrix ID | ||
- C<sub>pub</sub> | ||
|
||
The server generates its own ephemeral Curve25519 key pair | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we doing something about receiving a Curve25519 key from Malory that lies at the point of infinity like we had to for SAS verification? If so could we mention that, if there's no need for it could we mention that as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we're binding the generated keys to the public keys by including them in the HKDF info parameter. I guess I can throw something in the MITM section. |
||
<S<sub>priv</sub>,S<sub>pub</sub>>, and sends the S<sub>pub</sub> to the user. | ||
|
||
The client calculates K<sub>1</sub> = ECDH(C<sub>priv</sub>,S<sub>pub</sub>) | ||
and then calculates | ||
|
||
- K<sub>AES</sub> = HKDF(K<sub>1</sub>, "", "`encryption key|`\<Matrix ID>`|`C<sub>pub</sub>`|`S<sub>pub</sub>", 256) | ||
- K<sub>MAC</sub> = HKDF(K<sub>1</sub>, "", "`mac key|`\<Matrix ID>`|`C<sub>pub</sub>`|`S<sub>pub</sub>", 256) | ||
|
||
where \<Matrix ID> is the user's desired Matrix ID. | ||
|
||
The client then takes the user's password and generates the base key | ||
K<sub>base</sub> using PBKDF2 (K<sub>base</sub> can be used as the Secret | ||
Storage key). The client then calculates the Curve25519 private key | ||
A<sub>priv</sub> = HKDF(K<sub>base</sub>, "", "`authentication key|`\<Matrix | ||
ID>", 256), and the corresponding public key A<sub>pub</sub>. The client sends | ||
to the server, encrypted with AES-256-CBC using K<sub>AES</sub> the AES key | ||
generated above: | ||
|
||
- A<sub>pub</sub> | ||
- the PBKDF2 parameters used | ||
|
||
The ciphertext is MACed using HMAC-SHA-256 using K<sub>MAC</sub> as the key. | ||
|
||
The server stores A<sub>pub</sub> securely stores the result of | ||
K<sub>conf</sub> = HKDF(ECDH(S<sub>priv</sub>, C<sub>pub</sub>) || | ||
ECDH(S<sub>priv</sub>, A<sub>pub</sub>), "", "`confirmation key|`\<Matrix | ||
ID>`|`A<sub>pub</sub>`|`C<sub>pub</sub>`|`S<sub>pub</sub>", 16), called the | ||
confirmation key. | ||
|
||
The client calculates K<sub>conf</sub> = HKDF(ECDH(C<sub>priv</sub>, | ||
S<sub>pub</sub>) || ECDH(A<sub>priv</sub>, S<sub>pub</sub>), "", "`confirmation | ||
tag|`\<Matrix ID>`|`A<sub>pub</sub>`|`C<sub>pub</sub>`|`S<sub>pub</sub>", 16), | ||
and calculates HKDF(K<sub>conf</sub>, "", "`security check|`\<Matrix | ||
ID>`|`A<sub>priv</sub>", 3), giving a number between 0 and 7. The client then | ||
displays the emoji (or the text equivalent) from the SAS verification emoji | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how useful really is this UX? given there's a 12.5% chance of the right emoji appearing later even if things have gone wrong, what does it buy us? am worried the additional UX complexity could confuse casual users even more than usual. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since that is something people would likely write on a paper, it might be a good idea to also give the option of numbers, instead of emoji. While emoji are nice for comparing in device verification, numbers are significantly easier to write down. Also, what if you don't write down the emoji / numbers and forget them? Realistically quite a few people will do just that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Possibly. Or offer both the emoji version and the text equivalent. The idea behind using emoji was that it's something that's easier for people to recognize, as opposed to trying to remember a number. But this part is very much open for discussion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't this purpose of protecting against impersonating homeservers already served by X.509 TLS certificates, which are already verified? I am not sure a user overriding an invalid cert would care about this, either. And if so, that sounds more like something that should be addressed in UX of clients, and not on this level. Of course there is the angle of protecting against compromised CAs/roots, which is a nice improvement - but perhaps that is better adressed in how that level of PKI is handled? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In addition to protecting against compromised CAs/roots, or an attacker who is able to gain control of a valid cert somehow, it would also protect against attacks such as typosquatting. |
||
list corresponding to that number. The user remembers/records the emoji for | ||
later verification. | ||
|
||
Resetting a user's password would happen similarly, with the addition that the | ||
data in Secret Storage would need to be re-encrypted if the user is using the | ||
same password for that. | ||
|
||
#### Logging in | ||
|
||
The client generates an ephemeral Curve25519 key pair | ||
<C'<sub>priv</sub>,C'<sub>pub</sub>> and sends their Matrix ID and | ||
C'<sub>pub</sub> to the server. | ||
|
||
The server then generates its own ephemeral Curve25519 key pair | ||
<S'<sub>priv</sub>,S'<sub>pub</sub>> and calculates K'<sub>AES</sub> = HKDF(ECDH(S'<sub>priv</sub>, | ||
A<sub>pub</sub>) || ECDH(S'<sub>priv</sub>, C'<sub>pub</sub>), "", "`server | ||
encryption|`\<Matrix ID>`|`A<sub>pub</sub>`|`C'<sub>pub</sub>`|`S'<sub>pub</sub>", 256). | ||
|
||
- the PBKDF2 parameters to use, | ||
uhoreg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- S'<sub>pub</sub> | ||
- a random 32-byte nonce | ||
- K<sub>conf</sub>, encrypted with AES-256-CBC using K'<sub>AES</sub> | ||
|
||
The client performs PBKDF2 on the user's password using the given parameters to | ||
generate the base key K<sub>base</sub>. It then calculates | ||
|
||
- the Curve25519 private key A<sub>priv</sub> = HKDF(K<sub>base</sub>, "", | ||
"`authentication key|`\<Matrix ID>", 256) and the corresponding public key | ||
A<sub>pub</sub> | ||
- K'<sub>AES</sub> = HKDF(ECDH(A<sub>priv</sub>, S'<sub>pub</sub>) || | ||
ECDH(C'<sub>priv</sub>, S'<sub>pub</sub>), "", "`server encryption|`\<Matrix | ||
ID>`|`A<sub>pub</sub>`|`C'<sub>pub</sub>`|`S'<sub>pub</sub>", 256), and | ||
decrypts K<sub>conf</sub> using K'<sub>AES</sub>. | ||
- HKDF(K<sub>conf</sub>, "", "`security check|`\<Matrix ID>`|`A<sub>priv</sub>", | ||
3) | ||
|
||
The client displays the emoji (or text equivalent) from the SAS verification | ||
emoji list corresponding to the number given by the last calculation, and | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with @ara4n's earlier comment on this aspect. Allowing the attacker a 1 in 8 chance of success is generally not sufficient. Just to make sure I'm following this part correctly: The core problem here is that you need to verify the identity of the server, but you can't rely on (or don't have) the SSL/TLS layer certs, and you can't be sure that the client has anything stored locally. Like, maybe this is a new device. Right? If so, then yeah, this is a hard problem with a well known set of unsatisfying solutions. The emoji thing is like a modern version of the ASCII art that SSH used to generate. Some other ideas:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The emoji check is something that I'm not entirely committed to. It was just an interesting idea that I came up with, and wondered if it would be useful. But the emoji check does two things: 1) it gives the user a way to see if they typo'ed their password (with some reasonable-ish probability), and 2) sort-of authenticates the server. Thing 1 I would classify as nice-to-have, and thing 2 is very optional, given that the server gets fully authenticated later on. The problem with the client-generated "cert" idea is that it allows an attacker to test different passwords to see if it is the right one by seeing which one yields a successful signature/MAC, which allows an an attacker to do a login attempt and then use the result to perform an offline attack. That's the reason why I only take 3 bits (8 emoji) is that it gives some help to the user without giving too much information to an attacker. Though that number may need to be fine tuned. Or we could just scrap it if it turns out to be a not-so-great idea. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, that makes a lot of sense. If the emoji is mostly to verify the password, then some chance of failure is fine.
Yeah, any password-derived key has to come from a good password-based KDF, like bcrypt / scrypt / argon2 with properly chosen parameters. Otherwise it's wide open to attack. |
||
allows the user to check that the emoji matches the one displayed when the user | ||
registered their account. This allows the user to verify (to a degree of | ||
confidence) that they entered their password correctly, and that they are | ||
communicating with the same entity that they were communicating with when they | ||
registered. | ||
|
||
The client then calculates K<sub>2</sub> = ECDH(A<sub>priv</sub>, | ||
S'<sub>pub</sub>) || ECDH(C'<sub>priv</sub>,S'<sub>pub</sub>) and | ||
K'<sub>MAC</sub> = HKDF(K<sub>2</sub>, "", "`client MAC|`\<Matrix | ||
ID>`|`A<sub>pub</sub>`|`C'<sub>pub</sub>`|`S'<sub>pub</sub>`|`K<sub>conf</sub>", | ||
256), and sends an HMAC of the nonce using this key to the server. | ||
|
||
The server calculates | ||
|
||
- K<sub>2</sub> = ECDH(S'<sub>priv</sub>, A<sub>pub</sub>) || | ||
ECDH(S'<sub>priv</sub>,C'<sub>pub</sub>) | ||
- K'<sub>MAC</sub> = HKDF(K<sub>2</sub>, "", "`client MAC|`\<Matrix | ||
ID>`|`A<sub>pub</sub>`|`C'<sub>pub</sub>`|`S'<sub>pub</sub>`|`K<sub>conf</sub>", | ||
256) | ||
- K''<sub>MAC</sub> = HKDF(K<sub>2</sub>, "", "`server MAC|`\<Matrix | ||
ID>`|`A<sub>pub</sub>`|`C'<sub>pub</sub>`|`S'<sub>pub</sub>`|`K<sub>conf</sub>", | ||
256) | ||
|
||
The server verifies the HMAC sent by the client, which proves to the server | ||
that the client is in possession of the secret key A<sub>priv</sub>. The | ||
server then responds with an HMAC of the nonce using K''<sub>MAC</sub>, which | ||
the client can check to show that the server is in possession of the public key | ||
A<sub>pub</sub>. | ||
|
||
### Protocol details | ||
|
||
TODO: | ||
|
||
## Security characteristics | ||
|
||
### Replay attacks | ||
|
||
If an attacker tries to replay the client's messages to the server to | ||
authenticate with it, the authentication will fail since authentication depends | ||
on the randomly chosen ephemeral key and nonce which will be different for the | ||
attacker's session. | ||
|
||
### Data breach | ||
|
||
If the server's database is leaked, this could reveal A<sub>pub</sub> and | ||
K<sub>conf</sub>. | ||
|
||
An attacker could try to brute-force the user's password by trying various | ||
passwords and performing the PBKDF2 and HKDF operations to see if it yields a | ||
Curve25519 private key that matches A<sub>pub</sub>. However, PBKDF2 will slow | ||
down the attacker's attempts. This is no worse than the current practice of | ||
storing a hashed version of the user's password. This can also be made more | ||
secure by encrypting A<sub>pub</sub> using a key that is stored separately from | ||
the database, similarly to how Synapse allows specifying a "pepper" value that | ||
is used when hashing the user's password. In this way, an attacker who only | ||
has the database, and not the additional encryption key, cannot retrieve | ||
information about the user's password. | ||
|
||
If the attacker obtains A<sub>pub</sub> and K<sub>conf</sub>, they can | ||
impersonate the server to the user. Again, this can be partially mitigated by | ||
encrypting K<sub>conf</sub> in addition to A<sub>pub</sub> using a key that is | ||
stored separately from the database. | ||
|
||
Since the server does not know the private key A<sub>priv</sub>, the attacker | ||
cannot use the data stored on the server to authenticate as the given user | ||
short of attacking Curve25519 to obtain A<sub>priv</sub> from A<sub>pub</sub>. | ||
|
||
### Deniability | ||
|
||
Even though the protocol allows the server to authenticate the user, it cannot | ||
prove to a third party that the user authenticated with it, even if it produces | ||
a full transcript of the authentication process. All information contained in | ||
the client's requests is either known to the server or could be created by the | ||
server, so the server cannot prove that the requests were created by the user | ||
and not fabricated by the server. | ||
|
||
### Offline computation | ||
|
||
If an attacker initiates a login attempt, the server does not reveal any | ||
information that would help the attacker determine the user's password. The | ||
server only reveals: the PBKDF2 parameters to use (which should be viewed as | ||
public information, and do not give any information about the password), | ||
S'<sub>pub</sub> and a random 32-byte nonce (which are single-use and are not | ||
related to the user's password), and an encrypted version of K<sub>conf</sub>. | ||
|
||
If the attacker knows K<sub>conf</sub>, they could try to brute-force the | ||
user's password until they can decrypt the encrypted version of | ||
K<sub>conf</sub> to obtain the known value of K<sub>conf</sub>. However, | ||
K<sub>conf</sub> is only 16 bits long, so there may be multiple passwords that | ||
can be result in its correct decryption. Also, if the attacker knows | ||
uhoreg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
K<sub>conf</sub>, they would most likely also know A<sub>pub</sub>, which would | ||
already allow them to try to brute-force the user's password, so in this case, | ||
the attacker does not gain any information by attempting to log in. Note that | ||
in this case, it is important that the encryption of K<sub>conf</sub> is done | ||
in an unauthenticated manner to ensure that an attacker is not given any | ||
information about whether or not they have guessed the right decryption key. | ||
|
||
It should be noted that an attacker who shoulder-surfs when the user registers | ||
or logs in will be able to see the emoji security check displayed to the user. | ||
The attacker may then use this to reduce the search space when trying | ||
passwords. Since there are eight possible emoji, this reduces the search space | ||
by a factor of 8, which can be compensated for by the user adding an extra | ||
character to their password. As well, the attacker still needs to test each | ||
password by submitting requests to the server, and so can be rate-limited by | ||
the server. Since the emoji security check provides some feedback to the user | ||
on whether they mistyped their password (a mistyped password would have a 7/8 | ||
chance of displaying the wrong emoji), servers can more aggressively rate-limit | ||
login attempts when using this method. Clients could also make the emoji | ||
security check optional so that users can disable it when they are in a | ||
situation where shoulder-surfing is likely. | ||
|
||
### Man-in-the-middle attacks | ||
|
||
An attacker who is able to eavesdrop on the protocol messages could gain | ||
information (for example, A<sub>pub</sub>, if they eavesdrop during the user's | ||
registration) that would allow them to brute-force the user's password. Since | ||
the sensitive data is encrypted using a key produced by an ECDH, it is not | ||
enough for the attacker to be a passive eavesdropper; they would need to be an | ||
active man-in-the-middle. | ||
|
||
TODO: ... | ||
|
||
### Phishing | ||
|
||
TODO: ... | ||
|
||
### ... | ||
|
||
## Potential issues | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how does password reset work? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be similar to registration. Though of course if you're using the same password for 4S, you'd also need to re-encrypt all your 4S secrets. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In order to be able to re-encrypt SSSS secrets you have to have them unencrypted, though. If you use "resent password" you typically don't have your password, and thus can't decrypt them. Meaning all your secret store is effectively lost. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right. I was thinking password changing rather than password reset. For password changing, you can re-encrypt. For password reset, you'd have to re-create the SSSS secrets, cross-signing keys, etc. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what i was more getting at is: how do you recover your account if you forget your password? it feels like a recovery code could work - could we just give the user their private key derived from the password to store offline as a way to get back in if they forget their human password? |
||
|
||
This proposal cannot be used by users who log in using SSO, or whose passwords | ||
are managed by an external system. | ||
|
||
... | ||
|
||
## Alternatives | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe compare how this is better than just having the client hash the password w/ a salt (from the server) and sending the hash to the server, and the server treats the hash as a password and hashes the hash in its db? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I'm understanding what you're suggesting, I think one main difference is that it would be open to replay attacks. i.e. if someone listens in on your login attempt, they'll see your hashed password, and they can then use that to log in as you. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, if I understand your proposal, it is somewhat similar to parts of SCRAM. In SCRAM, the client does PBKDF2 followed by HMAC to generate a |
||
|
||
TODO: compare with various PAKEs (e.g. SRP, OPAQUE) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it would really help to see some discussion here. How is the problem here different from the problem solved by PAKEs? And why is a PAKE not sufficient here? Otherwise it's tempting to say, just grab the current best PAKE (is that OPAQUE?) and run with it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically, the tl;dr for why I'm not suggesting a PAKE is that most PAKEs are complicated to implement (is there a good OPAQUE implementation for, say, JavaScript that's readily available?) and/or tied to specific math problems that will be hard to replace if they are shown to be vulnerable. Whereas the scheme presented here uses primitives that are used elsewhere in Matrix and can be easily replaced by equivalent primitives. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was going to say, it's probably easier to implement whatever existing scheme than to design your own. Then I started reading OPAQUE... yikes. SRP and SCRAM are much simpler and use primitives much closer to what you're using. They also have lots of implementations. What makes them not a good fit? I'm not saying you can't build your own PAKE or PAKE-like thing, only that it's really hard. And if you screw up, you'll get the Telegram treatment where the "serious" infosec / crypto people decide to laugh at you instead of looking at your fixed version. All that said, what I've seen so far looks pretty reasonable. I'll find some time later this week to do a full read-through and provide more in depth comments then. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think SRP still requires implementing low-level math stuff. But there's probably at least some decent implementations lying around. SCRAM is pretty decent too, and could be used, though I'd probably want to make some tweaks to it to tighten things up a bit. The main issue with SCRAM is the one vulnerability that I have mentioned in the section where I talk about SCRAM. But aside from that, it should be usable.
Yeah, completely agreed. This is basically just an idea that I had in the middle of the night, and I believe that it's better than SCRAM, but I don't want to push this forward until it's been reviewed by other people who are knowledgeable in crypto. |
||
|
||
### SCRAM | ||
|
||
[SCRAM](https://tools.ietf.org/html/rfc5802) is another protocol that allows a | ||
user to authenticate without the server receiving the user's password. It also | ||
has the feature that the user is also able to authenticate the server since the | ||
client proves that it has access to the `StoredKey`. One of its goals is that | ||
the information stored on the server is not sufficient to impersonate a user. | ||
However, if an attacker has access to the server's storage AND is able to | ||
eavesdrop on an authentication (or impersonate the server), they can compute | ||
the `ClientKey`, which is sufficient for the attacker to authenticate with the | ||
server. This is noted in the "Security Considerations" section of RFC-5802: | ||
|
||
> If an attacker obtains the authentication information from the authentication | ||
> repository and either eavesdrops on one authentication exchange or | ||
> impersonates a server, the attacker gains the ability to impersonate that | ||
> user to all servers providing SCRAM access using the same hash function, | ||
> password, iteration count, and salt. For this reason, it is important to use | ||
> randomly generated salt values. | ||
|
||
### Argon2 | ||
|
||
Argon2 would likely be a better option than PBKDF2 for generating a key from | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Presumably AES-GCM wasn't considered for the same reason? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sort of. By now, there's probably enough implementations of AES-GCM that we could use it if we wanted to. But we're using AES-CBC here for a few reasons. We're already using CBC in olm and SSSS, and we don't use GCM anywhere else (yet -- /me looks at MLS). But another reason is that we do not want the encryption of Kconf (in the server's first response in the login stage) to be authenticated, as noted in the "Offline computation" section. So that encryption cannot use GCM, and it seems kind of silly to use two different encryption modes in the same protocol unless there's a strong reason that both are needed. |
||
a password. However, this proposal uses PBKDF2 for compatibility with Secret | ||
Storage, which used PBKDF2 due to the availability of implementations of both | ||
algorithms. (For example, WebCrypto includes a PBKDF2 implementation, but not | ||
an Argon2 implementation.) In the future, we may switch to Argon2 for both | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW there are some reports that bcrypt is stronger than Argon2 for interactive use, where the computation time is < 1000 ms. Note that this is coming from committee members of the Password Hashing Competition, who authored a competing system (Pufferfish). https://twitter.com/TerahashCorp/status/1155129705034653698 https://www.reddit.com/r/crypto/comments/hvbgt7/alternatives_to_bcrypt/ |
||
authentication and Secret Storage. | ||
|
||
## Security considerations | ||
|
||
### Old clients | ||
|
||
If a user tries to log into their account using a server that does not follow | ||
this proposal may send the user's password to the server by trying to log in | ||
using the current `POST /login` endpoint. This can be partially mitigated in | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we not have a different password for those using the legacy /login flow, separate to the 4S/3C one, much as we do today? So users on old clients (or who want to script their client without understanding this MSC ;) can just grab an AT using an insecure oldschool login - completely independently of whether the account also has 3C set up? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is that old, existing clients will just |
||
two ways. | ||
|
||
1. Deployments in which the choice of clients is not well controlled should not | ||
enable this feature until most of the commonly-used clients are updated to | ||
support this feature. It is up to individual server administrators to | ||
determine when to do this. | ||
|
||
2. Users should be educated to expect to see and verify the emoji security | ||
check before submitting the password. Old clients will not display the | ||
emoji, providing a hint to users that the client does not support this | ||
authentication method. | ||
|
||
## Possible future work | ||
|
||
TODO: combine 2FA? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we have UIA on It feels to soru like 2FA would go beyond the scope of this MSC and would better live as its own MSC, which builds on #2835 and #2839 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah. This is more ildly wondering about whether there are any security benefits from integrating 2FA, versus tacking it on as separate thing. I don't think there are any benefits, but I'm not sure enough at the moment that I want to rule it out completely. So this is mainly a note to think about it. |
||
|
||
## Unstable prefix | ||
|
||
TODO: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds like a step backwards of that other MSC to have decentrel identities, a that proposes to have your account exist on multiple servers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that this conflicts with decentralized identities. Even with decentralized identities, there is some point at which you have to tell a server that you want to use it. This would be analogous to the "registration" part, and then with subsequent logins, you can verify that you're connecting to that same server.