What's the safest encryption I can use for a user to login to my program? - md5

I'm writing a program and before it loads I want the user to enter the correct password without storing the password anywhere in my code. I've implemented MD5 hashes before but from what I've read they're outdated and can be broken. There are a few sites out there that attempt to reverse engineer and MD5 hash. What's the strongest encryption I can use to keep prying eyes out of my program (e.g., The NSA)?

"Encryption" is not the right thing to do for storing user passwords - as by design an encrypted password can be decrypted. As you said - hashing is the way to go.
MD5 is outdated, and I believe the current recommendation is sha1.
Note that there are ways to reverse any hashing algorithm to acceptable input. The commonly accepted standard to make this much more dificult is to add a unique "salt" to all passwords before putting them through the hashing function. A common mistake made when adding salts to passwords is to use the same salt value on every password in the database.
When salting passwords, use a unique value, for example the user ID, or the created date/time string for the user record. This will prevent attacks based on rainbow tables because there will be no existing ready to use rainbow table for your stored password hashes.
I personally like the approach of using the created date / time string of the user as it's a value that should never change and will be available and will likely be different for each user the the database.
Eexamples below assume you are familiar with PHP - however the concepts can be applied to any language.
Example:
Before saving a new user into the database:
$date = date('Y-m-d H:i:s');
// save this same value into the user record somewhere
$passwordHash = sha1($user['created_date'].$_POST['password']);
// and save the $passwordHash value into the password field for that user
To authenticate a login attempt, use something like the following:
function authenticateUserLogin($email, $password) {
$user = $db->fetchRow('SELECT * FROM users WHERE email=?', array($email));
if (!$user) return false;
$passwordHash = sha1($user['created_date'].$password);
return $user['password_hash'] !== $passwordHash;
}
To update an existing users password, use something like...
$passwordHash = sha1($user['date_created'].$newPassword);
$db->query('UPDATE users set password_hash=? WHERE id = ?', array($passwordHash, $user['id']));

Related

Are there known issues with the C function crypt()?

I use crypt() to encrypt passwords for a project of mine. When the password is chosen by the user, it's encrypted like this:
password = crypt(<password chosen>, <user's account name>)
The problem is when the user logs in using their password. If what they type doesn't match their password, it should enter this if check:
if (strcmp(crypt(<what user types in as password>, <user's account name>), <user's encrypted password>)) {
//...
}
It doesn't in one certain scenario. Let's say their password is 'asdf'. If they enter 'asdf' with any random trailing characters, such as 'asdffffff' or 'asdf339sfd', it still accepts the password. It seems to ignore everything after 'asdf'.
Is this a known issue with crypt? Is there another way to encrypt passwords?
The second argument to crypt is not supposed to be the user's account name. It's supposed to be a setting string. Setting strings look like this:
$2b$07$fQuDK3TaQP4sw6IX6iVcTw
The $2b$07$ part tells crypt which password-hashing algorithm to use, and the string of random characters that follows is the salt. The salt must be different for each user, but it is not supposed to have any correlation with the user's account name. It doesn't technically have to be random, but it's critical that it be different for each user, and it needs to change every time the user changes their password, so best practice is to use a long string drawn from a cryptographic PRNG.
When you authenticate a user who has logged in before, you use the stored hashed password as the setting string:
char *new_hash = crypt("password typed in", "stored hash");
if (new_hash && !strcmp(new_hash, "stored hash")) {
// user has successfully logged in
}
This works because the stored hashed password always begins with the setting string that was used to create it in the first place, and crypt is coded to look only at the setting-string part.
(Also note the null check; some implementations of crypt can fail and report failure by returning a null pointer.)
When you create a new account or change a password, you have to generate a new setting string. If you have the function crypt_gensalt, use that:
char *new_setting = crypt_gensalt("$2b$", 0, 0, 0);
if (new_setting) {
char *new_hash = crypt("user's new password", new_setting);
// ...
} else {
// halt and catch fire
}
If you don't have crypt_gensalt you have to implement it yourself, unfortunately. (To make matters worse, some Unixes have the crypt_gensalt whose documentation I linked to above, and others have a different version, with the same name, doing the same job, but taking different arguments. Time to dust off your Autoconf skillz!)
Now you know all of that, I can explain why
password = crypt("password chosen", "user's account name");
appeared to work but truncated the password. Your user account names probably begin with at least two alphanumeric characters, right? Like, "Ma[ya]", or "zw[ol]"? Unfortunately, any two alphanumeric characters make a valid setting string ... that selects one of the oldest and least secure password-hashing algorithms known to science, descrypt. (It was pretty good when it was invented ... in the mid-1970s. Nowadays, it can be cracked by brute force no matter what the password is.) One of the many problems with this algorithm is that it truncates all passwords to eight characters. asdf and asdfhjkl hash to different things, but asdfhjkl and asdfhjkl1234 hash to the same thing.
The cure for this is to use crypt_gensalt or equivalent to select a modern algorithm. All the modern algorithms accept arbitrarily long passphrases.

How to save variables on access storage without a table?

I've protected delete queries on my forms with a password (did it with some VBA) and I let the user change the password so I can't just compare it to a text when I ask the user to enter the password, is there any way I could save the password variable on access storage without a table?
currently, I'm saving the password on a table with one field and doing the comparisons at the background...
It's a school project.
I would suggest hashing the password and storing the hash in your table; then, when the user enters a password, hash the entered password and compare the result with the stored hash.
This approach has the benefit that no passwords are stored in human readable format, and the hashing process cannot be reversed to yield the plain text password from the stored hash (one could only brute-force guess the password and compare the resulting hash).
You can save the password, but better password hash as advised #Lee Mac in the database properties. Property can be changed at any time by code. Change remains in the database file after database closing.
Create property:
Function CreatePropery()
Dim DB As Database
Dim P As Property
Set DB = CurrentDb
Set P = DB.CreateProperty("MyPassword", DB_TEXT, "MyInitialPassword")
DB.Properties.Append P
End Function
Get current password:
Function GetPasswod()
GetPasswod = CurrentDb.Properties![MyPassword]
End Function
Set new password:
Function SetPassword(strNewPassword As String)
CurrentDb.Properties![MyPassword] = strNewPassword
End Function

Log users into eXist-db using MD5 password (XQuery)

I need to log users into eXist-db using XQuery. Of course I can use this code:
xquery version "3.0";
declare namespace exist = "http://exist.sourceforge.net/NS/exist";
declare namespace request="http://exist-db.org/xquery/request";
declare namespace xmldb="http://exist-db.org/xquery/xmldb";
declare option exist:serialize "method=json media-type=text/javascript";
let $userName := request:get-parameter("userName", ())
let $hash := request:get-parameter("hash", ())
let $login := xmldb:authenticate('/db', $userName, $hash)
return
<ajax-response>
<success>{$login}</success>
<username>{$userName}</username>
</ajax-response>
The problem is that, due to the fact that I receive the password and the username from another service, I receive them in hash form encrypted with MD5 (because they can't be passed in clear from a service to another).
But the xmldb:authenticate function needs the password in clear. How can I resolve this? Any idea? Is there a way to login 'manually' in eXist-db without using the authenticate function?
No, this is not possible: eXist-db does not work with hashes on the authentication functions, that would be a security risk since MD5 is not safe. In addition, eXist-db does not use MD5 internally for hashing the passwords, so validating a password would be difficult (matching two different hashing techniques is impossible)
Unfortunately there is no way to work around this with the standard functions.

convert mysql query to cake php find

i have a mysql query as below :
select * from users where email='xxx#xxx.com' and password = SHA1(CONCAT(SHA1(SHA1("123456")),salt))
i want to convert to cake PHP find using beforSave Function :
public function beforeFind(array $queryData) {
if(isset($queryData['conditions']['User.password'])) {
$queryData['conditions']['User.password'] = 'SHA1(CONCAT(SHA1(SHA1("'.$queryData['conditions']['User.password'].'")),User.salt))';
}
$this->log($queryData);
return $queryData;
}
the mysql query is run okie but in cakephp find this not work.
Thank for help.
Don't include plain-text passwords in your queries!
You should never do this; you're including plain-text passwords as part of your query and including your 'salt' values as readable string as well.
SQL queries may be logged (and backed up), so those log files can contain all this information in readable format!
You should 'hash' the password using PHP and use the hashed password to query your database
Hashing passwords via the AuthComponent
First of all, if you're using the AuthComponent, CakePHP will do all this kind of actions automatically; it will look up/identify a user and (if correct) allow you to log-in that user.
See: Authentication
To encrypt passwords 'manually', use AuthComponent::Password() or Security::hash()
I'm in a hurry right now, but if you need more information or an example, place a comment, then I will add that information
If I have understood your problem correctly then you want to search for a user with given username and password. You don't need to use beforeSave for this. If you want to encode password then surely you could use beforeFind or IMO you can do it in a single line itself, just before you execute the query.
You can use Cakephp find by query method. Something like this $this->Users->query("your mysql query"); or if you want to use normal find, that would also work.
$user = $this->Users->find('first', array(
'conditions' => array('Users.email' => $email, 'Users.password' => $password)
));
Hope that helps.

what are the rules that apply on the key_name in app engine?

I'm trying to use an app engine User object's user_id (returned by the User.user_id() method) as a key_name in my own User class. The problem is that it keeps telling me that it's an invalid key_name. I've tried sha2'ing it, and using the digest() as well as the hexdigest() method to reduce the number of possible characters, but still no good result. Is this because the value is too long, or because key names can't have certain characters? And also, how can I modify a user_id in such a way that it stays unique, but is also usable as a key_name for an entity? Extra bonus if it uses a hash so that thje user_id can't be guessed.
Here is the code where the error occured:
def get_current_user():
return User.get(db.Key(hashlib.sha1(users.get_current_user().user_id()).hexdigest()))
I'm now doing some more testing, concidering suggestions from the comments and answer.
I'm not sure why it isn't working for you, the following has no issues when I run it in the dev console.
from google.appengine.ext import db
from google.appengine.api import users
user = users.get_current_user()
name = user.user_id()
print db.Key.from_path ('User', name)
However if you are hashing it (which it sounds like you may be), be aware that you may get a collision. I would avoid against using a hash and would consider some other means of anonymization if you are giving the key to clients. Such as another model whose key you can give away, that has the user's key stored in it. Another method would be to encrypt the id (using the same key for all users) rather than hash it.
If you are doing something that generates binary data (encryption / hash digest) app engine (the sdk at-least) has issues, so you need to encode it first, and use that as the key_name.
name = user.user_id()
hashed_name = hashlib.sha1(name).digest()
encoded_name = base64.b64encode (name)
db.Key.from_path ('User', encoded_name)

Resources