CBCrypt: Encrypt from the client rather than send passwords to servers
cbcrypt.org
cbcrypt.org
> To cryptographers, the phrase “prove you know something secret without exposing it” instantly suggests “use asymmetric cryptography.”
No, wrong, stop right there!
The phrase "prove you know something secret without exposing it" instantly suggests that you should figure out what "exposing" means before you try to design a protocol. If I'm a user reusing a password between two sites, then it's unavoidable that either site can try to brute-force my password. However, it would be rather nice if an attacker who hasn't compromised either site can't brute-force my password without interacting with one of the servers for every single guess.
That property is achievable using well-understood techniques, and this blind use of asymmetric cryptography fails to achieve this goal and is unnecessarily complicated (what's the PRNG for?). The primitive you want is an "augmented PAKE". The IRTF CFGR is very slowly working on standardizing one, but in the mean time there are several high-quality augmented PAKEs out there.
Also, note that I said "primitive". A strong primitive does not automatically make a good protocol. CBCrypt's docs say "Keypair is ECDH 256, derived from SeededPRNG". This raises all kinds of warning bells: while there are perfectly good protocols based on ECDH, ECDH by itself just gives an /unauthenticated/ session key, and from a 30-second look at the code, CBCrypt appears to be trivially vulnerable to a replay attack in which a malicious server A convinces a standard client to give it a valid authenticator for a session to a different server B.
Nice catch! This looks like a trivial (and thus educationally useful) instance of an unknown keyshare attack.
Your 30-second look at the code needs more than 30 seconds. If a client connects to malicious server A, the private key it would use for that connection is different from the private key it would use on server B. So malicious server A cannot replay an authentication session on a different server.
Video is not suited for technical details.
It's not easy to quote / excerpt, to quickly refer back to previous (or later) parts, to take more time over parts that need it, etc; not the way text is.
My default reaction to "you'll understand if you just watch the video", is that someone is peddling bullshit and doesn't want me thinking too deeply.
Note, however, PBKDF2 has a bug where each additional block of output bytes is recomputed independently, which means the work factor (iteration count of the underlying hash algorithm) is applied separately for each block of output generated. So if you ask for, say, 1,000,000 iterations of PBKDF2-HMAC-SHA256 with 64 bytes of output, you are actually running two separate independent runs of 1,000,000 HMAC-SHA512 under the hood. This allows attackers to derive the output block-by-block instead of having to compute all or nothing, which can increase cracking speed in some cases (see 1Password writeup [1])
More simply, you can use a hash/KDF to produce a single block of seed with all your desired work factor imputed into that one value, and then stretch the seed simply as: for 1..n { hash(seed || n) } to get however many bytes you need to produce your privKey. In other words, 1,000,000 iterations of work for the seed, and a single iteration of work for each final block -- effectively all or nothing.
This will let you reduce the number of primitives to the single hash function you choose, which personally I think is much cleaner than introducing a whole PRNG into the mix.
[1] - http://blog.agilebits.com/wp-content/uploads/2013/07/playing...
That may or may not be true for traditional DH. For ECDH it's false. A Curve25519 ECDH private key, for example, is quite literally a handful of random bits. (Depending on how you look at it, it's a 256-bit number with some fixed bits or just 252-ish bits. I say "ish" because I don't remember the exact number of fixed bits off the top of my head.)
Edit: Fixed bogus EdDSA reference. Also, I just looked it up. A Curve25519 private key (http://cr.yp.to/ecdh.html) indeed requires exactly 252 random bits (or the 252-bit output of a secure KDF).
From looking at their tests and the PowerPoint file in their repo, they mention confirming that the hostname provided by the server in the challenge matches the SSL Certificate. Asking as someone who knows very little about crypto, under the assumption that they validate the hostname and are using TLS would it still be vulnerable to a replay attack?
All of these seem like pointless assumptions to have to make when a better protocol wouldn't have this problem in the first place.
In any case, I'm having a little bit of trouble understanding why this thing is useful at all. It helps against an attacker that compromises a server but isn't willing to inject malicious code into the JavaScript served up by the attacker, and attackers who want to target everyone without being detected might actually have that limitation, but more targeted attackers will just modify the JavaScript (unless they have some other deployment scenario in mind).
(Minor correction to my first post: I didn't actually mean "replay attack" -- I meant "relay attack". Whoops, silly typo. Although, now that I think about it, they might be vulnerable to replay attacks, too -- I make no effort to check for that.)
I'm not saying it's right, but as people keep reminding me there's a lot of grey area between 'bad' and 'perfect' and most of the time we don't get anywhere near perfect. 'Better' would be something for a lot of people.
When the SRP code was going around people kept saying "Hey use the javascript library" and for reasons similar to yours I said, "No thanks, when will the browsers support it?"
Because if we're going to use keypairs for authentication, it really should be integrated into the user agent, where it's extremely hard (and hopefully impossible most days) to inject code.
Ad networks get hacked all the time. Probably better than half the sites I visit will pop up a login prompt over the top of the ads, which means somewhere I'm logging in, an ad could very well be trying to get my credentials, and it only takes once for the UA to fail to prevent it and I'm in hot water.
If you don't know what the PRNG is for, perhaps a cursory 30 second lookover and then crap all over wasn't enough. ;-) Watch the 9 minute Tech Video, which explains, the asymmetric key generator can't use a fixed length seed; it needs to be a random stream. Also, there's a challenge/response which can only be answered by knowledge of the client's private key, so your comment about the replay attack (I think you meant relay attack) is also incorrect - whichever you actually meant, you're wrong either way.
PAKE can be used to construct all kinds of things. You can generate a key for one session, you can generate a persistent key, you can run a PAKE to authenticate an existing session, etc.
The algo can work by the site sending the user their personal salt. The algo will then encrypt the password, use the salt, and send the derived key.
This DOES remove the burden on the user of trusting every site with their password. The problem is quickly the password is only but one of a lot of data hackers look for.
Do you rely on the server to play nice, and not present you with fake login boxes, then all bets are off.
I actually read the Github page for this, and glanced over the C#. There's no realistic example of how this would work in practice, and I have unanswered questions. This would legitimately solve some phishing scenarios and MIGHT slightly mitigate password reuse scenarios (since they know username + domain, they now need to spend time cracking scrypt() on the password). The arguments that it helps user privacy (NSA something something) are tin foil hat wearing jibberish.
Overall: Meh. If they're serious about this, they need more than a vague proposal.
PS - And a password manager solves all of the named issues with less complexity in my opinion.
Before submitting passwords to a website, they're replaced with a hashed version which incorporates the domain, so passwords are unique to each domain. (The hash isn't anything fancy, so it could definitely be modernized with scrypt or bcrypt or whatever is fashionable.)
I've used it for years and it always works well, apart from the sites that claim my password is too long. It requires no support from the website, just a simple browser extension.
- 10 characters
- at least one punctuation
- at least one digit
- at least one upper case
- at least one lower case
By coercing the password to have this form you're losing a trivial amount of entropy, but you'll pass the vast majority of password policies.Also add a nonce to the password generation (1, 2, 3, 4) so that you can change it if needed or required. No need to remember the nonce, just try a few until you can login.
It's not directly related, but I'm reminded of this Hall of Shame I stumbled upon from some HN comment a few weeks ago: http://plaintextoffenders.com/
In particular, the fact that you type your password into the password field means that failing to invoke PwdHash means you either register with your raw password (making it worse than useless) or just leak your raw password with failed login attempts.
The password manager model (e.g. LastPass) is clearly superior in my opinion because the user doesn't know their passwords. Largely the only way to input your password is the correct way. Also determining the password for one site provides no information for others (assuming you're random generating the passwords). For PwdHash, if you crack the password you have a lot of information for breaking all the user's other accounts (because presumably they're reusing the same base password).
Pwdhash uses md5, which is relatively fast. According to the below, even a strong master password could be derived in less than about 30 days.
https://security.stackexchange.com/questions/52355/how-secur...
On the other hand, the odds you'll be the victim of such a targeted attack are presumably pretty low. This at least gets you out of the category of "low-hanging fruit" for an attacker.
Using SHA is of course discouraged, because compared to bcrypt the collision attack can be parallelized on top of GPUs and you can try tens of billions of combinations or more on top of commodity hardware. But here's the gist - with a good salt, the complexity of finding collisions is about 2^256. Basically without knowing the salt, you're shit out of luck, because all the PC or GPU power in the world cannot crack 2^256. You can't use rainbow tables either and there are no shortcuts discovered for SHA-256, like you've got for MD5. And then you've got things like bcrypt, an 11 years old algorithms that can't be parallelized over GPUs and that's still unbreakable.
I disagree with you. This doesn't just slightly mitigate password reuse. It actually solves it.
And for me it's way better than a password manager because (a) it isn't a single point of failure like LastPass, (b) you don't have to trust a proprietary binary blob like 1Password, (c) you don't run into the risk of losing access, as everything is in your head, (d) when one of your passwords is compromised, you have the incentive to change the master passwords which will trigger a change of all the passwords, everywhere and (e) best of all it's free.
The general concept I stole from somewhere else -- you've got a stored list of sites and when you type your master password in a field, each site in the list then gets a "copy password" button based on the site name + master password. But this isn't quite flexible enough for general use, so I added some features:
First, each site has a 'version' field which becomes just another piece of data input to the hash. This makes it so you can rotate passwords on a particular site without changing your master password: increment this number and you get a whole new password.
Second, each site has a password 'scheme' which allows for disparate password requirements on different sites. The underlying generation algorithm is the same, but rather than converting the hash output to a base64 number and using it directly, the hash output is used to deterministically select characters based on the rule set. Roughly, each scheme has an arbitrary number of character "classes" that may be included (e.g. "numbers", "letters", and "symbols") and each scheme may specify a minimum number of characters from each class (a typical rule being that that min=1 for numbers and symbols). So the class-specific minimums are satisfied, then the rest of the characters are selected from all classes equally, then a few more bytes of hash are consumed to deterministically change the order of the selected chars (otherwise you'd always end up with your minimum two special characters at the front, for example, which technically weakens the password). Each site also can have a distinct password length setting. Currently I only have three or four different "schemes" defined and haven't had the need to add one in a while so they're all hardcoded, but one could easily imagine having a "password scheme editor" which lets you define new ones with a few primitive rule types.
And third, each site has a "last changed" date which helps me keep on top of which site passwords haven't been rotated in a while. If you change your master password every time you need to roll one site's password, this probably isn't an issue for you, but I definitely prefer to avoid the ritual of changing passwords on every site I use at once.
My impetus for all the password scheme complexity is that I found that more straightforward password generators simply don't work on all sites, and I hated having exceptions. The site where I pay my electric bill, for example, doesn't allow exclamation points in passwords, and they must be between 6 and 8 characters. Lame to be sure, but I really have no choice but to go along, so my password generator must too.
All that said about my password generator, I think this is a fundamentally different approach to the problem and I think the cbcrypt approach is ultimately more interesting if we can get it incorporated into browsers. I've long thought we should expose some sort of modified SSH-agent functionality to the browser JS API so sites could do public key auth for login (with the appropriate user prompting, of course -- just allowing websites unfettered access to your SSH agent would obviously be a terrible idea).
I used it for years (for unimportant things) before switching to a password manager. It's technically not secure against a malicious site that sniffs for the existence of the bookmarklet window, but it's a good way to get slightly better security on sites you'd other reuse the same password for.
Using something like public key authentication allows you to use the same public key for every website. Your password management software and synchronization strategies are both suddenly a lot simpler. Server-side mistakes are less problematic to the end user.
It removes several points of failure, and has greater flexibility against user, server, and developer mistakes.
If it deterministically generates a keypair from a password, then attacker acquiring a public key is equivalent to acquiring a password hash — the public key now becomes a verifier.
"The worst attack a malicious server can mount is an expensive brute force attack, attempting to overpower the rate-limiting function and eventually guess a password that recreates the exposed public key."
Almost the same result as if the server just stored an scrypt hash, but more complicated, and without a random salt. The solution for the problem just makes it worse.
Instead of sending the public key every time, the server sends a challenge, which only the private key holder can answer. This is a pretty basic usage of keypairs and an extremely brief perusal of their source code suggests to me they've thought of it.
So no, the public key is not the password, unlike hash based systems which do suffer from the problem you're concerned about. The hash IS in fact now your password in those systems.
But for this class of algorithms, that doesn't have to be the case. Starting with a cryptographic hash could keep the key from being reversed to the input. There are probably other things that could help as well, like maybe not using the password in the public key at all.
Remember, the attack is: start with "aardvark", run the deterministic key-generation process, hash, scrypt, elliptic curve and all, and check to see if you get the same result. If you don't, move on to "apple", then "ataxia" and so on.
The attacker has every piece of information in the system except the password string, which they can substitute with a dictionary.
In most systems where the server never sees your password, they store a hash that is generated from the password.
Then the login code on the client takes the password, performs the same operation and then sends either that same hash to the server, or one that's simple to calculate from it.
So if I steal your password file, I can log in as everybody without even knowing what their passwords are. I just change the code in the client to skip the hash generation part of the authentication algorithm and use the one I supply.
The idea with asymmetric ciphers (at least the ones that interest us) is that one party HAS to know the secret, and the other has no way to get it.
I think you're saying that this system is better because, since it uses public key pairs, an attacker who steals the password file doesn't know enough to log in as a different user.
Leaving aside that an attacker who steals your password file has probably mooted login security altogether, the attacker in this system seems to have exactly the same leverage as an attacker who steals a password file full of scrypt hashes.
S <- scrypt(zeroes,
SHA2(name, pw, host))
secureSrand(s)
keypair <- keygen(ecdh, secureRandom)
The client sends the pubkey to the server, the sever sends nonce challenges to the client."CBcrypt combines publicly known authentication factors (typically username and server id) with secret factors (password), applies a rate-limiting work function such as scrypt or pbkdf2, to deterministically generate a random seed. This seed is then used in a pseudo-random number generator (prng), and the prng is used as the basis for generating a public/private keypair."
EDIT: ah, got it (libc! :), secureSrand means "initialize PRNG with seed", so we're talking about the same thing.
Also: is it safe to use a secret-seeded DRBG as a CSPRNG for ECDH keygen? The time it will take to generate the ECDH key will be secret-dependent, right?
(I'm sure it doesn't matter in this case. Just curious about the general case.)
And it's been pretty obvious that most service providers have no idea what they're doing and can't be trusted to do that.
Further, a fake website can sidestep this by not using a secured connection and just faking the UI.
Windows reserves CTRL + ALT + DEL for this reason, but doing that on a tablet / phone that's already in production quickly runs into issues. Also, windows had plenty of issues with fake login screens.
PS: I suspect protecting people from such things ends up requiring fairly strong AI or significant compromises.
In the end, I'd probably prefer something like SRP
Not if the server generates a unique ID for each attempt, and that ID must be used in hashing. It can be as simple as a timestamp.
Use all of the authentication data as the seed for generating a key pair. When you create a new password you send the public key to the server, where it is stored. The private key is regenerated on the client on every authentication challenge.
I submit for your perusal:
But now that I RTFA'd these guys seem to be using the same basic concept so I'll be keeping an eye on them.
[salt, modexp(g, H(salt, password), n)]
The exponentiation makes the brute-force attack a little bit harder than a simple salted hash, but not that much. You can obviously replace the salted hash with something else, and that's a good idea, but the point of this post is that password hashes are insufficient to protect user secrets.I disagree with the post, of course.
Edit: okay, you just answered that. Thanks! :-)
https://github.com/rahvee/CBcrypt/blob/master/CBcrypt/CBcryp...
... appears to have a straightforward, helpfully inlined timeable comparison of challenge responses.
I don't understand what this package is accomplishing. The description leads off talking about the grave privacy implications of storing scrypt password hashes. But then it stores what is in effect an scrypt password hash on the server.
I don't think it's saying that storing the hash is bad, it's saying that sending an unmodified password to be hashed on the server is bad since that server now has your cleartext password.
I actually don't know very much about challenge/response protocols, and I'm struggling to find any good resources, so take this with a grain of salt. You could build a protocol out of digital signatures (probably there are massive things wrong with this, don't do this, here by dragons, don't build your own crypto etc. etc.):
1) When the user registers with the site, the client generates a public/private key pair and sends the public key to the server, which stores it.
2) When the user wants to log in, the server sends a challenge to the client. The client uses their private key to sign it and sends the signed message back to the server. The server uses the public key stored against the user to validate the signature.
Obviously this is more than just hashing the password on the client. If the server sends a different challenge each time (possibly time based like OTP?), you're protected against replay attacks.
The problem is you need a key pair. You don't want to generate a random one because then the user has to manage it and keep it with them and copy it from machine to machine etc. So the problem solved on the website is how to generate a good key pair from just a site identifier, username and password.
How effective it is at that, I have no idea.
[edit] other posts have helped me realise the public key is just an unconventially derived hash. Even if it's used in an unconventially way for authentication, you can brute force it the way you brute force any general hashing algorithm: key == generate_key(password_guess)
Edit: And then you (maybe?) use your password to encrypt the private key locally.. maybe? That's a total guess. That's what I'd do :P
Does the client send the private key to the server for verification? I'm not sure but I doubt it. At least I hope that's not what it does.
My guess would be that the server sends an encrypted message of some sort that the client cannot decipher unless it possesses the private key. It deciphers the message then sends it back to the server in deciphered form to say: hey, see, I have the private key, here's the proof: this is the message you sent me earlier. I couldn't have deciphered it without having the private key.
Can this scheme be used with passwords as well? As in, treat the password as a private key, so the client never has to send it over the network.
Server ---- [garbled-message-challenge] ---> Client
Server <--- [ungarbled-message-response] --- Client
Does this scheme work?I'm talking more about authentication over a channel that's not necessarily encrypted.
The point being, avoiding having the client send its "secret pass word" to the server, but still allowing the server to verify the identity of the client.
It's also what SSH uses.
Hope that's helpful!
I don't want to share my secret with you. You just throw a test at me that only I could possibly answer.
The point is, every time you should throw a completely different test at me.
Not only you can verify my identity, but anyone who's listening to the conversation can also verify my identity, and I don't have to share any secret.
Yes, once you've done a DH exchange, you can use the established key to relay a nonce to prove both sides have the same key.
But tptacek obviously knows what he is talking about.
There's a lot of dazzle and he seems to be going out of his way to confuse people, or he is himself confused.
Canonical protocol that involves generating (in this case symmetric) keys from passwords is Kerberos. Implementing same idea with asymmetric crypto is certainly possible, but of somewhat questionable utility, because doing ephemeral DH and then some kind of authentication handshake is both more secure (PFS and so on) and more efficient. True asymmetric encryption algorithms (e.g. RSA) have ciphertexts of considerable sizes (in comparison to anything ECC or sizes of DSA signatures), while discrete-log encryption algorithms essentially involve doing the DH exchange anyway.
In other words: asymmetric encryption is rarely the right primitive for network protocols. On the other hand converting password to keypair that is used for signing or something like SRP is useful for some applications (for most applications there isn't any practical benefit).
Does this provide any advantages over SRP?
It also doesn't instill confidence when somebody talks about "encrypting" passwords rather than hashing them.
The way this project tries to solve the problem is by hashing the password from the client side so that sites never get the real password, but a hash instead. As other commenters have pointed out, this is not entirely effective because the attacker still can crack the hash. It just makes the problem more difficult depending on the size of the original password.
The real solution to this problem is to stop sharing password at all. Use a password manager for that purpose.
The real problem with this is that it'd never be feasible to convert enough sites and apps to using it to make it safe to reuse passwords
+1 for password managers or U2F style authentication systems.
On the other hand, there's nothing that's made _worse_ by choosing to do it that way. Plenty of things that are the same, some things better, but nothing worse.
In the Notes system, the user has an encrypted local credential store (part of the ID file) which contains, among other things, the user's private key and any shared secret keys the user may have been granted. The ID file also contains (in the clear) a certified public key, user name, and other information that should not be considered secret. The only password authentication is locally with the ID file. The password is salted and stretched with a key derivation function; the derived key is used to attempt to decrypt the encrypted portion of the ID file. "Success" is determined entirely by padding and checksums. Neither the password nor any variation on the theme of a hash of the password is stored anywhere. The "safe" portions of the ID (username and public key) are used to create a user account on the server.
Authentication proceeds much like this: "Hi, server! I'm this guy according to that guy." "Oh yeah? Well, this guy (if that's your real name), you ought to be able to answer this encrypted question and send me a signed response."
(Determining whether that guy actually vouched for this guy is standard signature stuff, assuming the check is needed at all. For stand-alone clients, a locally-generated certifier is SOP.)
That does raise a couple of potential pain points, though. One is simply managing the local store, making sure that the users always have access to their credentials. Another is that when a store dies, the private key dies with it (secret keys can always be re-issued to a new credential store once the user is satisfactorily vetted). And users have this horrible, horrible habit of either never backing anything up or "backing up" to the same physical medium. In the corporate Notes world, that's not such a problem since updated ID files mail themselves off to an ID vault, but who gets that trust in the civilian world? And there's the little matter of password recovery (in Notes, a KDF state accessible using a combination of something like Shamir secret sharing and the private keys of k of n trusted administrator IDs) — one probably doesn't want to throw recoverable credential stores into the wild hoping that trust is never broken. Without password recovery (which isn't actually password recovery; it simply allows the user to re-encrypt the I with a key derived from a new password they choose) of some sort, anything that requires your private key is lost when your password is lost. Automating the resetting of a server account brings us back into the realm of highly insecure things like "security questions" (since it's very likely these days that the second factor of 2FA is the same lost/stolen device that prompted the need to reset the account in the first place).
Nothing's perfect... or easy.
Doesn't this assume a lot about the state of the internet? I mean a phishing attack could easily harvest the user's password, then the attacker effectively has their private key. Unless every user were trained well on how to determine whether the connection can be trusted, but that's still a problem today in 2015 even with https.
Instead, imagine new HTML elements and you could have
<form type="cbcrypt"> <input type="username" /> <input type="password" /> </form>
and the web browser would allow you to enter your credentials in a secure, NATIVE window. (At least secure from web stuff - keyloggers get a lot more powerful under this scheme.)
If it works as advertised, it's quite nice. Personally, I think this is very close to what we need.
I will note I still probably wouldn't use it because if your password is exposed, then you're screwed. It is very close though. A hardware element or something might mitigate this enough.
I would think an out of browser app might work better for that task.
(I'm going by the textual description on the linked page as there doesn't seem to be a more detailed or formal one)
That way the server only has your public key (and everyone can have it anyway).
It probably won't ever change unless one of the browser vendors that is also an vendor of popular online services decides that it would be good to enable it in its own services, and picks up the cost of upgrading its own UX to support that (creating pressure on other browser vendors, while also lowering the barrier for other online services.)
The problem is that all of the browser vendors that could do it are pushing their own, online authentications schemes, and have no interest in client-based authentication.
"The site is asking you to sign up. What secure login key would you like to use?
* Personal
* Office
* Contracting"
You are person 'A' and you have the private key (and maybe password used to unlock the key) to prove this fact.
You don't need different private keys for each and the remote end just has a public key that says the account belongs to person 'A' and that key is public.
The only usage case would be if someone wanted multiple accounts at the same site, and that would be rare indeed.
The only other real concern, site hacks/collaboration leaking where you're a member of by public key, wouldn't be alleviated by merely a handful of keys anyways: you'd need unique keypairs for each to be truly secure.
But yes, having small memorizable passwords is much more convenient.
Things like U2F have a better chance of solving the password issue.
Information though.. i'm happy with google apps processing my data but i'd rather they can't actually store the data on their servers.
Ex: lets say you're a gmail user. Wouldnt it be nice if only your browser could read the contents and gmail servers only metadata?
Obviously, Google wouln't want that (remember, you're the product) - but that would be nice in the grand scale of things, wouldn't it? Like you know, instead of being slaves of corporations, just have them do stuff that's good for us and what not (dreaming out loud right now)
Unfortunately, neither mobile applications nor the JavaScript on most web pages are open source, so there's no guarantee that they have implemented this strategy correctly. You don't know what happens after you type a password into a text box.
It's also too idealistic to expect that enough people will implement this kind of system such that you can advise people that it's "okay" to reuse passwords.
[1] I think this was in one of Shannon's papers, but not sure. It should be very easy to find though. Basically once you start digging around a topic of using passwords as PRNG seeds all relevant research surfaces very quickly.
No idea how that compares to TFA, because they have no documentation.
Stored on server: x = SHA256("mypassword")
Server challenge to client: send a secure random nonce
Client sends: c = HMACSHA256(nonce, SHA256("mypassword"))
Server verifies: c == HMACSHA256(nonce, x)
In some implementations, the server challenge and 'c' are encrypted using 'x' or some derivation that both sides can create. In addition, salts can remove the sensitivity of the stored 'x' values (https://en.wikipedia.org/wiki/Salted_Challenge_Response_Auth...)
This only mitigates knowing the password itself, not anything to do with authentication.
But now you have to grab the hash first from one of the endpoints, MITMing the connection no longer suffices to impersonate the user.
I suppose public key schemes would be preferable, but deploying those isn't feasible for a lot of use cases.
Do they? Doesn't the server just need to share the salt and algorithm parameters it stores anyway?
CBCrypt seems to me to introduce a lot more complexity into the entire application space with very little real gain. I'm certainly open to being convinced (especially because I'm waffling on whether or not this is a dumb reaction).
But still: I just can't get worked up about this at all. I'd rather see pgp get implemented in browsers before this.
In my humble opinion; we need to use the blockchain to save hashes for trusted and open-audited JavaScript files to be confirmed by the user. This, however, needs to be done at the browser level to avoid an endless trust loop with JavaScript/browser extensions. blockstrap.com has figured out how to put file hashes on the chain; so technically it shouldn't be a major challenge to do the first part. The browser part is where it gets tricky!
This is an orthogonal problem. Something like CBCrypt would solve a real problem we have right now, which is most service providers don't secure their password database correctly.
If a service provider gets hacked to the point that they their javascript is malicious, all your content on that service is probably already pwned.
IMO, if you are going to use client certificates you should be just be using standard client certificates with whatever your OS provides to generate them.
Is it just me, or does the current way we handle passwords feel archaic, even while we still use them?
This sounds super fishy to me; feels like a misinterpretation made through tin-foil lenses. Citation please?
The problem is bigger than that - we should stop making users type password at all. There should be an authentication module any website could use to store and retrieve credentials from. Check out Truefactor.
We have the solution already in HTTPS client certificates. Browsers all have mechanisms for generating and storing them. The only problem is that no one uses them.
How do you plan to do that securely?
Also where is the salt stored? SHA256 is pretty easy to brute force even salted.
Am I missing something?
Obviously there is still a benefit to not sending your password to the real site, but their anti-phishing claims seem… phishy.
Also, C#? What is this, a Silverlight applet? :P
You get a random generated password for every website, and it won't suggest to use it unless you are on that website.
1password is better.
"Oh no, my shared secret for this site got compromised and now all my accounts are compromised because I authenticate to 50+ other sites with the same secret."
This is like putting your only private key on every service and complaining if bad things happen.
Make sure you encrypt ALL communication and not just the password or cookie.
No "Forgot your password?" functionality available (reset token), since the server does not store password (hashed or otherwise).
You should never store the users password.
In addition the reset password is not possible when the data is encrypted on the client side. This is how TrueCrypt works - if you forget the password, all your data is lost.
"Users are able to login to servers, and encrypt all their data, without ever exposing their password or encryption keys to the server."
"And if the user's data on the compromised server is encrypted using the user's keypair, then even the users' data is still protected."
Stepping back a minute, it's helpful to consider the fundamental reality of almost any password validation scheme. In this case we are storing a "public key" on the server, but it is more aptly described as the "password validator". Almost all designs will have such a thing (a notable exception is PolyPassHash which cleverly avoids a one-to-one mapping of users to validators, and uses this to try to defeat some offline attacks, with some interesting trade-offs).
If you combine public information, the password validator, and the correct password, your 'password validation function' will complete and return 1. Therefore, if you have the necessary public information (i.e. domain name, username, whatever else is stuffed in the hash) and you steal the password validator database, you now have everything you need in order to run the so-called "offline dictionary attack".
In SRP, an obvious inspiration to this CBCrypt design, the password validator database is basically computed entirely by the modexp() work required to generate the pub/priv keys. There is no additional/configurable key stretching which can be applied other than choosing the bitlength of the keys.
Here we have a configurable round of hashing (Scrypt or PBKDF2) which is applied before the key derivation step. This provides additional protection against offline attacks, depending on how hard the work factor is set. History has shown us, a key detail in ensuring secure password storage is actively managing the hashing function and work factors over time, or else watching Moore's law strip away any protection we thought we had.... So the next key question is, how do we actively manage and maintain a sufficient work factor?
When evaluating a hashing function, one key question to ask is can we add to the work-factor of existing passwords offline (without having the password in RAM) or do we need the user's password resident (somewhere, client or server-side) in order to recompute a new hash with the new work factor? In this case, by design it's impossible to offline harden the existing passwords. You would need to first login the user, verify their password, and then recompute a new hash (perhaps transparently, perhaps with some UI component if it is too slow otherwise) and re-derive and update the key server-side, in order to change the work factor.
But really, the primary consideration with any client-side hashing design, is how to support the extremely wide array of devices which will need to register/login to your site, and what's the user experience when they click the Login button?
From CBcrypt.cs, where the proof of concept is written in C#.NET using BouncyCastle's Scrypt library:
/* cost 4096, blockSize 8, parallel 1, cause SCrypt to take ~175-350ms on Core i5-540M, 2.5Ghz
* This is in addition to the approx 100ms-200ms to generate ECDSA keypair.
*/
Now, in reality we are going to be running Scrypt in Javascript on a mobile device. I found what seems to be a highly optimized implementation [1] and plugged it on Dropbox [2] so I could point my browser at it to see how slow just the Scrypt ran. On my laptop it was taking about 800ms and on my iPhone 5 about 2500ms. I would say that means for about 25% of the mobile population this function runs about an order of magnitude too slow for comfort... it will impact user experience, it could impact bounce rate, etc. This doesn't even include the ECDH part of the calculation.This is definitely the hardest question to answer with client-side hashing, or even simply "sever-relief" hashing where a portion of the overall hashing may optionally be pushed to the client, particularly during DDoS type events. How do you identify which clients are sufficiently powered to reasonably perform the hashing, or what kind of UI needs to be presented if you could be potentially locking up a browser for 5+ seconds while the hashing is running? Users are not well trained to expect logins to be slow -- a stall in the browser is almost always a reason to simply resubmit the form. It would be great if users associated their browser tab locking up, their fans spinning to full speed, and their battery power plummeting with "Whoohoo, this site is ROCKING a awesome work factor!" but in the real world we see that companies want hashing run on powerful CPUs server-side, with the capability to offline-upgrade hashes over time.
The final nail in any client-side hashing approach is when the claims start to cross over to "server never sees the password". I don't see this as a valid argument any time the code to perform the hashing is being sent over the same trusted connection from the server itself. There are corner cases, for example if you are shipping compiled and signed code which is hashing client-side, or if you take special precautions with browser plugins to ensure you are running a specific build of the Javascript, but that simply doesn't apply to 99.99% of use cases, and so I personal dismiss those benefits as not likely to be achieved in the real-world. What we're left with is technically a sub-optimal user experience with additional trade-offs. So in conclusion, I am currently quite bearish on client-side hashing on the web in general.
[1] - https://github.com/tonyg/js-scrypt [2] - https://dl.dropboxusercontent.com/u/42286273/site/test_scryp...