I have a external service which wishes to create user via a bespoke API that I have created in my Laravel application.
Rather than the remote end sending me the password in plain text I would like the remote end to hash the password first however I am unsure on how of the hashing using.
The remote end is using ASP.NET to make things slightly more complicated.
I am guessing Laravel is using CRYPT_BLOWFISH as that is the strongest available on the server but unsure how the salt works. Could anyone advise?
http://php.net/manual/en/function.crypt.php
CRYPT_BLOWFISH - Blowfish hashing with a salt as follows: "$2a$", "$2x$" or "$2y$", a two digit cost parameter, "$", and 22 characters from the alphabet "./0-9A-Za-z". Using characters outside of this range in the salt will cause crypt() to return a zero-length string. The two digit cost parameter is the base-2 logarithm of the iteration count for the underlying Blowfish-based hashing algorithmeter and must be in range 04-31, values outside this range will cause crypt() to fail. Versions of PHP before 5.3.7 only support "$2a$" as the salt prefix: PHP 5.3.7 introduced the new prefixes to fix a security weakness in the Blowfish implementation. Please refer to ยป this document for full details of the security fix, but to summarise, developers targeting only PHP 5.3.7 and later should use "$2y$" in preference to "$2a$".
Example hash from Laravel:
$2y$10$RXyfF5/5qdBeGbwKgU5NR.p1OcgT5t3N.M5ql5PHm.UoxYGOogDWi
2y = blowfish prefix
10 = cost parameter
RXyfF5/5qdBeGbwKgU5NR. = 22 char salt
p1OcgT5t3N.M5ql5PHm.UoxYGOogDWi = bcrypt hash
Related
I am using the Laravel Hash Facade to generate a hash. This is then passed to a 3rd party service which uses the same hash in a callback. I use this to ensure that the request is "trusted". However, the Hash::make() creates a 60 character long string, but the 3rd party service only allows 32 characters.
If I apply md5() to the hash, I won't be able to use the Hash::check(). If i use substr(), then two - or more - hashes can result in the same string.
What is the best way to handle this scenario, in a secure way?
By default, Laravel Hash uses the password_hash() function with the BLOWFISH cypher, which generates the 60 character result. The 60 character result, however, is actually 28 characters of parameters, and the resulting 32 character hash.
The first 28 characters consists of the 4 character prefix ($2y$), the 2 digit cost (04 - 31), and the 22 character salt. If you store this first 28 characters in your application somewhere (ex. .env file), you can use it to check the 32 character hashes you generate and receive from the third party.
The password_hash() function is a built-in wrapper around the crypt() function, but it generates it's own salt dynamically. Since Laravel doesn't provide a way to provide the salt manually, you won't be able to use the Hash::make() method; you'll need to use the crypt() method directly, and pass in the proper data to trigger using the BLOWFISH cipher with your static salt. The generated results are still compatible with the password_verify() function, though, so you will still be able to use Hash::check() to verify the received hash (or just use password_verify() directly).
Below is hopefully a more helpful illustration with code and comments.
// This tells crypt() to use the BLOWFISH cypher
$prefix = '$2y$';
// This tells crypt() the number of rounds for the BLOWFISH algorithm to use.
// The higher the number, the longer it takes to generate a hash (good).
// Value must be two digits and between 04 and 31. 10 is default.
$cost = '10';
// This is the 22 character salt (including start and end dollar signs). This is
// the value normally dynamically generated by password_hash(), but you
// are storing a static value in your application.
$salt = '$thisisahardcodedsalt$';
// Concat the three parameters to generate the full 28 character BLOWFISH
// prefix. Instead of using the hardcoded variables above, you would
// probably just get the value out of the config (set by .env file).
$blowfishPrefix = $prefix.$cost.$salt;
// I don't know where your password is coming from, but this is the password
// that you were planning on using for your Hash::make() and Hash::check()
// calls.
$password = 'This is your password.';
// Hash the password to get your 60 character BLOWFISH cipher result.
$hash = crypt($password, $blowfishPrefix);
// The real hash is the last 32 characters. This is the value you pass to your
// third party service.
$hashToThirdParty = substr($hash, -32);
// Now we've generated a hash and sent it to the third party. Now we wait.
// ... at some point, the third party sends the hash back to you.
$hashFromThirdParty = $hashToThirdParty;
// Add your stored BLOWFISH prefix to the hash received from the third party,
// and pass the result into Hash::check() (along with your password).
$verified = Hash::check($password, $blowfishPrefix.$hashFromThirdParty);
// Since we're not using Hash::make() to generate the password, you may not care
// about using Hash::check() to check it. You can just use the underlying
// password_verify() function at this point, if you want.
$altVerified = password_verify($password, $blowfishPrefix.$hashFromThirdParty);
PHP function resources:
password_hash()
crypt()
password_verify()
Laravel code resources:
Hash::make() for the bcrypt hasher
Hash::check() for the bcrypt hasher
We're building a system to validate mobile phone numbers.
To achieve this, when a user adds his number, we are sending him a text message with a 6 digit code.
We don't want this code to go in our database as we don't like to clutter our database with fields that have no business meaning.
So we came up with the idea to reuse pragmarx/google2falibrary, have it generate an OTP code, dispatch it to the user by a text message, and then the circle would be round.
So basically we wanted to use the phone number, prefixed by somehting secret as the "secret" for the pragmarx/google2fa library:
$secret = '1263' . $mobile->country_code . $mobile->subscriber;
$google2fa = new Google2FA();
$google2fa->setEnforceGoogleAuthenticatorCompatibility(false);
$google2fa->getCurrentOtp($secret);
The above results in a secretsimilar to 12633232970987. However, the call to getCurrentOtp throws an exception Invalid characters in the base32 string. which is obviously not what I was hoping for.
So, I tried adding
$secret = base_convert($secret, 10, 32)
and pass that to the getCurrentOtpmethod, but that returned the same error. Checking into the library code, I see the following constant:
const VALID_FOR_B32 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
My base_convert returns a string that has other characters in there though. Are these really the only valid characters?
My alternative would be to just have the library generate a random secret, but we don't really want to do that, as that would require us to keep that secret somewhere in the database (or at least in cache), which we would like to avoid. The idea is that we could generate the code for a mobile number using the number as the secret, and let the OTP mechanism deal with expiring codes.
Anyone has any suggestion how I can resolve this?
I am using Laravel's bcrypt function for hashing passwords. When I do,
bcrypt('secret')
I get
=> "$2y$10$mnPgYt2xm9pxb/c2I.SH.uuhgrOj4WajDQTJYssUbTjmPOcgQybcu"
But if I run it again, I get
=> "$2y$10$J8h.Xmf6muivJ4bDweUlcu/BaNzI2wlBiAcop30PbPoKa0kDaf9xi"
and so on...
So, won't the password matching process fail if I get different values every time?
This is how bcrypt is supposed to work. See wikipedia.
Bcrypt generates a random 128-bit salt during hashing. This salt becomes part of the hash, hence we always get a different hash value for the same input string. The random salt is actually used to deter brute-force attacks.
The password matching process won't fail due to different values of hashes.
Try the following in tinker
$hash1 = bcrypt('secret')
$hash2 = bcrypt('secret')
Hash::check('secret', $hash1)
Hash::check('secret', $hash2)
You should get true in both the cases of Hash::check.
So even if the hash values are different, the password matching won't fail.
Bcrypt uses a 128-bit salt and encrypts a 192-bit magic value. It takes advantage of the expensive key setup in eksblowfish.
The bcrypt algorithm runs in two phases, sketched in Figure 3. In the first phase, EksBlowfishSetup is called with the cost, the salt, and the password, to initialize eksblowfish's state. Most of bcrypt's time is spent in the expensive key schedule. Following that, the 192-bit value ``OrpheanBeholderScryDoubt'' is encrypted 64 times using eksblowfish in ECB mode with the state from the previous phase. The output is the cost and 128-bit salt concatenated with the result of the encryption loop.
How it works in laravel :
if (! function_exists('bcrypt')) {
/**
* Hash the given value against the bcrypt algorithm.
*
* #param string $value
* #param array $options
* #return string
*/
function bcrypt($value, $options = [])
{
return app('hash')->driver('bcrypt')->make($value, $options);
}
}
Supported options for PASSWORD_BCRYPT:
salt (string) - to manually provide a salt to use when hashing the password. Note that this will override and prevent a salt from being automatically generated.
If omitted, a random salt will be generated by password_hash() for each password hashed. This is the intended mode of operation.
Warning The salt option has been deprecated as of PHP 7.0.0. It is now
preferred to simply use the salt that is generated by default.
cost (integer) - which denotes the algorithmic cost that should be used. Examples of these values can be found on the crypt() page.
If omitted, a default value of 10 will be used. This is a good baseline cost, but you may want to consider increasing it depending on your hardware.
How Bcrypt encryption and decryption works:
Internally bcrypt() use uses PHP's built-in password_hash() function. password_hash() returns different values each time because it appends a random string (a "salt") to the password. The salt is actually contained in the output hash.
If the same password is hashed with the same salt, you will always get the same output. Therefore password_verify() looks at the stored hash, extracts the salt, and then hashes the given password with that same salt.
AIX, like other Unix, only store a salted hash of user password.
In the old days, it uses to use DES crypt, and then a (slighty different version of) MD5 Crypt, the same that you will find on Linux.
With more recent version of AIX and the use of /etc/security/passwd, you can use new SHA1/SHA256/SHA512 hashes. They look like that (with example hash string result for the password "secret"):
- salted sha1 : {ssha1}12$tyiOfoE4WXucUfh/$1olYn48enIIKGOOs0ve/GE.k.sF
- salted ssha256: {ssha256}12$tyiOfoE4WXucUfh/$YDkcqbY5oKk4lwQ4pVKPy8o4MqcfVpp1ZxxvSfP0.wS
- salted ssha512: {ssha512}10$tyiOfoE4WXucUfh/$qaLbOhKx3fwIu93Hkh4Z89Vr.otLYEhRGN3b3SAZFD3mtxhqWZmY2iJKf0KB/5fuwlERv14pIN9h4XRAZtWH..
The config file /etc/security/pwdalg.cfg explain the the number after {algo_name} is the "num_cost", and we can get the number of iteration used in the hashing function with 2^num_cost.
I need to generate valid hash from a Scala application that are latter place in /etc/security/passwd.
I tried to adapt commons-codec Sha2Crypt (https://commons.apache.org/proper/commons-codec/apidocs/src-html/org/apache/commons/codec/digest/Sha2Crypt.html) witch implements the official Sha-Crypt algorithm (https://www.akkadia.org/drepper/SHA-crypt.txt), but that give the wrong hash.
Anybody knows what should be done ?
The short answer is that, appart for md5, which is the standard unix implementation and differs only for the prefix ({smd5} in place of "$1", the other implementations differ SIGNIFICANTLY from standard Unix crypt described at https://www.akkadia.org/drepper/SHA-crypt.txt. In fact, they only kept:
the number of bytes (and so chars) for the hash: 20 for ssha1, 32 for ssha256, 64 for ssh512
the base64 encoding table (which is not the standard one but starts with "./012" etc
What changed is:
they use PBKDF2 HMAC-(sha1, sha256, sha512) in place of Sha-Crypt,
they use a different padding table
the number of iterations, named "rounds" in Unix crypt vocabulary, is not the number N found at the begining of the hash string (after the algo name). The number of iteration is actually 2^N, and N is called in /etc/security/pwdalg.cfg the "cost"
A valid Scala implementation can be found in Rudder's AixPasswordHashAlgo.scala here: https://github.com/Normation/rudder/blob/master/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/cfclerk/domain/AixPasswordHashAlgo.scala
Maybe this is a stupid question, but I wouldn't be shocked if some excellent brains come around with a proper solution or an idea: Is it possible to recalculate/transcode a salted sha512 string into a salted blowfish string ?
The (imo quite interesting) background is: I have a big database of SHA512+salt strings like that $6$rounds=5000$usesomesillystri$D4IrlXatmP7rx3P3InaxBeoomnAihCKREY4... (118 chars) and want to move to another hash/salt algorithm, generating strings like $2a$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi (60 chars).
I'm intentionally NOT asking this on security.stackexchange.com as this is not a security question. It's about transcoding/recalculation.
Is it possible to recalculate/transcode a salted sha512 string into a salted blowfish string ?
Nope.
SHA2-512 is a cryptographic hash. Data goes in, but there's no way to get it back out. Do note that the thing you're using is a proposed but not standardized form of crypt that uses SHA2, and is not a raw SHA2 hash.
bcrypt (which is derived from, but is not Blowfish) is a key derivation function, which while a different thing than a cryptographic hash, still has the same result: data goes in, but there's no way to get it back out.
There is no way to simply convert one of these password hash types to another. This is true of almost every hash type. If you need to change the hash type, do so when the user next logs in.