Hi folks
I'm playing with the PBKDF2 package of Udo: http://www.smalltalkhub.com/#!/~UdoSchneider/PBKDF2 (thanks Udo), but I can't find how to validate a stored hash. Can you point me in the right direction? Thanks Francis |
Looks like you'll have to store the salt when making the original hash of the password.
With that you can do | salt originalPassword userInputPassword originalHash newHash secretKey | salt:='salt'. originalPassword:='password'. userInputPassword:='12345678'. originalHash:=PBKDF2 derivedKeySHA1Password: originalPassword salt: salt. newHash:=PBKDF2 derivedKeySHA1Password: userInputPassword salt: salt. secretKey:= SecureRandom new nextBytes: 16. ((SHA256 new hmac key: secretKey) digestMessage: originalHash) = ((SHA256 new hmac key: secretKey) digestMessage: newHash). We do the double SHA256 HMAC signing of the hashes because of https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/ You can store the #secretKey and each user should get a new #salt every time they change their password and you shouldn't reuse the salts for other users or password. For PBKDF2 there is probably a max (or recommended) salt length but I don't know it. I also don't know anything about the SecureRandom class but it says it on the tin, so maybe it is. Maybe not though. I don't know how to find out. But I don't know that it matters in this instance as its only used for the SHA256 HMAC internally in the comparison function. Hope this helps.
|
Thank you Paul,
Saving the salt is not a big issue but I'd like something more simple. In python I can store the salt with the password see:https://pypi.python.org/pypi/bcrypt/3.1.0 # Hash a password for the first time, with a randomly-generated salt hashed = bcrypt.hashpw(password, bcrypt.gensalt()) and retrieve it subsequently if bcrypt.checkpw(password, hashed): ... print("It Matches!") Are you (smalltalkers) aware of something similar? Thanks again Francis
|
In reply to this post by Paul DeBruicker
Thank you Paul,
Saving the salt is not a big issue but I'd like something more simple. In python I can store the salt with the password see:https://pypi.python.org/pypi/bcrypt/3.1.0 # Hash a password for the first time, with a randomly-generated salt hashed = bcrypt.hashpw(password, bcrypt.gensalt()) and retrieve it subsequently if bcrypt.checkpw(password, hashed): ... print("It Matches!") Are you (smalltalkers) aware of something similar? Thanks again Francis Paul DeBruicker wrote > Looks like you'll have to store the salt when making the original hash of > the password. > > With that you can do > > > | salt originalPassword userInputPassword originalHash newHash secretKey > | > salt:='salt'. > originalPassword:='password'. > userInputPassword:='12345678'. > originalHash:=PBKDF2 derivedKeySHA1Password: originalPassword salt: salt. > newHash:=PBKDF2 derivedKeySHA1Password: userInputPassword salt: salt. > > secretKey:= SecureRandom new nextBytes: 16. > > ((SHA256 new hmac key: secretKey) digestMessage: originalHash) = ((SHA256 > new hmac key: secretKey) digestMessage: newHash). > > > > We do the double SHA256 HMAC signing of the hashes because of > https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/ > > You can store the #secretKey and each user should get a new #salt every > time they change their password and you shouldn't reuse the salts for > other users or password. > > For PBKDF2 there is probably a max (or recommended) salt length but I > don't know it. > > I also don't know anything about the SecureRandom class but it says it on > the tin, so maybe it is. Maybe not though. I don't know how to find out. > But I don't know that it matters in this instance as its only used for the > SHA256 HMAC internally in the comparison function. > > > Hope this helps. > > > Francis wrote >> Hi folks >> >> I'm playing with the PBKDF2 package of Udo: >> http://www.smalltalkhub.com/#!/~UdoSchneider/PBKDF2 >> (thanks Udo), but I can't find how to validate a stored hash. >> Can you point me in the right direction? >> >> Thanks >> Francis -- View this message in context: http://forum.world.st/Validate-password-with-PBKDF2-tp4952973p4953004.html Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com. |
On Fri, Jun 30, 2017 at 12:43:23AM -0700, Francis via Pharo-users wrote:
> Saving the salt is not a big issue but I'd like something more simple. > In python I can store the salt with the password > see:https://pypi.python.org/pypi/bcrypt/3.1.0 Hi, you could try PasswordCrypt: https://github.com/PierceNg/PasswordCrypt Pierce |
In reply to this post by Pharo Smalltalk Users mailing list
Francis,
The hashpw function returns a hash with the salt prepended. So it contains both elements. (See for example explanation at: https://stackoverflow.com/questions/27413248/why-can-bcrypt-hashpw-be-used-both-for-hashing-and-verifying-passwords). You can do the same thing here. Assuming you have a fixed size salt, just prepend it before the hash value. Since the salt is (should be) random, returning it's value does not weaken the security. Using a salt prevents against rainbow table attacks: pre-generated hash values for many possible passwords. (See https://en.wikipedia.org/wiki/Rainbow_table). Cheers, Erik |
In reply to this post by Pharo Smalltalk Users mailing list
I guess I could integrate Udo's PBKDF2 into ApplicationSecurity. See under "Using the CheckPoint" if matches your API you're looking for: Cheers,http://80738163270632.blogspot.com.ar/2014/10/application-security-2-checkpoint.html 2017-06-30 4:43 GMT-03:00 Francis via Pharo-users <[hidden email]>:
|
In reply to this post by Erik Stel
Thanks Pierce and hernanmd
I decided to adopt the solution of the prepended salt as Erik said in the previous post. Here is my code, I hope it can be useful for the community First I hash the password with an empty salt PBKDF2 derivedKeyHashFunction: SHA256 password: 'aSimplePassword' salt: '' iterations: 3000 length: 16 . I would have liked to avoid the empty salt but the message deriveKey needs it. Then I used UUID new as real salt and the string '$$' as separator between the salt and the hashed password. So here is the byte array I'm going to store in my db saltPlusHashedPassword := UUID new , '$$' asByteArray , (PBKDF2 derivedKeyHashFunction: SHA256 password: 'aSimplePassword' salt: '' iterations: 3000 length: 16 ). To validate the password, I retrieve the saltPlusHashedPassword from the db and splitting it hashedPassword := (saltPlusHashedPassword splitOn:('$$' asByteArray)) second. Finally the validation (PBKDF2 derivedKeyHashFunction: SHA256 password: 'aSimplePassword' salt: '' iterations: 3000 length: 16 ) = (ByteArray new, hashedPassword). Note, I have to concatenate ByteArray new with hashedPassword because hashedPassword is not a ByteAttay but a UUID, if you have a smarter way to do it you are welcome. HTH Francis Erik Stel wrote > Francis, > > The hashpw function returns a hash with the salt prepended. So it contains > both elements. (See for example explanation at: > https://stackoverflow.com/questions/27413248/why-can-bcrypt-hashpw-be-used-both-for-hashing-and-verifying-passwords). > > You can do the same thing here. Assuming you have a fixed size salt, just > prepend it before the hash value. Since the salt is (should be) random, > returning it's value does not weaken the security. Using a salt prevents > against rainbow table attacks: pre-generated hash values for many possible > passwords. (See https://en.wikipedia.org/wiki/Rainbow_table). > > Cheers, > Erik -- View this message in context: http://forum.world.st/Validate-password-with-PBKDF2-tp4952973p4953119.html Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com. |
In reply to this post by Erik Stel
Thanks Pierce and hernanmd
I decided to adopt the solution of the prepended salt as Erik said in the previous post. Here is my code, I hope it can be useful for the community First I hash the password with an empty salt PBKDF2 derivedKeyHashFunction: SHA256 password: 'aSimplePassword' salt: '' iterations: 3000 length: 16 . I would have liked to avoid the empty salt but the message deriveKey needs it. Then I used UUID new as real salt and the string '$$' as separator between the salt and the hashed password. So here is the byte array I'm going to store in my db saltPlusHashedPassword := UUID new , '$$' asByteArray , (PBKDF2 derivedKeyHashFunction: SHA256 password: 'aSimplePassword' salt: '' iterations: 3000 length: 16 ). To validate the password, I retrieve the saltPlusHashedPassword from the db and splitting it hashedPassword := (saltPlusHashedPassword splitOn:('$$' asByteArray)) second. Finally the validation (PBKDF2 derivedKeyHashFunction: SHA256 password: 'aSimplePassword' salt: '' iterations: 3000 length: 16 ) = (ByteArray new, hashedPassword). Note, I have to concatenate ByteArray new with hashedPassword because hashedPassword is not a ByteAttay but a UUID, if you have a smarter way to do it you are welcome. HTH Francis
|
This post was updated on .
In reply to this post by Pharo Smalltalk Users mailing list
Francis,
You're using an empty salt when creating the hash. Just prepending a random number does not add much security. Anyone knowing your solution will just prepend a random number. And creating only a few accounts in your system will probably reveal that information as well. A wrong-doer will just use a fake salt and will still be able to try a rainbow table attack. Please use a real random value for the salt. And easiest would be to give it a fixed size. (Don't have an image and/or code available, so this might lead to some pseudo code ;-) To generate a safe password hash which you can store in your db, the following method. It creates a random number (your example of a UUID of 16 bytes) and uses that as a salt for the password hash. Both values are then concatenated and returned as a 'safe' password. This can be stored in your db. generateSafePasswordHashFor: aPassword | salt passwordHash safePasswordHash | salt := UUID new asByteArray. passwordHash := PBKDF2 derivedKeyHashFunction: SHA256 password: aPassword salt: salt iterations: 3000 length: 16. safePasswordHash := salt, passwordHash ^safePasswordHash To validate a user's password you retrieve the safePasswordHash from your db (based on the user's id) and validate the given password against it. For this the salt is retrieved from the safePasswordHash (first 16 bytes because UUID is 16 bytes) and it is then used to calculate the hash of the given password. It should match the second part of the safePasswordHash. validatePassword: aPassword against: safePasswordHash | salt passwordHash | salt := safePasswordHash first: 16. passwordHash := PBKDF2 derivedKeyHashFunction: SHA256 password: aPassword salt: salt iterations: 3000 length: 16. ^safePasswordHash endsWith: passwordHash Hope this helps. For real safety, please add some checks for valid values. Did we receive a valid password? Is the safePasswordHash the correct length (in this case 32 bytes)? You might consider using another salt generator than UUID. Cheers, Erik |
Ah-ha! You are right, the proper way to encrypt is with the salt and then
prepend the salt. Thanks Francis FIY does not give a ByteArray because UUID is a subclass of ByteArray and asByteArray returns self Erik Stel wrote > Francis, > > You're using an empty salt when creating the hash. Just prepending a > random number does not add much security. Anyone knowing your solution > will just prepend a random number. And creating only a few accounts in > your system will probably reveal that information as well. A wrong-doer > will just use a fake salt and will still be able to try a rainbow table > attack. > > Please use a real random value for the salt. And easiest would be to give > it a fixed size. > > (Don't have an image and/or code available, so this might lead to some > pseudo code ;-) > > To generate a safe password hash which you can store in your db, the > following method. It creates a random number (your example of a UUID of 16 > bytes) and uses that as a salt for the password hash. Both values are then > concatenated and returned as a 'safe' password. This can be stored in your > db. > > To validate a user's password you retrieve the safePasswordHash from your > db (based on the user's id) and validate the given password against it. > For this the salt is retrieved from the safePasswordHash (first 16 bytes > because UUID is 16 bytes) and it is then used to calculate the hash of the > given password. It should match the second part of the safePasswordHash. > > Hope this helps. > > For real safety, please add some checks for valid values. Did we receive a > valid password? Is the safePasswordHash the correct length (in this case > 32 bytes)? You might consider using another salt generator than UUID. > > Cheers, > Erik -- View this message in context: http://forum.world.st/Validate-password-with-PBKDF2-tp4952973p4953138.html Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com. |
In reply to this post by Erik Stel
Ah-ha! You are right, the proper way to encrypt is with the salt and then prepend the salt.
Thanks Francis FIY UUID new asByteArraydoes not give a ByteArray because UUID is a subclass of ByteArray and asByteArray returns self
|
In reply to this post by Pharo Smalltalk Users mailing list
Hi Francis,
You write: (Entering teacher mode) This actually means that "UUID new asByteArray" does answer a ByteArray. It will answer (as you mentioned correctly) itself. Since a UUID is a ByteArray it means it will answer a ByteArray (in contrary to your statement). To put it differently: The inheritance relation (UUID being a subclass of ByteArray) is a "IS-A" relation. So any UUID is a ByteArray. This means however the message "asByteArray" did not have to be send of course (it is already a ByteArray). I was not sure the class UUID was actually a subclass of ByteArray when writing my reply. Turns out it is. Cheers, Erik |
In reply to this post by Pharo Smalltalk Users mailing list
Francis,
I can relate to the idea of easily embedding PBKDF2/bcrypt into your code. However the functionality of /managing/ the salt is not specificed in PBKDF2. The spec only covers the actual the hashing part. However wrapping it into a simple to use wrapper is pretty simple. The code below is something I use in my code for example: "Create a new password instance" pwd := KNPassword fromPlaintext: 'secret'. "Now store that instance. It encapsulates hash, generated salt and the load parameter. Because all the load parameters are accessed via methods you can also back them with ivars and have different instances with different load parameters. E.g. for adapting to advances in hash cracking." pwd verify: 'secret'. "Verify the password" CU, Udo 'From Pharo5.0 of 16 April 2015 [Latest update: #50772] on 1 July 2017 at 10:01:05.207245 am'! Object subclass: #KNPassword instanceVariableNames: 'salt hash' classVariableNames: 'PRNG' poolDictionaries: '' category: 'ThreatNews-Core'! !KNPassword methodsFor: 'accessing' stamp: 'UdoSchneider 5/26/2017 11:48'! salt ^ salt ifNil: [ salt := ((1 to: self saltLength) collect: [ :each | self class prng nextInt: 255 ]) asByteArray ]! ! !KNPassword methodsFor: 'accessing' stamp: 'UdoSchneider 7/1/2017 09:58'! iterations ^ 1000! ! !KNPassword methodsFor: 'accessing' stamp: 'UdoSchneider 7/1/2017 09:58'! length ^ 64! ! !KNPassword methodsFor: 'accessing' stamp: 'UdoSchneider 7/1/2017 09:58'! saltLength ^ 16! ! !KNPassword methodsFor: 'accessing' stamp: 'UdoSchneider 7/1/2017 09:57'! hashClass ^ SHA256! ! !KNPassword methodsFor: 'as yet unclassified' stamp: 'UdoSchneider 5/26/2017 11:51'! setPlaintext: aString hash := self hashString: aString! ! !KNPassword methodsFor: 'as yet unclassified' stamp: 'UdoSchneider 5/26/2017 11:52'! verify: aString ^ (self hashString: aString) = hash! ! !KNPassword methodsFor: 'as yet unclassified' stamp: 'UdoSchneider 5/26/2017 11:51'! hashString: aString ^ PBKDF2 derivedKeyHashFunction: self hashClass password: aString salt: self salt iterations: self iterations length: self length! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! KNPassword class instanceVariableNames: ''! !KNPassword class methodsFor: 'as yet unclassified' stamp: 'UdoSchneider 5/26/2017 11:49'! reset PRNG := nil! ! !KNPassword class methodsFor: 'as yet unclassified' stamp: 'UdoSchneider 5/26/2017 11:49'! fromPlaintext: aString ^ self new setPlaintext: aString; yourself! ! !KNPassword class methodsFor: 'as yet unclassified' stamp: 'UdoSchneider 5/26/2017 11:49'! prng ^ PRNG ifNil: [ PRNG := Random new ]! ! |
In reply to this post by Erik Stel
Erik,
> On 1 Jul 2017, at 09:41, Erik Stel <[hidden email]> wrote: > > Hi Francis, > > You write: > > Pharo Smalltalk Users mailing list wrote >> FIY >> >> UUID new asByteArray >> >> does not give a ByteArray because UUID is a subclass of ByteArray and >> asByteArray returns self > > (Entering teacher mode) > This actually means that "UUID new asByteArray" does answer a ByteArray. It > will answer (as you mentioned correctly) itself. Since a UUID is a ByteArray > it means it will answer a ByteArray (in contrary to your statement). > > To put it differently: The inheritance relation (UUID being a subclass of > ByteArray) is a "IS-A" relation. So any UUID is a ByteArray. > > This means however the message "asByteArray" did not have to be send of > course (it is already a ByteArray). I was not sure the class UUID was > actually a subclass of ByteArray when writing my reply. Turns out it is. Not so fast. The discussion started with validating the final result which involved #=. Note that UUID new in: [ :uuid | uuid = (ByteArray readHexFrom: uuid hex) ]. => false UUID new in: [ :uuid | uuid hasEqualElements: (ByteArray readHexFrom: uuid hex) ]. => true SequenceableCollection>>#= fails when the classes/species involved are different, so even though UUID inherits from ByteArray, you cannot easily/naively compare them. Now, using #hasEqualElements: would solve the original problem (PBKDF2 derivedKeyHashFunction: SHA256 password: 'aSimplePassword' salt: '' iterations: 3000 length: 16 ) hasEqualElements: hashedPassword. Sven > Cheers, > Erik > > > > > > -- > View this message in context: http://forum.world.st/Validate-password-with-PBKDF2-tp4952973p4953168.html > Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com. > |
In reply to this post by Erik Stel
Evaluate:
(UUID fromString: '0608b9dc-02e4-4dd0-9f8a-ea45160df641') asByteArray = (ByteArray fromHexString: '0608B9DC02E44DD09F8AEA45160DF641'). Francis Erik Stel wrote > Hi Francis, > > You write: > Pharo Smalltalk Users mailing list wrote >> FIY >> >> UUID new asByteArray >> >> does not give a ByteArray because UUID is a subclass of ByteArray and >> asByteArray returns self > (Entering teacher mode) > This actually means that "UUID new asByteArray" does answer a ByteArray. > It will answer (as you mentioned correctly) itself. Since a UUID is a > ByteArray it means it will answer a ByteArray (in contrary to your > statement). > > To put it differently: The inheritance relation (UUID being a subclass of > ByteArray) is a "IS-A" relation. So any UUID is a ByteArray. > > This means however the message "asByteArray" did not have to be send of > course (it is already a ByteArray). I was not sure the class UUID was > actually a subclass of ByteArray when writing my reply. Turns out it is. > > Cheers, > Erik -- View this message in context: http://forum.world.st/Validate-password-with-PBKDF2-tp4952973p4953174.html Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com. |
In reply to this post by Erik Stel
Evaluate:
(UUID fromString: '0608b9dc-02e4-4dd0-9f8a-ea45160df641') asByteArray = (ByteArray fromHexString: '0608B9DC02E44DD09F8AEA45160DF641'). Francis
|
In reply to this post by Sven Van Caekenberghe-2
Right!
Sven Van Caekenberghe-2 wrote > Now, using #hasEqualElements: would solve the original problem -- View this message in context: http://forum.world.st/Validate-password-with-PBKDF2-tp4952973p4953176.html Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com. |
In reply to this post by Sven Van Caekenberghe-2
Right!
|
In reply to this post by Udo Schneider
That's fine, thanks Udo and thanks for your PBKDF2 code
Francis Udo Schneider wrote > Francis, > > I can relate to the idea of easily embedding PBKDF2/bcrypt into your > code. However the functionality of /managing/ the salt is not specificed > in PBKDF2. The spec only covers the actual the hashing part. However > wrapping it into a simple to use wrapper is pretty simple. -- View this message in context: http://forum.world.st/Validate-password-with-PBKDF2-tp4952973p4953178.html Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com. |
Free forum by Nabble | Edit this page |