That would only be true if it didn't keep history. Let's assume my previous two passwords are "love123" and "hate098". If I try to use a new password "love124", then the permutation checker (which, for the moment, knows the new password in plaintext) should check the hash of "love123" and reject it.
A better method would be to save previous password hashes when a password is changed, then check hashes of permutations of the new password against the previous ones.
But if you have hashed the password correctly (i.e. a one way hash) you shouldn't know what the previous passwords are. This means that you would only be able to test if the password was the same, not similar.
Not necessarily, you can have the user input the old password when setting up the new one, check it against the old hash and if it matches, do whatever comparisons you need between old and new.
> What the system I describe does not prevent is switching between "FooBarX" and "BazQuxY" where X and Y are changing numbers or characters every time you switch back to them. To prevent that you would need a custom backend, sure.
Yes that's what I figured. Thanks!
Thinking about the problem a bit, I came up with two possible solutions[1].
The first is to save N prior hashes and brute force the permutations. The main issue with this is that if the CPU cost of the hashing is non-trivial (which you hope it would be) then this will be prohibitively slow (though still feasible for a small number of permutations).
The second is to store the plaintext of the old passwords encrypted using the current password. That way after verifying the current password you can decrypt the old ones and run the permutation checks against those as well. Updating the password would decrypt/encrypt the old passwords with the new password as the key[2].
[1]: If anybody else is following this thread and wants to build this, it's all yours!
[2]: Or more likely the new password would be the seed used to derive a key.
Same way you check if the password is correct. Check against the old hashes. When the user sets the new password, if it looks like it matches an iterative pattern (i.e. if it ends in a number) then test the previous few from that sequence against the old hashes. Note, this is still a terrible idea.
You can permutate all possible character positions for combinations of four changed characters, and for _each_ permutation permutate all four characters and then compare the hash, and if the hash is the same you do not accept the password (even though of course you could have false positives with hashes). It is of course much slower than the change of one character which is only 256 iterations if you mutate the underlying bytes and not Unicode characters.
All they'd have to do to safely achieve that is, when you initially set your password to "foo" they will store 11 hashes (foo, foo0, foo1, foo2...). Then when you change your password, it's hash cannot equal any previous hashes.
No, I think you misunderstood the post I responded to a bit.
In the case where the current password is captured on the password change, you have two plaintext values that aren't stored yet and you can just do some text analysis and understand how close they are.
With past passwords, you just take the current input and transform it with common transformations (adding numbers, incrementing/decrementing numbers, etc), hash it, and see if it matches a previous password hash. If so, then you know that they're using a very similar password pattern repeatedly.
Why are you assuming that? You can compare hashes ("does the encrypted version of what they entered as a new password equal any of the encrypted previous passwords").
You could imagine a scheme where they just store N salted hashes of your N-character previous password with 1 character deleted. Then at password changes, they do the same iteration with the candidate password and see if any digests match. This tells them if you made a 1 character change to your password, without storing your old password in plaintext.
You can also implement that by just bruteforcing the previous hash with variants of the new password. IIRC Windows since 2000 implement these kinds of checks in exactly this way.
They wouldn't have to store 3 hashes, would they? They could just get the hash of each of those transformations, e.g., reverse case, get hash. If the transformation make the incorrect password into the correct one, it will match the original hash.
This is done by keeping the old hashes around. The new password hash is compared to prior hashes to be sure it doesn't match any of them. This only catches exact matches on re-used passwords.
Or, the current plaintext password is compared to the new plaintext password (normally a password change requires the current password) so you can do more sophisticated similarity checks, but only compared to the current passord, not any older ones.
> your password can't be anything like any of the previous ones (i.e. they're not stored hashed)
That's... not necessarily the case. You can implement that check by only storing hashes of previous passwords, or of patterns derived form them that are also forbidden (e.g. store a bcrypt of every previous password converted to all lowercase and with numbers and symbols removed).
Or, even simpler: if the plaintext of the new password ends in a number, try stripping (or decrementing!) that number and see if either of those hash to the same as the stored old passwword.
They can't do #4, as they don't have the old password. They'd either end up having to reverse the hash (with the same problems as #3), in which case why keep the crypt() hash? Or they could use the crypt() output as the input to the new hash, which wouldn't change the set of passwords accepted, and therefore wouldn't help at all.
reply