BCrypt generated + hard-coded Salt: Is this more safety? - cryptography

I found a blog post about BCrypt and I'am not sure what is the Benefit ob adding the hard-coded Salt "^Y8~JJ" to the password?
The 'hashToStoreInDatabase' containing the salt and the crypted password, but not the hard-coded salt 'Y8~JJ'. So, if somebody steal the database it's useless for the hacker to generate an own rainbowtable with the salt (containing in the database) and the hashed password, because they never get the hard-coded salt 'Y8~JJ'.
(I knew that is already safety to save the salt and passwordhash togheter, because a rainbowtable is expencive to generate)
Is this using of BCrypt recommended?
Quote from: https://www.codeproject.com/articles/475262/useplusbcryptplustoplushashplusyourpluspasswords
private void SetPassword(string user, string userPassword)
{
string pwdToHash = userPassword + "^Y8~JJ"; // ^Y8~JJ is my hard-coded salt
string hashToStoreInDatabase = BCrypt.HashPassword(pwdToHash, BCrypt.GenerateSalt());
using (SqlConnection sqlConn = new System.Data.SqlClient.SqlConnection(...)
{
sqlConn.Open();
SqlCommand cmSql = sqlConn.CreateCommand();
cmSql.CommandText = "UPDATE LOGINS SET PASSWORD=#parm1 WHERE USERNAME=#parm2";
cmSql.Parameters.Add("#parm1", SqlDbType.Char);
cmSql.Parameters.Add("#parm2", SqlDbType.VarChar);
cmSql.Parameters["#parm1"].Value = hashToStoreInDatabase;
cmSql.Parameters["#parm2"].Value = user;
cmSql.ExecuteNonQuery();
}
}
private bool DoesPasswordMatch(string hashedPwdFromDatabase, string userEnteredPassword)
{
return BCrypt.CheckPassword(userEnteredPassword + "^Y8~JJ", hashedPwdFromDatabase);
}

It is actually called pepper. The salt is stored in DB, but pepper is stored somewhere else then DB.
The Wikipedia states as;
A pepper performs a comparable role to a salt, but while a salt is not secret (merely unique) and can be stored alongside the hashed output, a pepper is secret and must not be stored with the output. The hash and salt are usually stored in a database, but a pepper must be stored separately (e.g. in a configuration file) to prevent it from being obtained by the attacker in case of a database breach.
When the database hacked, the attacker cannot access the pepper, as a result, password search would be impossible even for weak passwords.
In short, yes recommended.
However, Bcrypt is old. One should use Argon2 as the winner of the password hashing competition.

Related

I want to used md5 encryption method for password field in login form instead of existing bcrypt encryption method?

I have completed login functionality using Auth middleware where is used a Bcrypt encryption method. Login functionality is works fine. But we need to handle set password functionality with having old password need to validate. But everytime Bcrypt method change the password string so the previous store bcrypt string of password in table is not match with the manually enter password in the set password form. So how to validate old password field if it will not match with existing saved passoword in the table.
$credentials = request(['email', 'password']);
$user=Auth::attempt($credentials);
You are using Laravel so you should use Hash in order to deal with passwords.
Here is all you need to know about it: https://laravel.com/docs/6.x/hashing#basic-usage
In short you can create and verify the passwords in following ways:
Create hashed password to store in DB:
$hashedPassword = Hash::make($request->password);
Verify against existing password
if (Hash::check('entered-password-by-user', $hashedPassword)) {
// The passwords match...
}
Of course dont forget to include Hash facade: use Illuminate\Support\Facades\Hash;
md5 is ancient and very vulnerable way to go if you want to hash your passwords with it. It is HIGHLY DISCOURAGED!

Itextsharp Encryption without password is not working properly

I am trying to use itextsharp writer.setEncryption method with nothing to encrypt file without password but it is setting password for some random pdf even if I have passed nothing to encrypt it.
pdf.SetEncryption(Nothing, Nothing, PdfWriter.AllowScreenReaders, PdfWriter.STRENGTH40BITS)
It is working properly.
Please have a look at the documentation of the method you used:
/** Sets the encryption options for this document. The userPassword and the
* ownerPassword can be null or have zero length. In this case the ownerPassword
* is replaced by a random string. The open permissions for the document can be
* AllowPrinting, AllowModifyContents, AllowCopy, AllowModifyAnnotations,
* AllowFillIn, AllowScreenReaders, AllowAssembly and AllowDegradedPrinting.
* The permissions can be combined by ORing them.
* #param userPassword the user password. Can be null or empty
* #param ownerPassword the owner password. Can be null or empty
* #param permissions the user permissions
* #param strength128Bits <code>true</code> for 128 bit key length, <code>false</code> for 40 bit key length
* #throws DocumentException if the document is already open
*/
virtual public void SetEncryption(byte[] userPassword, byte[] ownerPassword, int permissions, bool strength128Bits)
So if you don't give a value for the owner password, the documented behavior is that a random string is used, exactly as you observed.
Apparently you try to set the permissions of the PDF to only PdfWriter.AllowScreenReaders, but setting this permission selection is only possible for encrypted files, and for encryption a non-empty owner password is required, so iText chooses one for you.
An empty user password on the other hand is possible because in the course of its use during encryption and decryption a "default password string" is appended to the user password value anyways.
Addendum
In answer to questions in comments...
What does "is replaced by a random string" mean exactly? And in what format would that password be?
if (ownerPassword == null || ownerPassword.Length == 0)
ownerPassword = DigestAlgorithms.Digest("MD5", CreateDocumentId());
(PdfEncryption method SetupAllKeys)
where CreateDocumentId is defined like this:
public static byte[] CreateDocumentId() {
long time = DateTime.Now.Ticks + Environment.TickCount;
long mem = GC.GetTotalMemory(false);
String s = time + "+" + mem + "+" + (seq++);
byte[] b = Encoding.ASCII.GetBytes(s);
return DigestAlgorithms.Digest("MD5", b);
}
Can you still retrieve the password somehow?
The password is not explicitly stored anywhere for later retrieval. In this situation, i.e. a call for encryption using an empty owner password, it is assumed that the caller is not interested in knowing the password.
If this sounds weird to you, please be aware that for the actual encryption of document data the user password is used, not the owner password. (More exactly a value derived from the user password.) The owner password during document encryption only is used to encrypt the user password (more exactly, a value derived from it) and store that value in the PDF.
When the PDF is opened again and the user provides a password, it is tested whether it can immediately be used for document data decryption (i.e. it is the user password) or whether it can be used to decrypt the above mentioned value to the user password which then can decrypt the document (i.e. it is the owner password).
In either case the user has access to the PDF but if it was only the user password, not the owner password, the PDF processor is expected to restrict the allowed operations according to a given permissions value.
Thus, a caller not giving an owner password here is interpreted to be not interested in anyone having full access to the PDF in a specification conforming PDF processor, for restricted access the user password suffices. This has nothing to do with making the document undecryptable due to a lost password...
Would it use one of the indicated key strengths?
Well, MD5 returns a 128 bit hash but as the structure of the hashed data is well known, the password is by far not as strong as a truly random 128 bis value. On the other hand an eight character string usually also is by far not as strong as that...

password History for Identity Core

is there any default implementation for password history? i'm trying to implement that feature on my project with identity so i have added password history table which contain password hashes. when user change password usermanager generate hash for password.
var passwordHash = _userManager.PasswordHasher.HashPassword(user, newPassword);
if this hash does not inserted in password history table it allow to change password otherwise return error
but the problem is each time when generating hash for the specific password it generate random hashes which cannot be compare also
var passwordHash = _userManager.PasswordHasher.HashPassword(user, newPassword);
hash differ from
_userManager.ResetPasswordAsync(user, request.Token, password);
generated password hash.
May be i'm trying to do this in wrong way. what was the mistake i have done implementing password history?
thanks
Different hashes every time - it's how default implementation IPasswordHasher works. Look at this answer for more details: https://stackoverflow.com/a/20622428/6104621.
So, for your implementation password history, you can either implement IPasswordHasher or just verify a new password with all stored passwords hashes using method
PasswordVerificationResult VerifyHashedPassword(TUser user, string hashedPassword, string providedPassword);
Just for example:
var passAlreadyExist = user.UserHistory
.Select(h => h.PasswordHash)
.Distinct()
.Any(hash =>
{
var res = manager.PasswordHasher.VerifyHashedPassword(user, hash, password);
return res == PasswordVerificationResult.Success;
});
where UserHistory - it's custom table with some user info like password, email, name...

AJAX login: check password, how to get it to work with md5

this is my code, it works, except for the passwords, how would I fix this? I know I should do something with md5 but I couldn't get found solutions to work with my code. I really need to make this right and safe, please assist
//get the posted values
$username=htmlspecialchars($_POST['user_name'],ENT_QUOTES);
$password=htmlspecialchars($_POST['password'],ENT_QUOTES);
$check_for_username = $mysqli->query("SELECT username FROM q4jli_users WHERE username='$username' AND password=MD5('$password')");
if (mysqli_num_rows($check_for_username)) {
echo "yes";
} else {
echo "no";
}
Thanks in advance
MD5 is outdated and no longer a sufficient method of password encryption. You should investigate salted hashes using more modern encryption algorithims.
food for thought:
bcrypt
First of all, you need to make sure that a user's password is encrypted into the database with MD5. If not, then you can use this code:
$mysqli->query("INSERT INTO q4jli_users (username, password) VALUES ('$username', MD5('$password'))");
Then, when seeing if a user enters the correct password, you need to encrypt it to MD5 and then run a query in the database:
$check_for_username = $mysqli->query("SELECT username FROM q4jli_users WHERE username='$username' AND password=MD5('$password')");

PasswordHasher updating user information

The PasswordHasher takes in a generic TUser and then takes the user's object for hashing and verifying, something like this:
var result = hash.VerifyHashedPassword(user, HashedPassword, Password);
string HashedPassword = hash.HashPassword(user, Password);
So I am assuming the user data is used to hash the password and then to verify. But doesn't this mean I need to rehash the password? If so, wouldn't that mean each time the user changes any of his account info he also needs to re-enter his password or is there a way around it where I can rehash it without asking the user for his password?