I've developed a website that uses ASP.NET membership. Based on comments from previous sites, I decided to encrypt passwords so they could be recovered for users who forgot them.
However, the new site (which now has over 500 registered users) has brought me some criticism that the industry standard is really to hash passwords.
However, after a fairly extensive search, I have been unable to find anything about how to convert existing users' passwords from encrypted to hashed.
I know I can change the web.config file, and new users' passwords will use the new format. But it does nothing to update the existing users.
Note: I previously asked a similar question but mostly just got a debate about which is better, encrypted or hashed. I'm past that discussion but I've been unable to find a way to convert them without losing the hundreds of users already registered.
it seems you already know how to decrypt the passwords and change the web.config file, but you're stuck with how to implement the rest of the process.
using ILSpy, here's how to generate the salt for each user:
byte[] array = new byte[16];
new RNGCryptoServiceProvider().GetBytes(array);
return Convert.ToBase64String(array);
once you have the salt, here's how to generate the password:
byte[] bytes = Encoding.Unicode.GetBytes(pass);
byte[] array = Convert.FromBase64String(salt);
byte[] array2 = new byte[array.Length + bytes.Length];
Buffer.BlockCopy(array, 0, array2, 0, array.Length);
Buffer.BlockCopy(bytes, 0, array2, array.Length, bytes.Length);
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) {
return Convert.ToBase64String(sha1.ComputeHash(array2));
}
where pass is the plain-text password you calculated, and salt is the string calculated in the first code snippet above. the default algorithm is SHA1, if you're wondering why it's being used.
since this is a one-time process, i would write a HTTP handler to manually update the database during a short, scheduled maintenance period - hopefully you have that luxury. (obviously make a backup and test first). you need to update the following fields in the aspnet_Membership table:
Password - calculated above
PasswordFormat - 1
PasswordSalt - calculated above
never had to do anything like this, but hopefully that will get you started :)
IMHO, Greg's response (and the associated comments) on your previous question (Changing passwordFormat from Encrypted to Hashed) is the way to go. Essentially, you want to:
Add a hashed membership provider
Loop through all of the encrypted password users,
For each one decrypt the password, create the hash, store it, delete the encrypted version from the database, and move on.
When you are done, all of the encrypted password users should be converted to hashed.
Maybe I'm missing something here, but it should be pretty simple. Create a process to decrypt the password, then salt accordingly and store the hash of the salt + user's decrypted password in the database. Obviously you don't want to be hashing the user's encrypted password. Don't forget to store the salt too.
Related
I am learning about hashing and encryption and can’t seem to understand this:
Client: New user logs in => Creates password => Sent to a server in plain text
Server: Server generates a random "salt" => plain text and salt are unified => Hash function (e.g. SHA-3) hashes the password+salt into a hash => Hash is stored in DB.
Client: Same user logs out and logs in => Password sent to a server in plain text.
Server: Password needs to re-add the same salt it generated when creating the account to get the same hash.
How does the server generate that same random and unique salt?
Is the salt stored on a different DB altogether?
If a DB is compromised the hackers would also gain access to the salt and just brute force rainbow tables with the salt and unhash them.
The salt that was randomly generated must be stored in the database and linked to the user that logged in. It could be simply added as another column in the user table.
In a typical setting, the salt and the password (or its version after
key stretching) are concatenated and processed with a cryptographic
hash function, and the output hash value (but not the original
password) is stored with the salt in a database
Source: https://en.wikipedia.org/wiki/Salt_(cryptography) retrieved 19/02/21
The generation of the salt depends on which technology you are using. The following stack overflow answer has an example for PHP:
Can we use uniqid() to generate a unique Salt in PHP
The password should also never be sent in plain text to the server. This can be done via HTTPS for example
When the user logs in again. The password is sent to server side along with email.
The email is used to fetch the user record and then the Hash value saved against that email is compared with the new hash (salt + password entered).
The validate function method matches the 2 different hash values and checks if password entered was same or not.
For example, I am using bcrypt in Node JS and it has a method compareSync which matches the entered password with the saved hash
bcrypt.compareSync(password, databaseHash);
I'm reversing an app but I'm not very expert of the AES algorithm.
The application gives the user the opportunity to make an offline login.
The user is asked to provide his username and password
This is the function that is used to store the info of the user
public void EncryptLoginInfo(string username, byte[] secretShared, byte[] salt)
{
byte[] random = calc.GenerateRandomBytes();
byte[] array = aes.Encrypt(secretShared, random);
OfflineLogin loginInfo = new OfflineLogin()
{
Username = username,
SecretShared = array,
Iv = random,
Salt = salt
};
this._userCredentials.StoreOfflineLoginData(username, loginInfo);
}
And this are the info that are stored inside an internal config file of the app. In the example below, the password passed to the encryptLoginInfo is 123
Username: not_important
SecretShared: 4KVrjy1cQVWYpWF7aolpMS0HzhKyFf+9VXauQrXoXVUbf0bGXIDOLDJuSVhYoFo2
Iv:yil4nn02IoKsOnX5KXVsDg==
Salt: 5kJio2VQEqjomHRdQMqRVJ0zkBsmqi8K3NypC2VWJk4
If the user want to make an offline login, he is asked to provide username and his password.
Question: Is this algo safe? If an attacker is able to obtain SecretShared+Iv+Salt is he able to recover the password of the user (that in this specific example is 123)
This is the decrypt function
public void DencryptLoginInfo(OfflineLogin loginInfo)
{
byte[] array = aes.Decrypt(loginInfo.SecretShared, loginInfo.Iv);
loginInfo.SecretShared = array;
loginInfo.Iv = (byte[]) null;
}
Are you able to spot any security issues in this implementation? The algo used should be AES-256.. Are you able to implement a POC in python to decrypt the PASSWORD given SecretShared+Iv+Salt?
According to your comment, your goal is to authenticate the user. For that we use password base key derivation functions on the password. Often people refer to this as "hashing passwords", which is unfortunate terminology because "hashing" can mean anything. But the main point is that we do not encrypt passwords, instead we send them through a one-way function that is designed to be slow. The slow speed deters brute force attacks.
You do not need an IV to do this. Instead, your app should be deriving a salt and and using a password based key derivation function (sometimes referred to as a "password hashing" algorithm: you will have to excuse that the industry has made a mess out of the terminology on this topic). You can find guidance on this all over the web. But I suggest you have a read of point 4 in Top 10 Developer Crypto Mistakes to see common pitfalls in implementing this.
Don't use openssl to convert a password into a key (or password hash)! The algorithm in openssl is weak. Openssl's EVP_BytesToKey() fails to meet the requirements of slow speed, meaning that it is easy to brute force your key from your password.
The proper solution to this problem is to use an algorithm such as bcrypt or pbkdf2 (Java implementations can be found without much effort) to derive a "hash" from the password. You then verify that the user typed in the password correctly by re-doing the same computation with the user entered password and the salt that was stored for this password. If they match, access is granted, otherwise access is denied.
Note that if this app interacts with a server, normally you do password verification on the server side. If your app does not interact with a server, then you may have a good reason to do it on the device. I don't know what your app does, so I cannot tell you what is right or wrong for you.
A great reference for doing this properly is How to Safely Store Your Users' Passwords in 2016 .
I found on this forum some very interesting content for problem that I have, but I don't found answer for my question.
To change encryption password I can use command:
cryptsetup luksChangeKey /dev/sda2
... and that works. But how to encrypt /dev/sda2 partition again with new password?
If my old password is compromised and I only change password, stored data is encrypted with old password not with new.
The LUKS partition itself is not encrypted with your password: it is encrypted with a strong "master key" randomly calculated upon volume creation. Your old and new passwords only serve to encrypt the "master key". Unfortunately both passwords and the "master key" as often referred to as "keys" hence your (and others') confusion.
When in the old days cryptsetup did not rely on LUKS, every time you changed your cryptsetup password the entire disk would have to be re-encrypted!
Nowdays you only have to change your master key if someone also gains physical or administrative access to the encrypted device while the password is valid.
p.s. if not relying on temporary storage but having free space, the LUKS master key may be "changed" by shrinking a LUKS volume via "cryptsetup resize", creating another volume, moving data, deleting the first volume and expanding the second volume.
A client program (over which I have no control) is authenticating by sending me a password, hashed as SHA1(password).
I'm reluctant to store the password hashed using only SHA1 in my database, so I'm proposing to store passwords in the database hashed as SHA256(SHA1(password)) (where the password is hashed over multiple iterations using PBKDF-2 or something similar).
My question is: is there anything insecure about the inner-most hash using SHA1 in this scenario? I realise that the probability of collisions will be increased, but since this is just for storing passwords in the database I don't think I need to be concerned about that. Is there anything else that I'm missing?
Consider adding a salt which is unique-per-row before doing the final encryption. Example:
Lets say that you receive W6ph5Mm5Pz8GgiULbPgzG37mj9g= (a SHA1'd encryption of "password"). That is associated with a User, who should have a unique key, such as a UserID and/or UserName.
My suggestion - to avoid collision - would be to do a conversion of the Bytes to a Base64String (in C# this would be Convert.ToBase64String( byteVariable ) - then concatenate onto the string the user's unique-ID (making the new string something like:
W6ph5Mm5Pz8GgiULbPgzG37mj9g=+103 (where I added +103 to reflect the user's ID) - then apply your SHA256 algorithm. This will produce: mNXRjWsKJ7V+BHbAuwJJ7neGT+V1IrLQSQXmb4Vv1X8= - which you can store in your database. A SHA256 hash - which eliminates the collisions from the less-safe SHA1 algorithm.
And - since you are using 1-way encryption - when you go to check whether the password is valid in the future, you simply append the user's ID again before checking.
If the client always sends you the same password, simply SHA1 hashed, then the SHA1 hash output is the password, to all intents and purposes. Treat it and store it the same way you would any other password, such as by using PBKDF2, SCrypt, or BCrypt.
An old version of an application has some passwords stored in the clear in its database. I have written an updated version that encrypts the passwords when new entries are made, but I don't have direct access to the database to manually encrypt the entries that already exist. When the update goes live, it will try to decrypt the plaintext passwords, and crash.
Short of doing something drastic like deleting all the existing data, the only other approach I can think of is this (wrapper pseudocode called when the password data is used.):
# data refers to the password data, either encrypted or plain
if data length < AES.block_size:
# (Shorter than initialization vector, definitely not encrypted.)
open database and replace password entry with encrypt(data)
login(username, data)
else:
try: # try plaintext first
login(username, data)
except AuthenticationError:
login(username, decrypt(data))
else: #plain text worked, encrypt data for future use.
open database and replace password entry with encrypt(data)
It seems a shame to keep this code around to solve a problem that goes away after it runs once. Is there any other approach that might work to ensure the passwords are encrypted and only decrypt the ones that need it?
In this scenario I do one of the following, depending on the client and the system involved:
Set up the encrypted password code, delete all existing passwords, and make everyone enter a new password. I prefer this because the passwords were plain and over time may have been seen or shared.
Run a one-time script to encrypt every password in the system. This way there is never a mix.
Have newer encrypted passwords prefixed with the encryption method, e.g. "SHA1:". You run the risk of someone having that same text as the start of their password, but it is unlikely.