Jump to content

Websites which knows your new password is similar to your old one

Rakanoth
On 11/30/2018 at 8:54 PM, mshaugh said:

Took some time to find again: https://security.stackexchange.com/questions/53481/does-facebook-store-plain-text-passwords#comment84577_53483

 

Yes. Taken from the linked answer:

  1. user sets first password to "first" and fb stores hash("first").
  2. later on, users resets password and is asked to provide new password "First2"
  3. Facebook can generate bunch of passwords (similar to the new one): ["First2", "fIrst2", "firSt2", ... "first2", ... "first", ... ] and and then compare hash of each with the stored hash.

AHH so it was a misunderstanding after all. They are not checking the similarity of the hashes, they are attempting to generate the old password by applying slight modifications to the current password supplied and then seeing if that produces the SAME digest that they have on record.

Link to comment
Share on other sites

Link to post
Share on other sites

On 12/1/2018 at 1:54 AM, mshaugh said:

Took some time to find again: https://security.stackexchange.com/questions/53481/does-facebook-store-plain-text-passwords#comment84577_53483

 

Yes. Taken from the linked answer:

  1. user sets first password to "first" and fb stores hash("first").
  2. later on, users resets password and is asked to provide new password "First2"
  3. Facebook can generate bunch of passwords (similar to the new one): ["First2", "fIrst2", "firSt2", ... "first2", ... "first", ... ] and and then compare hash of each with the stored hash.

but has my code above shows even passwords that are the same will give completely different hashes, there is no why to compare hashes to see if they are similar.

                     ¸„»°'´¸„»°'´ Vorticalbox `'°«„¸`'°«„¸
`'°«„¸¸„»°'´¸„»°'´`'°«„¸Scientia Potentia est  ¸„»°'´`'°«„¸`'°«„¸¸„»°'´

Link to comment
Share on other sites

Link to post
Share on other sites

There are a lot of different ways to compare password similarity without saving the exact password, but it's at the expense of security so why bother?

-KuJoe

Link to comment
Share on other sites

Link to post
Share on other sites

4 hours ago, vorticalbox said:

but has my code above shows even passwords that are the same will give completely different hashes, there is no why to compare hashes to see if they are similar.

It's not comparing the hashes for similarity, it's generating similar plaintext and then hashing to see if the hashes are exactly the same. It's just doing the "similarity" portion through generating the plaintext. example:

real password is "password1", old salt is "1" and both encrypt together to "A" (i'm not gonna use real hashes for obvious readability reasons)

 

User attempts to reset password, and enters "password2", which together with a new salt "2" hashes to "B"

 

The system also generates a bunch of similar passwords from that new password: 

["password0", "password1", "password3", .... "password99", "password2!", "password2@", ] etc, and hashes them all with the old salt:

[C, A, D, ... ]

 

it checks all those hashes against the hash for the old password, and sees that one matches (the one from "password1"), and it determines that you only changed your password through a small numeric change. If none match, then it determines your password hash changed enough, and stores it's hash as well as the new random salt, and the process is complete. This is how it identifies similar passwords without ever knowing your old password (unless it finds a match, but it's not a huge deal since you are already in the process of changing the password)

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

3 minutes ago, reniat said:

It's not comparing the hashes for similarity, it's generating similar plaintext and then hashing to see if the hashes are exactly the same. It's just doing the "similarity" portion through generating the plaintext. example:

real password is "password1", and it encrypts to "A" (i'm not gonna use real hashes for obvious readability reasons)

 

User attempts to reset password, and enters "password2", which hashes to "B"

 

The system also generates a bunch of similar passwords from that new password: 

["password0", "password1", "password3", .... "password99", "password2!", "password2@", ] etc, and hashes them all:

[C, A, D, ... ]

 

it checks all those hashes against the hash for the old password, and sees that one matches (the one from "password1"), and it determines that you only changed your password through a small numeric change. This is how it identifies similar passwords without ever knowing your old password (unless it finds a match, which means you didn't change your new one enough)

I'm sorry but this doesn't make sense at all. Ignoring the computer power it would take to generate similar passwords on the fly, you're completely ignoring the salt. Using hashes, it's impossible to know what passwords are similar. If the system is even remotely secure, the same password SHOULD have a different hash. If the system is not salting the password before inserting it into the database, tell the developer it's 2018 and to also stop using MD5.

-KuJoe

Link to comment
Share on other sites

Link to post
Share on other sites

1 minute ago, KuJoe said:

I'm sorry but this doesn't make sense at all. Ignoring the computer power it would take to generate similar passwords on the fly, you're completely ignoring the salt. Using hashes, it's impossible to know what passwords are similar. If the system is even remotely secure, the same password SHOULD have a different hash. If the system is not salting the password before inserting it into the database, tell the developer it's 2018 and to also stop using MD5.

I actually just updated my example to use salts. It still works the same way. You still know the old salt, and can use that when hashing the new password modifications to check for matching hashes.

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

7 minutes ago, reniat said:

I actually just updated my example to use salts. It still works the same way. You still know the old salt, and can use that when hashing the new password modifications to check for matching hashes.

OK, yeah I was incorrect about the salts because it's the same user... but it still won't work. Here are three passwords and their respective sha256 hashes using the same salt:

 

password1 = 2e3fa5cf5ca9959f88145d33622a28fd2e34e709c4e9f12bcf1bbe300e284656

password2 = 6a98082c11c0665c701267f402a621111526fbeb4556aac058e7785275060c70

password3 = c1c68ad282238292c3e4be9ac145ba3519dcdfe50141ec75af7d3bcb12316885

password11 = 7bd3c1b1995843115de25fd39e5dd67e570314b1938af5679c3d67d71667723e

password1@ = 289b1ff692dcbcc9d39dc4a27a496f2b4cbad40f09f90dd24f08242fc71616e4

 

How do you compare the hashes to see what is similar?

Edited by KuJoe
Added more examples because I think I see what you think will happen if you add another character to the end of your existing password.

-KuJoe

Link to comment
Share on other sites

Link to post
Share on other sites

1 minute ago, KuJoe said:

How do you compare the hashes to see what is similar?

I'm not sure if you ready my example closely enough. You don't compare the hashes themselves for similarity. The hashing is done after generating passwords similar to the new password using simple heuristics for how users might only slightly change a password (e.g. increment a single number character and leaving the rest the same, or just adding one character).

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

1 minute ago, reniat said:

I'm not sure if you ready my example closely enough. You don't compare the hashes themselves for similarity. The hashing is done after generating passwords similar to the new password using simple heuristics for how users might only slightly change a password (e.g. increment a single number character and leaving the rest the same, or just adding one character).

Oh so you're suggesting that the system generates passwords based on the new password and compares it to the old password hash in less than 1 second? It can work on a small website I guess, but that kind of computer power just to do something that shouldn't be done is crazy.

-KuJoe

Link to comment
Share on other sites

Link to post
Share on other sites

5 minutes ago, KuJoe said:

Oh so you're suggesting that the system generates passwords based on the new password and compares it to the old password hash in less than 1 second?

This is not computationally expensive. You only need a handful of heuristically generated strings, and hashing and comparing those is incredible fast. You're not trying to compare all permutations of the new password, you're just using a heuristic to generate ones that will prevent 90% of users from using (mostly) repeated passwords.

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

7 minutes ago, reniat said:

This is not computationally expensive. You only need a handful of heuristically generated strings, and hashing and comparing those is incredible fast. You're not trying to compare all permutations of the new password, you're just using a heuristic to generate ones that will prevent 90% of users from using (mostly) repeated passwords.

When milliseconds matter, ain't no time for wasting time on passwords. Whoever is doing that needs to incorporate 2FA and do it right. ;) 

-KuJoe

Link to comment
Share on other sites

Link to post
Share on other sites

Just now, .Ocean said:

AHH so it was a misunderstanding after all. They are not checking the similarity of the hashes, they are attempting to generate the old password by applying slight modifications to the current password supplied and then seeing if that produces the SAME digest that they have on record.

This is most probably what it seems to me, would be easy to implement

Also, not the same to what some sites like github tells you to not use the same password as other services, yours has probably got leaked on some sites, it's a way github tells you should change it by comparing yours to those list.

Link to comment
Share on other sites

Link to post
Share on other sites

57 minutes ago, KuJoe said:

When milliseconds matter, ain't no time for wasting time on passwords.

 

Here's a script I wrote (don't judge on code, it's written fast not clean since I'm at work) which takes <1ms for a few heuristic password changes. Sure a real system would have a few more, but on my machine it's taking <15 ms per run, which is a reasonable amount of time for responding to a user action

 

import hashlib
import random
import time

alpha = "abcdefgijklmnopqrstuvwxyz"

def make_hash(salt, password):
    return hashlib.sha256(salt + password).hexdigest()

oldpassword = "password1"
oldsalt = str(random.randint(0,1000))
oldhash = make_hash(oldsalt, oldpassword)   #after this point, oldpassword isn't used. only the oldhash is known.

newpassword = "password2"

def match_found():
    print("Too similar to previous password")
    
def check_password(generated):
    if (make_hash(oldsalt, generated) == oldhash):
        match_found()
        miliseconds = (time.clock() - start_time)*1000
        print("time taken to calculate: " + str(miliseconds) + " miliseconds.")

start_time = time.clock()

#check for adding a single char
check_password(newpassword[:-1])

#check for numerical similarity at a digit level
for i in range(1,100):
    for j in range(1, 100):
        generated = newpassword.replace(str(i), str(j))
        check_password(generated)

#check for just removing last character
for letter in alpha:
    generated_lower = newpassword + letter
    generated_upper = newpassword + letter.upper()
    check_password(generated_lower)
    check_password(generated_upper)  
for digit in range(10):
    generated = newpassword + str(digit)
    check_password(generated)

Again, this is fugly fast scripting so don't judge too hard lol

 

 

EDIT: I just realized all my timing tests were done where the password was identified quickly in the first block, so it's not THAT fast. It maxes out at ~15ms, which is within the allowed time to process a thing before showing an update to the user. There are also optimizations to be made, especially in the numerical similarity check (could check to see if a given digit exists in the string instead of going through the entire O(100^2) loop, for example).

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

1 hour ago, reniat said:

 

Here's a script I wrote (don't judge on code, it's written fast not clean since I'm at work) which takes <1ms for a few heuristic password changes. Sure a real system would have a few more, but on my machine it's taking <15 ms per run, which is a reasonable amount of time for responding to a user action

 


import hashlib
import random
import time

alpha = "abcdefgijklmnopqrstuvwxyz"

def make_hash(salt, password):
    return hashlib.sha256(salt + password).hexdigest()

oldpassword = "password1"
oldsalt = str(random.randint(0,1000))
oldhash = make_hash(oldsalt, oldpassword)   #after this point, oldpassword isn't used. only the oldhash is known.

newpassword = "password2"

def match_found():
    print("Too similar to previous password")
    
def check_password(generated):
    if (make_hash(oldsalt, generated) == oldhash):
        match_found()
        miliseconds = (time.clock() - start_time)*1000
        print("time taken to calculate: " + str(miliseconds) + " miliseconds.")

start_time = time.clock()

#check for adding a single char
check_password(newpassword[:-1])

#check for numerical similarity at a digit level
for i in range(1,100):
    for j in range(1, 100):
        generated = newpassword.replace(str(i), str(j))
        check_password(generated)

#check for just removing last character
for letter in alpha:
    generated_lower = newpassword + letter
    generated_upper = newpassword + letter.upper()
    check_password(generated_lower)
    check_password(generated_upper)  
for digit in range(10):
    generated = newpassword + str(digit)
    check_password(generated)

Again, this is fugly fast scripting so don't judge too hard lol

 

 

EDIT: I just realized all my timing tests were done where the password was identified quickly in the first block, so it's not THAT fast. It maxes out at ~15ms, which is within the allowed time to process a thing before showing an update to the user. There are also optimizations to be made, especially in the numerical similarity check (could check to see if a given digit exists in the string instead of going through the entire O(100^2) loop, for example).

This assumes that the same salt is used for each password which is extremely bad practise.

 

In my node example every password is given a different salt and this sort of system couldn't work.

 

                     ¸„»°'´¸„»°'´ Vorticalbox `'°«„¸`'°«„¸
`'°«„¸¸„»°'´¸„»°'´`'°«„¸Scientia Potentia est  ¸„»°'´`'°«„¸`'°«„¸¸„»°'´

Link to comment
Share on other sites

Link to post
Share on other sites

42 minutes ago, vorticalbox said:

This assumes that the same salt is used for each password which is extremely bad practise.

 

In my node example every password is given a different salt and this sort of system couldn't work.

 

Not at all. You just use the old salt to look at similarity. Once the new password is validated, you can generate and store a new salt and use it to save the new password hash. My script doesn't actually have a database, so I stopped after validating the password and didn't add code to pretend save to a db, so that's why you only see the "oldsalt" in there.

 

using the context of the script, all you'd need to do after validating is:

newsalt = random.randint(0,1000)
newhash = make_hash(newsalt, newpassword)
fakedatabase.setHashForUser(newhash)
fakedatabase.setSaltForUser(newsalt)

 

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

9 minutes ago, reniat said:

Not at all. You just use the old salt to look at similarity. Once the new password is validated, you can generate and store a new salt and use it to save the new password hash. My script doesn't actually have a database, so I stopped after validating the password and didn't add code to pretend save to a db, so that's why you only see the "oldsalt" in there.

But you always store the last salt meaning it's useless in the event of a breech, as an attacker only needs use a dictionary of password then add the salt and hash and see of it matches the stores hash.

 

I would never allow this to be passed in a code review at work. 

 

 

                     ¸„»°'´¸„»°'´ Vorticalbox `'°«„¸`'°«„¸
`'°«„¸¸„»°'´¸„»°'´`'°«„¸Scientia Potentia est  ¸„»°'´`'°«„¸`'°«„¸¸„»°'´

Link to comment
Share on other sites

Link to post
Share on other sites

6 minutes ago, vorticalbox said:

But you always store the last salt meaning it's useless in the event of a breech, as an attacker only needs use a dictionary of password then add the salt and hash and see of it matches the stores hash.

I think you misunderstand what salts are for. Salts are not meant to prevent accessing data in the event of a breach directly by being hidden, they just need to be secret enough that you can't use a rainbow table to de-hash a breached password hash. 

 

Let's say that the salt was in plain text, and you had a securely hashed password, and an attacker got both. It would take them just as long to brute force that as it would if they just got the password, since they did not have the salt BEFORE they got the password. It's no easier to brute force de-hash(password) than it is de-hash(salt+password) even if you know salt. 

 

The reason salt exists is so that you can't spend years hashing words and them comparing them as soon as a password breach happens. Storing a salt in the same database doesn't make it any less secure, as long as that database isn't accessible outside of a breach situation.

 

Also, if you are not storing your hash, how the heck are you comparing the password attempt when the user logs in? How do you know what to hash and compare if you yourself don't even know the salt?

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

1 hour ago, reniat said:

I think you misunderstand what salts are for. Salts are not meant to prevent accessing data in the event of a breach directly by being hidden, they just need to be secret enough that you can't use a rainbow table to de-hash a breached password hash. 

 

Let's say that the salt was in plain text, and you had a securely hashed password, and an attacker got both. It would take them just as long to brute force that as it would if they just got the password, since they did not have the salt BEFORE they got the password. It's no easier to brute force de-hash(password) than it is de-hash(salt+password) even if you know salt. 

 

The reason salt exists is so that you can't spend years hashing words and them comparing them as soon as a password breach happens. Storing a salt in the same database doesn't make it any less secure, as long as that database isn't accessible outside of a breach situation.

 

Also, if you are not storing your hash, how the heck are you comparing the password attempt when the user logs in? How do you know what to hash and compare if you yourself don't even know the salt?

Have a look and bcrypt I used in my example, it has a password compare function. 

 

You have a number of hash runs not salt storing needed.

                     ¸„»°'´¸„»°'´ Vorticalbox `'°«„¸`'°«„¸
`'°«„¸¸„»°'´¸„»°'´`'°«„¸Scientia Potentia est  ¸„»°'´`'°«„¸`'°«„¸¸„»°'´

Link to comment
Share on other sites

Link to post
Share on other sites

7 minutes ago, vorticalbox said:

not salt storing needed

Bcrypt stores salts.

Link to comment
Share on other sites

Link to post
Share on other sites

1 hour ago, vorticalbox said:

You have a number of hash runs not salt storing needed.

Bcrypt is just abstracting the salt from you. It's still storing the salt as part of the string output of the hash, and it's also possible to retrieve it (it's just probably a really bad design to do so).

 

If you REALLY wanted to make a "similar password" functionality on your site, you would probably not use bcrypt OR be forced to manually extract the salt from it (which is janky AF, unless bcrypt has an API method for you to retrieve it instead of being janky). 

 

But back the original point, it still definitely is storing a salt, just not one you have to manage. 

 

EDIT: actually I found you can generate the salt via bcrypt in a separate step from the hashing itself, meaning you could use gensalt to store it manually just like a more basic login system. You'd obviously only do that if you had requirements around providing the password similarity checker functionality being discussed.

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

9 hours ago, mshaugh said:

Bcrypt stores salts.

But not in a database and that's my main issue.

 

I guess it's time to look into the inner workings of bcrypt.

 

How does it remember what salt to use on what password and how does it remember across reboots and reinstalles?

 

We use it inside docker that's getting clean installs every reboot.

 

Edit: stores it in the output. 

 

Makes sense now and I retract all of my comments perfectly fine to do :P

                     ¸„»°'´¸„»°'´ Vorticalbox `'°«„¸`'°«„¸
`'°«„¸¸„»°'´¸„»°'´`'°«„¸Scientia Potentia est  ¸„»°'´`'°«„¸`'°«„¸¸„»°'´

Link to comment
Share on other sites

Link to post
Share on other sites

1 hour ago, vorticalbox said:

Edit: stores it in the output. 

Like i said, it stores it in the string hash function output. This is still stored in the database. Granted i've only tried the npm bcrypt library, but it SEEMS like in at least that popular bcrypt implementation it's just generating a 29 character salt and concatenating it with the hash when storing it, which means getting the old salt is as easy as

newsalt = hash.substring(0, 29);

 

For proof, here's a small script that extracts the salt from a bcrypt hash, then uses it to hash the same plaintext using the derived salt, and results in the same hash being generated:

const bcrypt = require('bcrypt');
const saltRounds = 10;
const myPlaintextPassword = 'password';
 
var hash = bcrypt.hashSync(myPlaintextPassword, saltRounds);
 
salt = hash.substring(0, 29);
newHash = bcrypt.hashSync('password', salt);
 
if (newHash == hash) {
    console.log("They match!");
    console.log(hash);
    console.log(salt);
    console.log(newHash);
}
else {
    console.log("they don't match...");
}

 

This is my output:

They match!
old hash: $2b$10$jzy2.Y8Q4A0QEMiw43CIKu2mYozm6o6pw5N2WUlIviuT9/JznUM5C
salt: $2b$10$jzy2.Y8Q4A0QEMiw43CIKu
new hash: $2b$10$jzy2.Y8Q4A0QEMiw43CIKu2mYozm6o6pw5N2WUlIviuT9/JznUM5C

 

This isn't a flaw of bcrypt, this is just to illustrate that the salt is not something that must stay out of the database at all costs, and in fact it MUST be retrievable for salted hash comparison to work. Otherwise you have no possible way (outside of brute forcing your own login) to verify that the entered password matches the salted hashed password stored in the DB. I'm not a security expert, and i'm DEFINITELY not a cryptologist(?), but from what I do understand of these systems you MUST be able to retrieve the salt in order to do a comparison. I don't understand how it would be possible to compare hashes without that.

 

EDIT: didn't see your other edit before I posted this. Didn't mean to give you a wall of text you didn't need lol

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

25 minutes ago, reniat said:

Like i said, it stores it in the string hash function output. This is still stored in the database. Granted i've only tried the npm bcrypt library, but it SEEMS like in at least that popular bcrypt implementation it's just generating a 29 character salt and concatenating it with the hash when storing it, which means getting the old salt is as easy as


newsalt = hash.substring(0, 29);

 

For proof, here's a small script that extracts the salt from a bcrypt hash, then uses it to hash the same plaintext using the derived salt, and results in the same hash being generated:


const bcrypt = require('bcrypt');
const saltRounds = 10;
const myPlaintextPassword = 'password';
 
var hash = bcrypt.hashSync(myPlaintextPassword, saltRounds);
 
salt = hash.substring(0, 29);
newHash = bcrypt.hashSync('password', salt);
 
if (newHash == hash) {
    console.log("They match!");
    console.log(hash);
    console.log(salt);
    console.log(newHash);
}
else {
    console.log("they don't match...");
}

 

This is my output:


They match!
old hash: $2b$10$jzy2.Y8Q4A0QEMiw43CIKu2mYozm6o6pw5N2WUlIviuT9/JznUM5C
salt: $2b$10$jzy2.Y8Q4A0QEMiw43CIKu
new hash: $2b$10$jzy2.Y8Q4A0QEMiw43CIKu2mYozm6o6pw5N2WUlIviuT9/JznUM5C

 

This isn't a flaw of bcrypt, this is just to illustrate that the salt is not something that must stay out of the database at all costs, and in fact it MUST be retrievable for salted hash comparison to work. Otherwise you have no possible way (outside of brute forcing your own login) to verify that the entered password matches the salted hashed password stored in the DB. I'm not a security expert, and i'm DEFINITELY not a cryptologist(?), but from what I do understand of these systems you MUST be able to retrieve the salt in order to do a comparison. I don't understand how it would be possible to compare hashes without that.

 

EDIT: didn't see your other edit before I posted this. Didn't mean to give you a wall of text you didn't need lol

All good to get examples :) I mimight try and get this working in our main product seems like a nice feature actually.

                     ¸„»°'´¸„»°'´ Vorticalbox `'°«„¸`'°«„¸
`'°«„¸¸„»°'´¸„»°'´`'°«„¸Scientia Potentia est  ¸„»°'´`'°«„¸`'°«„¸¸„»°'´

Link to comment
Share on other sites

Link to post
Share on other sites

13 minutes ago, vorticalbox said:

All good to get examples :) I mimight try and get this working in our main product seems like a nice feature actually.

Before adding similarity checking on a real site, I would:

1) talk to a security team if you have one to make sure they are on board

2) profile and benchmark your current login to make sure you don't add too much time between input and response (it really shouldn't be an issue, but always measure before/after)

3) I would definitely avoid extracting the salt from the hash, and just store it in another column at the time when the new password is chosen like you would if you weren't using bcrypt. I only did the extraction to prove that it is in fact being stored in the databse. I don't know if that salt+hash concatenation is consistent across all implementations of bcrypt, let alone if it won't change in the future with the one we used here. You're losing some of the benefit of bcrypt (managing salt retrieval for you), but that's the tradeoff to get similarity checking to work in this case. It's not any less secure, just a bit more being written to the DB and retrieved for login, and you still get the benefit of bcrypt's slow hashing. Just keep in mind that bcrypt's slow hashing is going to affect the similarity checking performance, so it's even more important to benchmark.

Gaming build:

CPU: i7-7700k (5.0ghz, 1.312v)

GPU(s): Asus Strix 1080ti OC (~2063mhz)

Memory: 32GB (4x8) DDR4 G.Skill TridentZ RGB 3000mhz

Motherboard: Asus Prime z270-AR

PSU: Seasonic Prime Titanium 850W

Cooler: Custom water loop (420mm rad + 360mm rad)

Case: Be quiet! Dark base pro 900 (silver)
Primary storage: Samsung 960 evo m.2 SSD (500gb)

Secondary storage: Samsung 850 evo SSD (250gb)

 

Server build:

OS: Ubuntu server 16.04 LTS (though will probably upgrade to 17.04 for better ryzen support)

CPU: Ryzen R7 1700x

Memory: Ballistix Sport LT 16GB

Motherboard: Asrock B350 m4 pro

PSU: Corsair CX550M

Cooler: Cooler master hyper 212 evo

Storage: 2TB WD Red x1, 128gb OCZ SSD for OS

Case: HAF 932 adv

 

Link to comment
Share on other sites

Link to post
Share on other sites

In the past my method for handling salts is taking a static value (usually a random set of characters) and have that saved in a file somewhere then I hash that static with another value in the database (like username, e-mail, phone number, or something unique). This way if somebody does dump the database they don't have the salt unless they know which file to look in and have access to the source code (and if they do then it's game over for you anyways). I personally hate it when I see a DB dump with a field named 'salt', but that might just be me. :)

-KuJoe

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×