How to match crowd database passwords? - pbkdf2

I would like to have a piece of code that is able to check if a given password match the one stored in the crowd cwd_user table.
The passwords in that table starts with "{PKCS5S2}..." and I found in the link below that crowd is using the PBKDF2 algorithm:
The default is "Atlassian Security", which is currently a dumb wrapper around Bouncy Castle's implementation of PKCS 5 version 2 (aka PBKDF2), using a random 16 byte salt, 10, 000 iterations, and generating a 256-bit hash as the final output
https://answers.atlassian.com/questions/235858/password-security
Is anybody able to provide me a method I can use to match that password?
For example, if I create a user "toto" with password "1234", I get the following row in my database :
user_name credential
------------- -------------------------------------------------------------------------
toto {PKCS5S2}m+u8ed1RKRew3jjHPilZw0ICL6BG/qyeN+kVRRS9nsO+VK7Q5I0vCK3gLvCFWC3n
I would like a method such that:
public String getHash(String rowPassword){
// ?????
}
where
getHash("1234") returns "{PKCS5S2}m+u8ed1RKRew3jjHPilZw0ICL6BG/qyeN+kVRRS9nsO+VK7Q5I0vCK3gLvCFWC3n"

As a Crowd customer, you have access to the class AtlassianSecurityPasswordEncoder which is exactly that.
The underlying encoder chooses a random salt, ignoring the one passed in, so encodePassword won't give you the same hash each time. Use isPasswordValid to confirm that the password and hash match.

Related

Generating and Storing API Keys - Node js [duplicate]

So with lots of different services around now, Google APIs, Twitter API, Facebook API, etc etc.
Each service has an API key, like:
AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q
All the keys vary in length and the characters they contain, I'm wondering what the best approach is for generating an API key?
I'm not asking for a specific language, just the general approach to creating keys, should they be an encryption of details of the users app, or a hash, or a hash of a random string, etc. Should we worry about hash algorithm (MSD, SHA1, bcrypt) etc?
Edit:
I've spoke to a few friends (email/twitter) and they recommended just using a GUID with the dashes stripped.
This seems a little hacky to me though, hoping to get some more ideas.
Use a random number generator designed for cryptography. Then base-64 encode the number.
This is a C# example:
var key = new byte[32];
using (var generator = RandomNumberGenerator.Create())
generator.GetBytes(key);
string apiKey = Convert.ToBase64String(key);
API keys need to have the properties that they:
uniquely identify an authorized API user -- the "key" part of "API key"
authenticate that user -- cannot be guessed/forged
can be revoked if a user misbehaves -- typically they key into a database that can have a record deleted.
Typically you will have thousands or millions of API keys not billions, so they do not need to:
Reliably store information about the API user because that can be stored in your database.
As such, one way to generate an API key is to take two pieces of information:
a serial number to guarantee uniqueness
enough random bits to pad out the key
and sign them using a private secret.
The counter guarantees that they uniquely identify the user, and the signing prevents forgery. Revocability requires checking that the key is still valid in the database before doing anything that requires API-key authorization.
A good GUID generator is a pretty good approximation of an incremented counter if you need to generate keys from multiple data centers or don't have otherwise a good distributed way to assign serial numbers.
or a hash of a random string
Hashing doesn't prevent forgery. Signing is what guarantees that the key came from you.
Update, in Chrome's console and Node.js, you can issue:
crypto.randomUUID()
Example output:
'4f9d5fe0-a964-4f11-af99-6c40de98af77'
Original answer (stronger):
You could try your web browser console by opening a new tab, hitting CTRL + SHIFT + i on Chrome, and then entering the following immediately invoked function expression (IIFE):
(async function (){
let k = await window.crypto.subtle.generateKey(
{name: "AES-GCM", length: 256}, true, ["encrypt", "decrypt"]);
const jwk = await crypto.subtle.exportKey("jwk", k)
console.log(jwk.k)
})()
Example output:
gv4Gp1OeZhF5eBNU7vDjDL-yqZ6vrCfdCzF7HGVMiCs
References:
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey
I'll confess that I mainly wrote this for myself for future reference...
I use UUIDs, formatted in lower case without dashes.
Generation is easy since most languages have it built in.
API keys can be compromised, in which case a user may want to cancel their API key and generate a new one, so your key generation method must be able to satisfy this requirement.
If you want an API key with only alphanumeric characters, you can use a variant of the base64-random approach, only using a base-62 encoding instead. The base-62 encoder is based on this.
public static string CreateApiKey()
{
var bytes = new byte[256 / 8];
using (var random = RandomNumberGenerator.Create())
random.GetBytes(bytes);
return ToBase62String(bytes);
}
static string ToBase62String(byte[] toConvert)
{
const string alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
BigInteger dividend = new BigInteger(toConvert);
var builder = new StringBuilder();
while (dividend != 0) {
dividend = BigInteger.DivRem(dividend, alphabet.Length, out BigInteger remainder);
builder.Insert(0, alphabet[Math.Abs(((int)remainder))]);
}
return builder.ToString();
}
An API key should be some random value. Random enough that it can't be predicted. It should not contain any details of the user or account that it's for. Using UUIDs is a good idea, if you're certain that the IDs created are random.
Earlier versions of Windows produced predictable GUIDs, for example, but this is an old story.

Cant use original password, after hash (pgcrypto)

I have succeded in hashing my password for my admin user, the problem is now that i can no longer use the original password to log in (no errors, exept the correct response for invalid passwords). I am able to to select the user table and just copy in the hashed password from PGadmin (using PostgreSQL). Im not really sure where to go from here.
1. I think i have to get my login form to recognize the hashed password, and somehow match it up with the original.
2. figure out how to add salt and pepper to the hash
I am not looking for the exact solution, but maybe some hints to get further :)
Code
function createAdmin(){
var usertypeid = null;
const type = "adm";
pool.query(`INSERT INTO usertype(type) VALUES ($1) RETURNING userTypeId;`, [type], function (error, results) {
if (error){
throw error;
} else{
usertypeid = results.rows[0].usertypeid;
console.log(usertypeid);
insertAdmin();
}
});
function insertAdmin(){
pool.query(`
INSERT INTO users(
usertypeid, userName, email, password)
VALUES($1, 'admin', 'admin#admin.com', CRYPT('admin', GEN_SALT('md5')));`, [usertypeid]);
}
}
As mentioned in the comments, don't use MD5 anymore as it's deprecated a long time ago.
The other thing is that hashing is different from encrypting. You can't decrypt a hash like you do with a cipher.
What should happen is that you run the plaintext through the hashing algorithm and then see if it matches the original hash computed at the beginning.
For Node.js there are good libraries out there like bcrypt which can be used to simplify the process and perhaps make it more secure.
If you insist to perform your own validation procedure, then it should be like the following:
Get the user's password from the login form
Run it through the hashing algo of your choice (no MD5 please)
Query the database for the hashed password
Compare if the hashed password from the login form is the same as the one in the DB
As the docs say, you want something like this (renaming table and columns to match your example):
SELECT (password = crypt('entered password', password)) AS pswmatch FROM users where username='admin';
The value stored in users.password from your insertion is a combination of the algorithm, the salt, and result of hashing the actual password with that algorithm and salt. Now you pass users.password into crypt again, so that it can extract from it the algorithm and the salt. It then uses that algorithm and salt to recompute the hash of the alleged password. If the re-computed value matches the stored value, then the alleged password is correct.

Yii2 - how to properly use generatePasswordHash()?

I'm trying to generate a random password for a user in a Yii2 application.
I have the following code:
$rand_password = Yii::$app->security->generateRandomString(8);
$user->password = Yii::$app->security->generatePasswordHash($rand_password);
After that I save the $user model and the hashed string is also saved in the database. However, I cannot log in with the $rand_password string after that as I'm getting Invalid Password error message.
The generatePasswordHash description says that the hash is generated from the provided password and a random salt string. Indeed, I called the function with the same password string several times in a row and I got different result every time. So my question is, if that salt string is random and different every time, how can I use this function at all to verify passwords? When I try to login I call the same function with the password string provided by the user but this time the salt will be different so I'm unable to produce the same hash as before? What am I missing here?
Well, after hours of debugging and looking for resources and explanation, it turns out the the user module I'm using: https://github.com/amnah/yii2-user is actually automatically hashing the passwords before saving them in the database. In other words, as soon as you call:
$user->password = SOMETHING;
that SOMETHING is automatically going through the generatePasswordHash() function upon save. My problem was that I was dropping it in there in my code as well so basically the password got hashed twice.

What's the best approach for generating a new API key?

So with lots of different services around now, Google APIs, Twitter API, Facebook API, etc etc.
Each service has an API key, like:
AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q
All the keys vary in length and the characters they contain, I'm wondering what the best approach is for generating an API key?
I'm not asking for a specific language, just the general approach to creating keys, should they be an encryption of details of the users app, or a hash, or a hash of a random string, etc. Should we worry about hash algorithm (MSD, SHA1, bcrypt) etc?
Edit:
I've spoke to a few friends (email/twitter) and they recommended just using a GUID with the dashes stripped.
This seems a little hacky to me though, hoping to get some more ideas.
Use a random number generator designed for cryptography. Then base-64 encode the number.
This is a C# example:
var key = new byte[32];
using (var generator = RandomNumberGenerator.Create())
generator.GetBytes(key);
string apiKey = Convert.ToBase64String(key);
API keys need to have the properties that they:
uniquely identify an authorized API user -- the "key" part of "API key"
authenticate that user -- cannot be guessed/forged
can be revoked if a user misbehaves -- typically they key into a database that can have a record deleted.
Typically you will have thousands or millions of API keys not billions, so they do not need to:
Reliably store information about the API user because that can be stored in your database.
As such, one way to generate an API key is to take two pieces of information:
a serial number to guarantee uniqueness
enough random bits to pad out the key
and sign them using a private secret.
The counter guarantees that they uniquely identify the user, and the signing prevents forgery. Revocability requires checking that the key is still valid in the database before doing anything that requires API-key authorization.
A good GUID generator is a pretty good approximation of an incremented counter if you need to generate keys from multiple data centers or don't have otherwise a good distributed way to assign serial numbers.
or a hash of a random string
Hashing doesn't prevent forgery. Signing is what guarantees that the key came from you.
Update, in Chrome's console and Node.js, you can issue:
crypto.randomUUID()
Example output:
'4f9d5fe0-a964-4f11-af99-6c40de98af77'
Original answer (stronger):
You could try your web browser console by opening a new tab, hitting CTRL + SHIFT + i on Chrome, and then entering the following immediately invoked function expression (IIFE):
(async function (){
let k = await window.crypto.subtle.generateKey(
{name: "AES-GCM", length: 256}, true, ["encrypt", "decrypt"]);
const jwk = await crypto.subtle.exportKey("jwk", k)
console.log(jwk.k)
})()
Example output:
gv4Gp1OeZhF5eBNU7vDjDL-yqZ6vrCfdCzF7HGVMiCs
References:
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey
I'll confess that I mainly wrote this for myself for future reference...
I use UUIDs, formatted in lower case without dashes.
Generation is easy since most languages have it built in.
API keys can be compromised, in which case a user may want to cancel their API key and generate a new one, so your key generation method must be able to satisfy this requirement.
If you want an API key with only alphanumeric characters, you can use a variant of the base64-random approach, only using a base-62 encoding instead. The base-62 encoder is based on this.
public static string CreateApiKey()
{
var bytes = new byte[256 / 8];
using (var random = RandomNumberGenerator.Create())
random.GetBytes(bytes);
return ToBase62String(bytes);
}
static string ToBase62String(byte[] toConvert)
{
const string alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
BigInteger dividend = new BigInteger(toConvert);
var builder = new StringBuilder();
while (dividend != 0) {
dividend = BigInteger.DivRem(dividend, alphabet.Length, out BigInteger remainder);
builder.Insert(0, alphabet[Math.Abs(((int)remainder))]);
}
return builder.ToString();
}
An API key should be some random value. Random enough that it can't be predicted. It should not contain any details of the user or account that it's for. Using UUIDs is a good idea, if you're certain that the IDs created are random.
Earlier versions of Windows produced predictable GUIDs, for example, but this is an old story.

Password hashing - how to upgrade?

There's plenty of discussion on the best algorithm - but what if you're already in production? How do you upgrade without having to reset on the user?
EDIT/DISCLAIMER: Although I originally wanted a "quick fix" solution and chose orip's response, I must concede that if security in your application is important enough to be even bothering with this issue, then a quick fix is the wrong mentality and his proposed solution is probably inadequate.
One option is to make your stored hash include an algorithm version number - so you start with algorithm 0 (e.g. MD5) and store
0:ab0123fe
then when you upgrade to SHA-1, you bump the version number to 1:
1:babababa192df1312
(no, I know these lengths probably aren't right).
That way you can always tell which version to check against when validating a password. You can invalidate old algorithms just by wiping stored hashes which start with that version number.
If you've already got hashes in production without a version number, just choose a scheme such that you can easily recognise unversioned hashes - for example, using the above scheme of a colon, any hash which doesn't contain a colon must by definition predate the versioning scheme, so can be inferred to be version 0 (or whatever).
A cool way to secure all the existing passwords: use the existing hash as the input for the new, and better, password hash.
So if your existing hashes are straight MD5s, and you plan on moving to some form of PBKDF2 (or bcrypt, or scrypt), then change your password hash to:
PBKDF2( MD5( password ) )
You already have the MD5 in your database so all you do is apply PBKDF2 to it.
The reason this works well is that the weaknesses of MD5 vs other hashes (e.g. SHA-*) don't affect password use. For example, its collision vulnerabilities are devastating for digital signatures but they don't affect password hashes. Compared to longer hashes MD5 reduces the hash search-space somewhat with its 128-bit output, but this is insignificant compared to the password search space itself which is much much smaller.
What makes a password hash strong is slowing down (achieved in PBKDF2 by iterations) and a random, long-enough salt - the initial MD5 doesn't adversely affect either of them.
And while you're at it, add a version field to the passwords too.
EDIT: The cryptography StackExchange has an interesting discussion on this method.
Wait until your user logs in (so you have the password in plaintext), then hash it with the new algorithm & save it in your database.
One way to do it is to:
Introduce new field for new password
When the user logs in check the password against the old hash
If OK, hash the clear text password with the new hash
Remove the old hash
Then gradually you will have only passwords with the new hash
You probably can't change the password hashing scheme now, unless you're storing passwords in plain text. What you can do is re-hash the member passwords using a better hashing scheme after each user has successfully logged in.
You can try this:
First add a new column to your members table, or which ever table stores passwords.
ALTER TABLE members ADD is_pass_upgraded tinyint(1) default 0;
Next, in your code that authenticates users, add some additional logic (I'm using PHP):
<?php
$username = $_POST['username'];
$password = $_POST['password'];
$auth_success = authenticateUser($username, $password);
if (!$auth_success) {
/**
* They entered the wrong username/password. Redirect them back
* to the login page.
*/
} else {
/**
* Check to see if the member's password has been upgraded yet
*/
$username = mysql_real_escape_string($username);
$sql = "SELECT id FROM members WHERE username = '$username' AND is_pass_upgraded = 0 LIMIT 1";
$results = mysql_query($sql);
/**
* Getting any results from the query means their password hasn't been
* upgraded yet. We will upgrade it now.
*/
if (mysql_num_rows($results) > 0) {
/**
* Generate a new password hash using your new algorithm. That's
* what the generateNewPasswordHash() function does.
*/
$password = generateNewPasswordHash($password);
$password = mysql_real_escape_string($password);
/**
* Now that we have a new password hash, we'll update the member table
* with the new password hash, and change the is_pass_upgraded flag.
*/
$sql = "UPDATE members SET password = '$password', is_pass_upgraded = 1 WHERE username = '$username' LIMIT 1";
mysql_query($sql);
}
}
Your authenticateUser() function would need to be changed to something similar to this:
<?php
function authenticateUser($username, $password)
{
$username = mysql_real_escape_string($username);
/**
* We need password hashes using your old system (md5 for example)
* and your new system.
*/
$old_password_hashed = md5($password);
$new_password_hashed = generateBetterPasswordHash($password);
$old_password_hashed = mysql_real_escape_string($old_password_hashed);
$new_password_hashed = mysql_real_escape_string($new_password_hashed);
$sql = "SELECT *
FROM members
WHERE username = '$username'
AND
(
(is_pass_upgraded = 0 AND password = '$old_password_hashed')
OR
(is_pass_upgraded = 1 AND password = '$new_password_hashed')
)
LIMIT 1";
$results = mysql_query($sql);
if (mysql_num_rows($results) > 0) {
$row = mysql_fetch_assoc($results);
startUserSession($row);
return true;
} else {
return false;
}
}
There's upsides and downsides to this approach. On the upsides, an individual member's password becomes more secure after they've logged in. The downside is everyone's passwords aren't secured.
I'd only do this for maybe 2 weeks. I'd send an email to all my members, and tell them they have 2 weeks to log into their account because of site upgrades. If they fail to log in within 2 weeks they'll need to use the password recovery system to reset their password.
Just re-hash the plain text when they authenticate the next time. Oah and use SHA-256 with a salt of base256 (full byte) and 256 bytes in size.

Resources