Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed last year.
Improve this question
I need to store a hash of a single password in a .Net WinForms application.
What's the most secure way to do this?
In particular:
Salt, HMAC, or both?
How much salt?
How many iterations?
What encoding? (The password is plain ASCII)
I assume that the algorithm should be either SHA512 or HMACSHA512.
Salt your hash with secure random salt of at least 128bits or longer, to avoid a rainbow attack and use BCrypt, PBKDF2 or scrypt. PBKDF2 comes with NIST approval.
To quote: Archive.org: http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
The problem is that MD5 is fast. So are its modern competitors, like
SHA1 and SHA256. Speed is a design
goal of a modern secure hash, because
hashes are a building block of almost
every cryptosystem, and usually get
demand-executed on a per-packet or
per-message basis.
Speed is exactly what you don’t want in a password hash function.
Fast password validation functions are a problem, cause they can be attacked using brute force. With all the algorithms above you can control the "slowness"
I can recommend BCrypt.net. Very easy to use and you can tune how long it will take to do the hashing, which is awesome!
// Pass a logRounds parameter to GenerateSalt to explicitly specify the
// amount of resources required to check the password. The work factor
// increases exponentially, so each increment is twice as much work. If
// omitted, a default of 10 is used.
string hashed = BCrypt.HashPassword(password, BCrypt.GenerateSalt(12));
// Check the password.
bool matches = BCrypt.CheckPassword(candidate, hashed);
For a server-side implementation with a large number of passwords, you should definitely use a tunable iterated approach like bcrypt. This well-known article on the topic is still (mostly) relevant:
http://www.securityfocus.com/blogs/262
For a single password in a stand-alone application, where the storage location is probably already secured by the system's own authentication system, I think it's much less important. A single strong hash is likely good enough, and adding salt is easy enough that there's no reason not to do so.
RNGCryptoServiceProvider to generate a random salt, then SHA512 the password with the salt, and finally store both the password hash and the corresponding salt if you want to later verify that some text equals the stored password.
Hash and Salt. If you only hash you could be attacked by a rainbow attack (reverse has lookup) and a salt makes this much more difficult (random salt would be best.) For your encoding you will probably want to either Base64 or Hex encode your resulting byte array. If you just try to store the byte array as Unicode you could run the risk of some data being lost because not all patterns are valid characters. This also allows for an easier way to compare hashes (just compare the base64 or hex string when you want to validate instead of comparing the byte array)
An increased number of rounds doesn't do much beyond slowing down would be attackers. But is also makes is much more difficult to reuse the hashes in the future if you lose or need to recreate your hash algorithm. You might check out a standard password hash such as crypt on unix systems. This allows for you to change out the hash algorithm and can even support versioning.
But again, a simple hash + salt is good enough for most applications.
Strictly looking at more secure:
Salt, HMAC, or both?
Both would be more secure. Since the key to the HMAC could be considered a salt, doing both would be a little redundant, but still more secure because it would take more work to crack.
How much salt?
Every bit of salt would double the combinations that would need to be maintained in a rainbow-table to easily crack the password. But since there is only one password, and only one salt, more may not be needed. The HMAC uses the block size of the underlying hash for its key size, 1024 bits for SHA512. The block size should be good enough for the salt, but doubling or tripling it would make cracking the password with a rainbow-table much, much harder.
How many iterations?
The more the better. Sure, more iterations means it will take longer to determine if the correct password was entered, but computers are fast and users will not mind waiting for a few seconds while verifying the password. Doing more iterations would mean that someone cracking the password would have to do more iterations too.
What encoding? (The password is plain ASCII)
Might as well encrypt (with AES) the over-iterated, over-salted, HMAC'ed, super-secure password along with its salt just to make it harder. Make the password for the encrypted password hash and key, be some combination of strings that should appear in the executable such as "RNGCryptoServiceProvider" or "System.Security.Cryptography". And while encoding we might as well convert it hex, or base64, or better yet base-36 or some other less expected conversion.
Note: This was mostly written in jest, but should still contain some truth.
I think you should stick with open standards. Among the current hash schemes, the "{ssha}" used by OpenLDAP is very secure and widely used. You can find the description here,
http://www.openldap.org/faq/data/cache/347.html
Most LDAP libraries implement this scheme.
You could follow a published standard, like pkcs#5. see http://en.wikipedia.org/wiki/PKCS for a short description, or https://www.rfc-editor.org/rfc/rfc2898 for the RFC.
Here is an API which will do everything you need/want :)
https://sourceforge.net/projects/pwdtknet
Related
My current project is my first in Node.js (also using MongoDB, Mongoose, and Express, if it matters), and being easily distracted, I have fallen down the rabbit hole of crypto while deciding how to handle user authentication. (No other encryption is needed on this project).
Following the pattern on this page (pattern, not code - I am having problems with installing node.bcrypt but not with node-sodium) and also this page my process is
new user submits password over https
the schema generates a salt
schema hashes a concatenation of the password and salt
schema stores the salt and the password with the user information
Now I don't know if this my personal deficiency, but I am having trouble following the libsodium documentation. node-sodium does not provide any additional information for hashing (though it does have an example for encryption).
This is the code I want to use to generate the hash:
let buf = new Buffer(sodium.crypto_pwhash_STRBYTES);
sodium.randombytes_buf(buf, sodium.crypto_pwhash_STRBYTES);
let salt = buf.toString();
let preBuffer = "somePass" + salt;
let passwordBuf = Buffer.from(preBuffer);
let hash = sodium.crypto_pwhash_str(passwordBuf, sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE);
So the question is two parts. Is this a good process, and is the code appropriate?
I've used the scrypt-for-humans package in the past for exactly this reason.
https://github.com/joepie91/scrypt-for-humans
Scrypt is a very secure hashing library and this higher level wrapper makes it hard for you to mess anything up. It's also specifically designed for securely hashing passwords so thats a positive as well :)
At the moment the best password hashing algorithm is Argon 2. There is a module called secure-password written by Emil Bay. He talks more about cryptographically secure password hashing and best practices on this podcast. Here is a snippet of what he said about Argon 2.
Normally when you lay out a threat model, perfect security from a mathematical point of view is almost never practical. (In cryptography, can be referred to as perfect secrecy which means, even if you have an enormous computer the size of the universe, it doesn’t matter how big it is, you can never break the security, but that’s not really practical in the real world.) Instead you go for something called computational secrecy. Which means you can break this, but it will cost you too much money and take too much time.
The goal of these hash functions is to make it so expensive to brute force these algorithms that there would be no point in trying. In a threat model, you know that you are not going to get perfect security but can you make it so expensive for your adversary to attack you.
Argon 2 has two parameters that make it immune to large scale GPU attacks. You can control how much memory the function is allowed to use, and you can control how much computation time taken to make a hash. A CPU usually has a lot of memory but a few cores. A GPU has very little memory but thousands of cores. Argon 2 dials up a lot of memory that you can only do about 4 or 8 simultaneous Argon 2 hashes on a single GPU which makes it too expensive to try and crack. In secure-password, I’ve taken the values that Frank Denise who made sodium which it’s built on figured out. It’s within the bounds of an interactive service like a website can afford to create reasonable security without slowing down. To hash a password, you need about 16 or 32 Mb of memory and those parameters can be controlled in Argon 2.
Personally I've used crypto and I do exactly the same 4 steps you are doing right now (after checking a few conditions 7 chars pass, one symbol, one number... ). I'll share the code using crypto.
var salt =rand(160, 36);
var salted_pass = salt + password;
var token = crypto.randomBytes(64).toString('hex'); // I even generate a token for my users
var hashed_password = crypto.createHash('sha512').update(salted_pass).digest("hex");
EDIT: Warning this is not a completly safe method of doing it, as it may turn predictibly. Refer to comments below which explain why it is not a good method.
I would like to generate a unique number from string. The string is a combination of username and password. I would like to generate a unique number id (not string) from this combination. I first md5 the combination and then convert it to number. The number length needs to be 10. Any suggestions?
It would be best if you can provide more details about the third-party you're trying to interface with, because this is a very odd request and it contains a fundamental flaw. You ask for the number to be unique, but you are allowing for only 10 decimal ("number id") digits, or ~10 billion possible values.
This sounds like an awful lot but it's really not. This gives you a hash of just over 33 bits. The simple hash collision probability calculator at http://davidjohnstone.net/pages/hash-collision-probability puts this at a 44% chance of a collision at just 100,000 entries. But that assumes full usage of all the available input characters. Since username and password combinations are almost always limited to alphabetic and numeric characters, the real collision chance is much worse at far fewer entries (can't be calculated without knowing the characters you allow for these fields - but it's bad).
NodeJS provides numerous crypto functions in the crypto module. A whole set of hashing functions is available, including the ideal-case SHA* options. These can be used to provide safe, irreversible hashes with astronomically collision probabilities.
If these options are not usable for you, I would suggest you have a fundamental design flaw. You're almost certainly mapping a user/pass combination to a userID in a remote system in a way that an attacker would find easy to compromise with a simple brute-force attack, given the high collision risk in your model.
If you are doing what I think you are doing, the "right" way to do this would be to have a simple database on a server somewhere. The user/pass would be assigned a unique ID in there, and it doesn't matter what this is - it could be an auto-increment ID field in a single MySQL table. The server would then contact this remote service with the ID value for any API calls necessary, and return the results to the user. This eliminates the security risk because the username/password are not actually hashed, just stored, and can be checked 100% on every call.
Never use a hash as a primary data value. It's a simplification, not a real value on its own.
I have a situation where I need to generate short pseudo-random alphanumeric tokens which are unique, verifiable, and easily type-able by a human. These will be generated from a web app. The tokens don't need to be highly secure - they're used in a silly web game to claim a silly prize. For various reasons, the client wants these tokens to be human-readable and handled via email. This is non-negotiable (I know... but this is how it has to be for reasons beyond my control).
In other words, let's say we get the code "ABCDE12345"
There has to be a way to say "ABCDE12345" is "valid". For example: maybe two or three characters at the start run through an algorithm I write will generate the right sequence of remaining characters. E.g., f("AB")==="CDE12345"
Two people playing the game shouldn't be likely to generate the same token. In my mind, I'd be happy to use the current time in millis + game-character name & score to seed a home-made RNG. (which is to say, NOT use Math.random, since this is a web app). This would seed the two or three character sequence mentioned above.
Am I missing anything? I'm not looking for a concrete algorithm but rather your suggestions. Anything I'm missing?
If you think your token is comparable to an authenticated message saying "give this person a prize" you could look at https://en.wikipedia.org/wiki/Hash-based_message_authentication_code, recoding as necessary with e.g. https://en.wikipedia.org/wiki/Base64 to make the thing printable. Of course, HMAC uses a secret key which you will have to KEEP secret. A public key signature system would not require that you keep the key secret, but I would expect the signature to be longer, and I expect that it is already too long for you if you want non-trivial security.
A simple solution (and easy to hack) would be to generate a meaningful term (one way to achieve such is choose a random article from wikipedia), encrypt it with a pre-known password, and take the least significant x bits.
Now, the key you generate is word-<x bits as a number>.
This is easily verifiable by machine, simply re-encode the word and check if the bits fit, and offers a simple tradeoff of readability vs security (bigger x -> less readable, harder to fake).
Main problem with this approach though, is assuming your game is not communicating with any server, you will need to deploy the preshared secret somehow to your clients, and they will be able to reverse engineer it.
I need a common hashing method both in php and javascript, something like MD5 or if not MD5 then something to use salt, but to generate same result from php and javascript.
What I wanted to do is, I have a series of questions that I will ask user and users has to answer them, but to make it fast and avoid delay to check the user answers from server, I also want to load the answers with questions and match them in javascript as users answer them. Now I need to bring the answers hashed from php server, and when I am matching them with users answers, I would hash the user answer and match it with the hashed answer from server.
Is it possible?
This is little more than obfuscation what you are doing. Presumably you want to prevent the users from cheating. Doing so and relying on client side code won't work securely.
When the client browser receives the answer hashes and the corresponding salts, the user can simply brute force the correct answers. The number of possible answers is so small that the user can try every possible answer with the received salt and find the matching answer by comparing the hashes.
Since this is nothing more than obfuscation, why make it complicated? Simply encode your correct answers with Base 64 or something like that. This will prevent most users from cheating. If you actually want to make sure that no user can cheat, you need to send the selected answers to the server.
If you actually want to go ahead with your plan, the fastest MD5 hasher for JavaScript right now is SparkMD5, not that you need the speed for your use case. CryptoJS also implements MD5 and PHP has the md5() function. All those implementations are compatible. You just have to make sure that you use the same encoding (Character encoding and Hex/Base64).
A construction with a salt may be md5(answer || salt) where || denotes concatenation. This is not really save, but it doesn't matter in your case anyway.
I would like to get Both CryptoJS's SHA256 and php's Crypt SHA256 output to match.
PHP crypt has a salt and a number of rounds. E.g. for 5000 rounds and salt of "usesomesillystringforsalt" it would be;
$hash = crypt('Clear Text String', '$5$rounds=5000$usesomesillystringforsalt$');
I hope im not blind, but i cant find how to reproduce this behaviour in crypto-js. Its syntax doesn't seem to allow for rounds or salt.
Is it possible or should i just resort to using the basic PHP hash instead of crypt?
The CryptoJS API doesn't provide a way to specify a salt or the number of rounds for SHA256. You could add a salt manually if necessary, and specifying rounds doesn't make sense since "plain" SHA256 always uses a fixed number of rounds (64).
The number of rounds in PHP's crypt() actually defines how often the SHA256 algorithm is applied consecutively, in order to increase the complexity of brute force attacks. The PHP source code comments on this as follows: "Repeatedly run the collected hash value through SHA256 to burn CPU cycles".
As you can see in the source code (here and here), crypt() is actually a key derivation function that only makes use of SHA256 to generate cryptographically secure, salted hashes. So it also doesn't simply append the given salt to the key, instead it's a more elaborate process.
Therefore, it is not possible to get the same results with the algorithms provided by CryptoJS.
crypt() is mainly intended for password hashing. So if you need the hashes for another purpose, hash() is a good alternative (and of course creates exactly the same results as CryptoJS.SHA256()).
However, bear in mind that any cryptography with JavaScript is generally considered harmful. Hence, you should better use SSL in your application, if possible, and generate the hashes server side. If this is an option, have a look at bcrypt.