I am writing a Django app that needs to work with an existing Java Play framework app. The Play app uses PasswordHash.java to store passwords. It stores passwords in a colon separated format. Each hash is stored as iterations:salt:pbkdf2_hash.
For example, here is an entry for the password "test":
1000:f7fe4d511bcd33321747a778dd21097f4c0ff98f1e0eba39:b69139f51bc4098afc36b4ff804291b0bc697f87be9c1ced
Here we can split the string by : and find:
Iterations: 1000
Salt: f7fe4d511bcd33321747a778dd21097f4c0ff98f1e0eba39
PBKDF2 Hash: b69139f51bc4098afc36b4ff804291b0bc697f87be9c1ced.
I modified Django's check_password mechanism to be compatible with this format, but found that it didn't think the password was correct. I used Django's crypto.py to regenerate a hash for "test" using the same salt that Play used, and came up with this:
hash = crypto.pbkdf2('test', 'f7fe4d511bcd33321747a778dd21097f4c0ff98f1e0eba39', 1000, 24)
base64.b16encode(hash)
'9A8725BA1025803028ED5B92748DD61DFC2625CC39E45B91'
The PBKDF2 hash from play does not match this hash. (For those wondering, I used 24 as the fourth parameter because that is what is used in PasswordHash.java).
After I was unable to make Django's generated hash match Java's, I tried it on a website that does it for you.
I plugged in the same salt, used SHA-1 with 1000 iterations and a 24-bit key size and found that the website matched what Django had created!
I am not sure what is going on with PasswordHash.java, but I desperately need to get Django and Play to "play nicely" (couldn't help myself haha). Does anyone have an idea as to what is going on here?
Try salt = base64.b16decode(salt.upper()).
I did and I got the hash in your initial example, albeit uppercased B69139F5...
Explanation:
The hash and salt are both being stored in Base16 (hex) in your initial example. So you decode the salt to use it and then encode the resulting hash to compare it with the stored one.
The upper() is because python's b16decode is strict about uppercase Base16. It will error if you give it the lowercase one.
Related
I am working on an application in which I have to compare 2 hashed passwords in a database, one password is being generated in PHP with $Password = password_hash($RawPassword, PASSWORD_BCRYPT);
While the other password that is being sent to the database to compare with the PHP hashed password is generated in Java with String hashedPassword = BCrypt.hashpw(password);
As of PHP 7.0 the salting is automatically generated, how can i know what salt is being applied in PHP so i can apply it to my java code? Or is there a way to still specify the salt that is no longer in the documentation for PHP Hashing?
The standard idea behind the vast majority of bcrypt impls is that the thing that is in the database looks like $2y$10$AB where A is 22 characters and B is 31 characters for a grand total of 60. A is: left(base64(salt + 00 + 00), 22) and B is: left(base64(bcryptraw(salt + pass)), 31). (2y refers to the hash algorithm/ EDIT: 2y and 2a are more or less interchangible; most bcrypt impls treat them the same, and it is unlikely to matter which one is there. The 10 refers to the # of bcrypt rounds applied. 10 is common and usually what you want).
where:
base64(X) = apply base64 conversion, using . and / as the 63rd and 64th char.
+ is concatenate, i.e. salt (a 16-byte byte array) gets 2 zero bytes added.
left(chars, size) means: Take the first size chars and discard the rest.
salt is the salt in bytes and pass is the password, converted to bytes via UTF_8. (if not converting via UTF-8, it's generally $2a$ instead, and you should upgrade, folks with non-ascii chars in their password get pretty bad hashes in the older $2a$ mode!
This one string contains everything that a bcrypt impl needs to check if a given password is correct or not. Thus, all non-idiotic bcrypt library impls have just two methods and no others:
// This is for when the user creates an account or edits their password.
// send the password to this method, then take the string it returns,
// and store this in your database.
hash = crypto.hashPass(password);
// This is for when the user tries to log in. For 'hash', send the thing
// that the hashPass method made for you.
boolean passwordIsCorrect = crypto.checkPass(password, hash);
EDIT: NB: A truly well designed crypto library calls these methods processNewPassword and checkExistingPassword to avoid the kind of confusion that caused you to ask this question, but unfortunately, nobody out there seems to have had the wherewithal to think for 5 seconds about what their names suggest. Unfortunate. Security is hard.
if your BCrypt API doesn't work like this, get rid of it, and find a standard implementation that works like this.
It sounds like you're using the wrong method. To check passwords, don't use hashPass. Use checkPass, or whatever goes for checkPass in your impl (it might be called checkPw or verifyPw or validate, etcetera. It take 2 strings).
Thus, you should never generate a salt, nor ever extract a salt from such a string. Let the bcrypt lib do it. Those 'hashes' that standard bcrypt libraries generate (the $2y$ string) are interchangible; your PHP library can make em and your java library can check em, and vice versa.
If you MUST extract the salt (but don't):
take those 22 characters, after the $protocol$rounds$ part.
append 'aa' to this.
base64decode the result.
this gets you 18 bytes. toss the last 2 bytes, which contain garbage.
The remaining 16 bytes are the salt.
You should absolutely not write this - your bcrypt library will do this.
This question already has answers here:
How to reverse MD5 to get the original string? [duplicate]
(2 answers)
Closed 2 years ago.
I am looking into md5 hashing in java with the MessageDigest Class, lets say I do that
public void givenPassword_whenHashingUsingCommons_thenVerifying() {
String hash = "35454B055CC325EA1AF2126E27707052";
String password = "ILoveJava";
String md5Hex = DigestUtils
.md5Hex(password).toUpperCase();
assertThat(md5Hex.equals(hash)).isTrue();
}
So i did convert my password String into an md5 hash, lets say my recipient now wants the String not as hash, but as an normal String ( The Hash is just for transmission ), how can i convert the md5 hash String back to an "normal" Text String?
There is no way to convert a hash (MD5 or SHA1 or SHA2....) into the original string.
The purpose of a hashing function is a one-way translation. There is no coming back.
The MD5 hash function is an outdated cryptographic function that generates fixed length hashes of an input data. The how and whys is beyond the scope of this answer. I urge you to visit detailed texts on these online.
Please also remember that if you are using the MD5 for cryptographic and sensitive reasons, please learn about more secure recommended hashing as SHA256 etc..
For more details, please refer to this introductory text.
The reason that we hash passwords in particular is because it's one way and this is good for security reasons. Imagine a bad actor got access to your database, we wouldn't want them to be able to look up the password and log in as the user. By storing the hashed password, we can perform the same hashing algorithm on the password on login and compare it with the database value in the database for a successful login.
Even this has its issues. When bad actors gain access to a compromised database, they can generate "rainbow tables" to get from the hashed value to the password. Using common hashing algorithms and software such as hashcat they build up a database of common passwords, dictionary words etc. then match the hash value to the plain text string. This is why when storing passwords, we also use salting, which can be easily researched, Google "salting and hashing".
I see another answer which states that "The purpose of the hashing function is a one way translation". I think this is an over simplification. A hashing algorithm returns a message digest. It's a fixed length alphanumeric message which, as uniquely as possibly, represents the input. One the most important properties of a hashing algorithm is the uniqueness of the message and that it differs significantly from that of similar inputs. Here's an example using MD5:
String: aaaaaaaaaa
Hash: e09c80c42fda55f9d992e59ca6b3307d
String: aaaaaaaaab
Hash: ba05a43d3b98a72379fdc90a1e28ecaf
While using Jasypt, the encrypted passwords contains = (equal character) at the end. Is it guaranteed that the encrypted passwords will always have = at the end?
How/Can we control this behavior?
Foe example: test is encrypted to Nv4nMcuVwsvWVuYD7Av44Q==
It looks like the =s come from padding the Base64 representation of the encryption / hash output.
In that case, the answer is generally no, it won't necessarily end with "=".
However if the algorithm you're using produces constant-length output (e.g. if it uses hashing along the way), it might by a chance end up producing those "="s all the time - but there's no way of knowing that for sure unless you fully understand all steps the algorithm you're using performs.
I tried to search this but surprisingly could not find any results of converting SHA-1 generated string back to normal string. I hash a string to SHA-1 and then send it to some other device where this SHA-1 generated string should be unhashed and used but I am unable to find any such method in Java.
The whole point of SHA-1 and other hashing algorithms is that there is no such thing as unhashing. There is no such method in Java or any other language.
What you are searching for is symmetric encryption.
You are confusing hashing with encryption (this is what you would probably want to use instead). Encryption is reversible given a key, while hashing is not.
Hashes are one way, you can go from text to hash but not the other way.
Have a look at this for a nice discussion:
https://security.stackexchange.com/questions/11717/why-are-hash-functions-one-way-if-i-know-the-algorithm-why-cant-i-calculate-t
I'm planning to hash user passwords using bcrypt, and to store these hashed passwords in a database.
The server that handles user account creation, and inserts the hashed password to the database is written in Java.
Another server that needs to access user information (including the hashed passwords) is written in Python.
I was planning to use jBCrypt for the Java side, but before I do that I want to make sure that I'll by able to recognise/use these hashed passwords from the Python side.
How I understand things, this should be no problem as long as the Python BCrypt implementation is the same as the Java implementation.
So, can I use the passwords hashed using jBCrypt from Python? How?
Thanks in advance!
The best way to know is to actually try it.
Assuming both implementations are correct, they should be compatible, as long as you take care to re-encode data as necessary.
Typically, a hash is stored in memory either as a byte array of the raw hash, or as a ASCII hexadecimal representation. The best way to know what encoding it's using is actually printing it to the console: if it looks like garbage, it'll be a raw byte array; if it prints a hexadecimal string (0-9 and a-f), it's ascii encoded hexadecimal.
Salt will probably be stored like the hash. The number of rounds is a integer. It's up to you to store all this data in a common format. If you need to convert a ascii hex string to a byte array (actually, a string) in python, you can use string.encode:
>>> 'hello world'.encode('hex')
'68656c6c6f20776f726c64'
>>> '68656c6c6f20776f726c64'.decode('hex')
'hello world'
For a bcrypt implementation in python, you may want to try py-bcrypt