I am building my classes for development and am working on an encryption class. I have been reading up on php's crypt function and the different encryption types but a few areas have been vaguely explained.
my understanding is there are these encryption options CRYPT_STD_DES, CRYPT_EXT_DES, CRYPT_MD5, CRYPT_BLOWFISH, CRYPT_SHA256, and CRYPT_SHA512. to see if they are enabled you just check
if(CRYPT_FOO==1)
{
//is enabled
}
Questions
What are the salt requirements/format for the different encryption other than the.
blowfish requirements which is on SO.
And just for clarification I assume if you use a blowfish salt with crypt() it automatically does the blowfish encryption?
The official documentation of the crypt function has quite some information about the various modes, and what should be passed as their salt parameter:
CRYPT_STD_DES: two character salt from the alphabet ./0-9A-Za-z, i.e. an 12 bit salt.
CRYPT_EXT_DES: a _ character, then a 4 character iteration count, then a 4 character salt (each using the same alphabet).
CRYPT_MD5: a marker $1$, then 9 more salt characters (using the same alphabet as above, I suppose).
CRYPT_BLOWFISH: a marker $2a$, then a two digit cost parameter in the range 04 to 31 (meaning 24 to 231 iterations), then $ and a 22-digit salt (again, using the same alphabet as above).
CRYPT_SHA256: a marker $5$, an optional round parameter indication of rounds=number$ (with a decimal number between 1000 and 999999999), and a 16-character salt (using the same alphabet as above).
CRYPT_SHA512: a marker $6$, an optional round parameter indication of rounds=number$ (with a decimal number between 1000 and 999999999), and a 16-character salt (using the same alphabet as above).
The start of the salt parameter uniquely identifies which kind of password hash algorithm is to be used here - so yes, if you use a salt in the bcrypt format (starting with $2a$), it will automatically use bcrypt.
Related
I'm using
password_hash($password, PASSWORD_BCRYPT);
to encrypt passwords to store in a database. As I read, there's no length limit on generated hashes, but I need to know the maximum length so I can use it to define the field in my database which can fit all password hashes (in a worst case scenario).
If I put a limit of 20 characters for the password in plain text, how long will the password_hash() result will be?
From the password_hash documentation:
The following algorithms are currently supported:
PASSWORD_DEFAULT - Use the bcrypt algorithm (default as of PHP 5.5.0).
Note that this constant is designed to change over time as new and
stronger algorithms are added to PHP. For that reason, the length of
the result from using this identifier can change over time. Therefore,
it is recommended to store the result in a database column that can
expand beyond 60 characters (255 characters would be a good choice).
PASSWORD_BCRYPT - Use the CRYPT_BLOWFISH algorithm to create the hash.
This will produce a standard crypt() compatible hash using the "$2y$"
identifier. The result will always be a 60 character string, or FALSE
on failure.
Therefore, using PASSWORD_BCRYPT, the result of password_hash will be a 60 character string.
The result of BCrypt will always be a 60 character string. Limitless is only the input for the function, that means you do not (and should not) set a limit to the entered passwords.
Actually BCrypt internally uses only about 72 characters, but it accepts passwords of any length.
If you want to use the function in its future proof form like this (notice the PASSWORD_DEFAULT)...
password_hash($password, PASSWORD_DEFAULT);
...then you should make your database field bigger. Newer PHP versions may replace BCrypt with another default hash algorithm, which may generate longer hashes.
I am using Crypt() in PHP to encrypt passwords.
Let's say salt is "bg",
Password is: "gg456456gg"
Encrypted result gives: "bgvQk9C2Pv27o"
But if I use password: "gg456456" - without two last characters, it gives same result.
Because of this, users are able to login without typing 100% exact password.
What's happening? I mean gg456456 and gg456456gg are two different passwords, why is encrypted result same?
Php.net on function crypt()
The standard DES-based crypt() returns the salt as the first two
characters of the output. It also only uses the first eight characters
of str, so longer strings that start with the same eight characters
will generate the same result (when the same salt is used).
So use a different encryption method.
Such as blowfish or sha-512. These will accept much longer strings
E.g. SHA-512:
$encpassword = crypt($password,"$6$".$salt);
Used the method above (and same salt):
gg456456 -> $6$631080661$L2o7HNKfYrqB4H19vYe7fRWWLenQj2EcWqriNG9rX6ki1QKO2YytkylrYmZ8mhIr6XE19Ms4RW2of5Z/dsYRA/
gg456456gg -> $6$631080661$maGxQ2d7ZIPIdXDFN1sJJsIjTFEwD9dL/uljSXdKXeJU4E5miCzh1ZCao57sGDm9PrDhdPYPLGUvoy0HzTfqI.
Use a good random-number generator for your salt and voila you have a well encrypted password
The original crypt function on Unix systems only uses the first 8 characters of the password. Eventually we decided that was insecure and have switched to more secure password hashes.
The PHP crypt function selects the algorithm to use based on the salt you supply, and a two character alphanumeric salt like you used triggers that original crypt algorithm.
See http://php.net/manual/en/function.crypt.php for the list of algorithms and respective salts.
I have been doing some research on creating some different hashes, etc. I am aware of the password_hash() function, however I'm currently creating an initialization value using mcrypt. The issue that is arising is some of the hashed password being clipped if the password is larger than 8 characters.
My current code adds a salt (created by mcrypt_create_iv()) to a users password. Afterwards it is encrypted using the hash() function. The criteria for a password is anywhere from 8->40 characters.
My column in MySQL looks like varchar (64) using latin1_swedish_ci collation.
How would I calculate the maximum length (MySQL length) that the initialization value could be, as well as the maximum length for the user-inputted password?
Disclaimer: I purposefully left out the encryptions, but will appreciate any documentation for different cipher block init value lengths as well as hash lengths. (Not sure the terminology, hope that makes sense.)
Hash functions as well as password_hash() - which implements different Password Based Key Derivation Functions (PBKDF) using either a HMAC or a ciphered MAC - always return the same amount of data for any input value. If the password is being truncated then that is because of code that happens before any of these functions is called. Normally these functions return 20 bytes if you use SHA-1.
Of course the salt value needs to be stored as well.
If you store that using hexadecimals then you need twice the number of characters compared to the binary value. If you utilize base 64 encoding you need ( (size + 2) / 3 * 4 ) characters if you include padding.
So your password can be as long or short as wanted, the salt takes one byte (encoding) per byte.
It is strongly recommended that you also store some kind of indicator of the function used. That may be a single byte indicating your current protocol. That way you can upgrade your password protocol per entry once a user returns to fill out his (new) password.
I am not sure which algorithm crypt() uses when hashing. I looked on the PHP manual, but it just says that it uses whatever is available. But how do I know which one it uses, and if it does use one, how to tell it which one to use? I am using MAMP currently as my development environment, but I figure there must be a way to find out with a statement in PHP.
You specify the algorithm as part of the salt string. For example, starting with $2a$ gives you a Blowfish cypher. If the machine does not support the algorithm you are trying to use, you won't get a meaningful result. You can attempt to find out in advance which algorithms are supported by checking some of the predefined constants, such as CRYPT_BLOWFISH, although I have noticed that the constants CRYPT_SHA256 and CRYPT_SHA512 are not always defined, at least on PHP 5.2. Starting with PHP 5.3, PHP has its own implementations of the algorithms, so it does not matter what the system has available at PHP compile time like it does in PHP 5.2 and earlier. The Suhosin patch for PHP 5.2 supposedly adds at least Blowfish, but its implementation does not seem to be compatible with the one used in PHP 5.3.
The PHP docs for the crypt() function do provide some information on how to use the salt string to specify which algorithm to use:
CRYPT_STD_DES - Standard DES-based hash with a two character salt
from the alphabet "./0-9A-Za-z". Using invalid characters in the salt
will cause crypt() to fail.
CRYPT_EXT_DES - Extended DES-based
hash. The "salt" is a 9-character string consisting of an underscore
followed by 4 bytes of iteration count and 4 bytes of salt. These are
encoded as printable characters, 6 bits per character, least
significant character first. The values 0 to 63 are encoded as
"./0-9A-Za-z". Using invalid characters in the salt will cause crypt()
to fail.
CRYPT_MD5 - MD5 hashing with a twelve character salt
starting with $1$
CRYPT_BLOWFISH - Blowfish hashing with a salt as
follows: "$2a$", a two digit cost parameter, "$", and 22 digits 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.
CRYPT_SHA256 - SHA-256 hash with a sixteen character salt prefixed
with $5$. If the salt string starts with 'rounds=$', the numeric
value of N is used to indicate how many times the hashing loop should
be executed, much like the cost parameter on Blowfish. The default
number of rounds is 5000, there is a minimum of 1000 and a maximum of
999,999,999. Any selection of N outside this range will be truncated
to the nearest limit.
CRYPT_SHA512 - SHA-512 hash with a sixteen
character salt prefixed with $6$. If the salt string starts with
'rounds=$', the numeric value of N is used to indicate how many
times the hashing loop should be executed, much like the cost
parameter on Blowfish. The default number of rounds is 5000, there is
a minimum of 1000 and a maximum of 999,999,999. Any selection of N
outside this range will be truncated to the nearest limit.
So, to specify that you want the string "password" hashed using Blowfish with 2^10 iterations, you could use
crypt('password', '$2a$10$XA86t7EJ0xD9OYEUbnTulT');
where the string starting with XA86 is the salt.
Finally, if you want more examples or just want something to take care of all this password compatibility business for you, take a look at phpass. It is public domain and works nicely in my experience. It will automatically use the "best" algorithm on the system unless you specify that you want a hash that is compatible with multiple systems, in which case (I think) it uses MD5.
I'm using crypt() encryption in PHP like this:
<?php
$password = sanitizing_func($_POST['password']);
$var = crypt($password, 'ab');
?>
How Secure is this?
Found a better solution here: openwall phpass
Thanks to Edward Thomson
It's less secure than if you just use crypt the way it was designed, with the password as the first argument and the salt as the second.
Now you're encrypting known plaintext using the user's password as the salt. If your system uses an MD5 crypt, then you've just limited the salt space to 12 characters, so you're truncating the space of users passwords to twelve characters. Worse still, my system requires me to use a prefix on the salt in order to specify my crypt, or else I get old school crypt, meaning you have two characters for the salt. So you've limited the possible length of a users password to two characters. Plus there's no point in even running crypt at this point, you might as well just store their two character password, since the salt is prefixed to the ciphertext so that subsequent calls to crypt can pass the same salt.
Also, you're limiting the character space of the password by using it in the salt, since the character space of the salt is limited to A-Z, a-z, 0-9, ".", "/". Even if you switch the arguments around from your code example, you're using the same salt data for every call. This means that every password has the same salt. So if your password table is exposed, it becomes less computationally expensive to crack using a dictionary attack.
In other words, swapping the password and salt arguments is a fatal mistake.
Finally, there's simply no reason to call crypt twice. If you want better encryption, use a better algorithm, don't call it more frequently. For example, if you're using a DES crypt, then it's still an ancient algorithm no matter how many times you call it. (I also seem to remember reading that multiple passes of an algorithm may inadvertently produce weakened ciphertext. But I don't have Schneier in front of me.)
What you want to do is the industry standard: use a strong crypt, pass the password as the first argument and random salt data in as the second argument and make sure that you're passing the maximum allowable number of bytes in for the salt.