I am using passlib pbkdf2_sha512 on my python api to verify a users password. The input string that the algorithm needs has to follow this format as far as I am aware: $pbkdf2-digest$rounds$salt$checksum
Is there a library in Node that can generate me a sha512 password and return it in such format or would I need to write my own algorithm to format it in such way and pick random salts, rounds etc.
More information about the python library.
I tried to reproduce the String generated by the python library in Node:
function sha512(password) {
const salt = crypto.randomBytes(16);
const rounds = 29000;
// I used sha256 for testing purpose, it shouldn't matter for the sake of the result
const passwordHashed = crypto.pbkdf2Sync(password, salt, rounds, 256,
'sha256').toString('Base64');
console.log(passwordHashed);
}
I generated a hash for "password" and my code returns
Encoded in Base64:
7uLTDHjAhQX0yIqXptXuhHIygNogaZRcDqa7ckc0XCj4FAAW29V6KzIzRuJKJoTqN9xjfGOyGZ21X0J1vemQLThcnIXgwt2E84VrW/ai+BdVaUPHiT8J0mutOM9j52l1fFLT7rl5Rmr8qiyGzBaWj6i0sRkrdba9IVDHr1HxGAoM8qEuCSHgKsBVVX65+1pf2DDEUsgGShzE31xiuwF8UpHwq5Cxhiq8ER5xQnKj/j3mG/AAoylPVu30Jd4aFNoRi2Lfhk+6nFwLS0R222R38Jio93qzVD0Nb8kjXqjoXIYxTY6ZOumlsXWR/NmhTQi31x6JggoO1Z1jSFnCVUUd2Q==
And when generated with the python library in adept base 64
98jZicV16ODfEsEZeYPGHU3kbrUrvUEXOPimVSQDD44
Which is obviously a much smaller String. The library mentions that their encode is very basic except for some characters being swapped but this result doesn't seem to make quite sense to me. (I used the same salt size and the same rounds as in the exmample on the library website)
Related
I have the following code snippet:
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
pwd_context.hash(password)
Which is described here.
What i don't understand is, how can this be secure if it returns the same hashed password all the time without considering another secret_key for example to hash the password value?
Your assumption that it returns the same hashed password all the time without considering another "secret" (well, it's not really secret) is wrong; you'll see this if you run pwd_context.hash multiple times:
>>> from passlib.context import CryptContext
>>>
>>> pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
>>> pwd_context.hash("test")
'$2b$12$0qdOrAMoK7dgySjmNbyRpOggbk.IM2vffMh8rFoITorRKabyFiElC'
>>> pwd_context.hash("test")
'$2b$12$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
These two hashes are, as you can see, not the same - even when given the same password. So what's actually going on?
When you don't give hash an explicit salt (the secret "key" you're talking about) one will be generated for you by passlib. It's worth pointing out that hashing is NOT the same as encryption, so there is no key to talk about. Instead you'll see salt mentioned, which is a clear text value that is used to make sure that the same password hashed twice will give different results (since you're effectively hashing salt + password instead).
So why do we get two different values? The salt is the first 22 characters of the actual bcrypt value. The fields are separated by $ - 2b means bcrypt, 12 means 12 rounds, and the next string is the actual resulting value stored for the password (salt+resulting bcrypt hash). The first 22 characters of this string is the hash.
You can see this if you give bcrypt a salt instead of letting it generate one (we'll ignore a possible warning about small padding here, but to show the concept):
>>> pwd_context.hash("test", salt="a"*22)
'$2b$12$aaaaaaaaaaaaaaaaaaaaaOm/4kNFO.mb908CDiMw1TgDxyZeDSwum'
^-------------------^
If we explicitly give the same hash, the result should be the same (and is how you can verify the password later):
>>> pwd_context.hash("test", salt="a"*22)
'$2b$12$aaaaaaaaaaaaaaaaaaaaaOm/4kNFO.mb908CDiMw1TgDxyZeDSwum'
>>> pwd_context.hash("test", salt="a"*22)
'$2b$12$aaaaaaaaaaaaaaaaaaaaaOm/4kNFO.mb908CDiMw1TgDxyZeDSwum'
This same is the case for the previous hashes:
>>> pwd_context.hash("test")
'$2b$12$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
^-------------------^
This is the actual generated salt, which is then used together with test to create the actual hash:
>>> pwd_context.hash("test")
'$2b$12$gqaNzwTmjAQbGW/08zs4guq1xWD/g7JkWtKqE2BWo6nU1TyP37Feq'
^------------------------------^
So why do we use this salt when it's clearly visible to everyone? It makes it impossible to just scan through the a list of hashes for known hashes - since test in your list will have a different values than test in the list you're comparing it to (because of different salts), you'll have to actually test the guessed passwords together with their salt and run them through the hashing algorithm. bcrypt is explicitly designed to make that process take time, so you'll spend far longer trying to crack a password than just scan through a list of 200 million passwords and search for the known hash in a database.
So what do you do when computers gets even faster? You increase the 12 parameter - the rounds - this increases the runtime of the hashing alogrithm, hopefully staying safer for even longer (you can experiment with the rounds parameter to passlib.hash).
We are migrating a company we acquired a lot of kiosk hardware assets from that are in the field. Since the company was suffering, we are stuck with some issues in migrating the locations fingerprints, usernames and passwords without any implementation docs. Luckily, most of the passwords used are numeric 4-6 PIN or a common used word. I'm stuck with trying to figure out what format the password is hashed in and hopefully can decipher it from there using a dictionary for the majority of the passwords. I have the following format:
"password": "ce62f0002776890507c4050a3b76c064d3d24328aea52a08633b726d352532dc",
"salt": "JUQLSPOYGFURMGSDRYWIWBIWP",
The password above is "password". Hopefully this helps in finding the format.
If it is a hash, looks like a hash, possibly HMAC-SHA256 from the length, you need to run a password cracking program. You should be able to recover well over 90% but most likely not all.
On my laptop I can run a 20 byte password through SHA-512 and compare in under 1us so with just a SHA-512 hash I can try 1,000,000 passwords a second.
You can make a list to check but there are already good lists, see below.
For more information see:
Password list at SecLists.
Infosec password-cracking-tools
Arstechnica How I became a password cracker.
You can implement the old hashing method in your new code. When the password matches (i.e. the one the partner sends) you can then store it in your new format (essentually accepting both). This saves you the need to crack the existing passwords.
For this to work you do need to know how the passwords are hashed and what formatis used, lucikly this seems to be fairly easy (Java sample):
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write("password".getBytes(StandardCharsets.US_ASCII));
bos.write("JUQLSPOYGFURMGSDRYWIWBIWP".getBytes(StandardCharsets.US_ASCII));
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] out = md.digest(bos.toByteArray());
System.out.println("hex = " + new HexBinaryAdapter().marshal(out).toLowerCase());
Produces (i.e. concatenate password bytes and salt bytes, non-iteratively calculate SHA256 and convert to hex) the expected hash:
hex = ce62f0002776890507c4050a3b76c064d3d24328aea52a08633b726d352532dc
This is a theory question, as I already know the following:
Hashes are not encryptions
Hashes can be broken https://crackstation.net/
That my code is not serious enough to be used on an enterprise site
But my question is just on the theory of it all.
In theory, if I stored a hashed password into a database, how could I check it when a user comes to log in? Is it that simple or is there a standard way to actually store and retrieve passwords in SQLite3?
If you can offer some SQLite3 code or guidance on where to start, that would be appreciated.
import sqlite3
import hashlib
def encrypt_password(password):
encrypted_pass = hashlib.sha1(password.encode('utf-8')).hexdigest()
return encrypted_pass
cemail = input("E: ")
cpassword = input("P: ")
connection = sqlite3.connect('/Users/Air/Desktop/users.db')
connection.create_function('encrypt', 1, encrypt_password)
cursor_v = connection.cursor()
cursor_v.execute("insert into user (cemail, cpassword) values (?,encrypt(?))", (cemail, cpassword))
connection.commit()
cursor_v.close()
When dealing with passwords, there's an absolute ton of information you need to know as a minimum:
Firstly, hashing passwords must be slow, which is the exact opposite of what a hash function is usually intended for.
Use bcrypt or PBKDF2 for this purpose. MD5/SHA1/256/512 are not sufficient for a password and offer no real protection when faced with a GPU-based bruteforcer (such as hashcat).
Second, verification of passwords must be in constant-time, aka they must complete in the same time regardless of the length of a string.
String comparison functions are at risk of a timing attack, and this means that the hash can be deduced by repeatedly giving different inputs to your verification function until enough information about the hash is revealed.
To get around this, use a cryptography library that does this for you.
If you have no other choice, the following pseudocode should help you see how a constant-time algorithm generally works (though you should still use a library!)
def verify(hash, input):
key = secure_random(32)
hash = hmac_sha_512(key, hash)
input = hmac_sha_512(key, bcrypt(input))
results = []
for i, letter in input
results.add(hash[i] === letter)
return false not in results
Thirdly, passwords should have a cryptographically random salt used throughout the hashing. A secure random source of randomness is generally taken from /dev/urandom or a library dedicated to it.
To answer the question of Well how do I verify a password if I can't see the original value? — simple, just hash whatever a user gives you and see if the hash matches the one in the database. But see above for the huge pitfall there.
You cannot retrieve hashed password but compare new password whether it is the same. IF HASH(new_password) == hashed_password_in_db THEN ..ok.. ELSE ..wrong password....
i use this code for encrypt my data to blwofish but i dont know really to convert to blowfish or other encryption.
echo crypt('ab','$2a$09$anexamplestringforsalt$')."\n";
and i'm try bottom code but it's false
echo CRYPT_BLOWFISH('ab','$2a$09$anexamplestringforsalt$')."\n";
It is the crypt parameter string, that defines which algorithm is used:
$2a : This describes the algorithm (BCrypt) but should be 2y nowadays
$09 : This is the number of rounds and is usually 10 or higher
$anexamplestringforsalt : This should be a really random salt of a given alphabet
To generate a BCrypt hash, it is much safer to use the new password_hash() function though, there exists also a compatibility pack for earlier PHP versions.
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
I run a rather large site where my members add thousands of images every day. Obviously there is a lot of duplication and i was just wondering if during an upload of an image i can somehow generate a signature or a hash of an image so i can store it. And every time someone uploads the picture i would simply run a check if this signature already exists and fire an error stating that this image already exists. Not sure if this kind of technology already exists for asp.net but i am aware of tineye.com which sort of does it already.
If you think you can help i would appreciate your input.
Kris
A keyword that might be of interest is perceptual hashing.
You use any derived HashAlgorithm to generate a hash from the byte array of the file. Usually MD5 is used, but you could subsitute this for any of those provided in the System.Security.Cryptography namespace. This works for any binary, not just images.
Lots of sites provide MD5 hashes when you download files to verify if you've downloaded the file properly. For instance, an ISO CD/DVD image may be missing bytes when you've received the whole thing. Once you've downloaded the file, you generate the hash for it and make sure it's the same as the site says it should be. If all compares, you've got an exact copy.
I would probably use something similar to this:
public static class Helpers
{
//If you're running .NET 2.0 or lower, remove the 'this' keyword from the
//method signature as 2.0 doesn't support extension methods.
static string GetHashString(this byte[] bytes, HashAlgorithm cryptoProvider)
{
byte[] hash = cryptoProvider.ComputeHash(bytes);
return Convert.ToBase64String(hash);
}
}
Requires:
using System.Security.Cryptography;
Call using:
byte[] bytes = File.ReadAllBytes("FilePath");
string filehash = bytes.GetHashString(new MD5CryptoServiceProvider());
or if you're running in .NET 2.0 or lower:
string filehash = Helpers.GetHashString(File.ReadAllBytes("FilePath"), new MD5CryptoServiceProvider());
If you were to decide to go with a different hashing method instead of MD5 for the miniscule probability of collisions:
string filehash = bytes.GetHashString(new SHA1CryptoServiceProvider());
This way your has method isn't crypto provider specific and if you were to decide you wanted to change which crypto provider you're using, you just inject a different one into the cryptoProvider parameter.
You can use any of the other hashing classes just by changing the service provider you pass in:
string md5Hash = bytes.GetHashString(new MD5CryptoServiceProvider());
string sha1Hash = bytes.GetHashString(new SHA1CryptoServiceProvider());
string sha256Hash = bytes.GetHashString(new SHA256CryptoServiceProvider());
string sha384Hash = bytes.GetHashString(new SHA384CryptoServiceProvider());
string sha512Hash = bytes.GetHashString(new SHA512CryptoServiceProvider());
Typically you'd just use MD5 or similar to create a hash. This isn't guaranteed to be unique though, so I'd recommend you use the hash as a starting point. Identify if the image matches any known hashes you stored, then individually load the ones that it does match and do a full byte comparison on the potential collisions to be sure.
Another, simpler technique though is to simply pick a smallish number of bits and read first part of the image... store that number of starting bits as if they were a hash. This still gives you a small number of potential collisions that you'd need to check, but has much less overhead.
Look in the System.Security.Cryptography namespace. You have your choice of several hashing algorithms/implementations. Here's an example using md5, but since you have a lot of these you might want something bigger like SHA1:
public byte[] HashImage(Stream imageData)
{
return new MD5CryptoServiceProvider().ComputeHash(imageData);
}
I don't know if it already exists or not, but I can't think of a reason you can't do this yourself. Something similar to this will get you a hash of the file.
var fileStream = Request.Files[0].InputStream;//the uploaded file
var hasher = System.Security.Cryptography.HMACMD5();
var theHash = hasher.ComputeHash(fileStream);
System.Security.Cryptography