Hashes and Salts; what they are and the simple concept of it in Luau

The point is that you can’t decode it, otherwise in the case of a breach, hackers could use the decode method and get access to accounts

3 Likes

Hashing to its core meaning is just encription that can’t be descripted. If you are storing something that needs to be descripted, then it would need to be encripted, not hashed.

Instead of decoding. The data sent, for example, passwords, are hashed, then if the hash is the same as the one stored in the database, the password would be correct.

2 Likes

I have fixed a flaw by adding a debounce and break.
Basically, the script would return 3 or 4 calls if the string already had a hash, it is meant to return 1.
Here is the modified script:

local HashEvent = game.ReplicatedStorage.HashEvent -- The function object that we will use to connect to the client.

local StoredHashes = {} -- This table stores all of the hashes.
local HashLengh = 10 -- how long our hash will be in terms of characters

function GenerateHash(player:Player,Input:string) -- this will generate a random hash we can assign to our string
	local success, errorMessage = pcall(function()
		local LegalCharacters = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz123456789" -- the characters that our hash will consist of
		local Hash = ""
		local Complete = false

		for hash, stringValue in pairs(StoredHashes) do -- checks if there is already a hash for that object
			task.wait()
			if stringValue == Input then
				HashEvent:FireClient(player,hash)
				Complete = true
				break
			end
		end
		if Complete == false then
			for HashStepsDone=1,HashLengh do 
				local RandomNumber = math.random(1,#LegalCharacters) -- creates a random number for a character
				local RandomCharacter = string.sub(LegalCharacters,RandomNumber,RandomNumber) -- gets the character
				Hash..=RandomCharacter -- adds the random character onto our hash
			end
			if not StoredHashes[Hash] then
				StoredHashes[Hash] = Input
				HashEvent:FireClient(player,Hash)
			else
				if StoredHashes[Hash] == Input then
					HashEvent:FireClient(player,Hash)
				else
					GenerateHash(player,Input)
				end
			end
		end
	end)
	if not success then warn(errorMessage) end
end

HashEvent.OnServerEvent:Connect(GenerateHash)

The Complete variable is the debounce variable if you haven’t noticed.

2 Likes

I think this is useless on roblox remotes because hackes can do remote spy thing , so he should know ours password

What is this hash’s collision resistance? (How hard is it to craft an input that matches a desired output?)

Sorry for bumping, but, this post is largely misinformation. Cryptography is a complicated field but it is extremely important. Your implementation of a “hash function” in Lua is nothing more than a fancy random-string generator. In other words, your example was very silly and actually made no contribution to security, especially when dealing with sensitive passwords.

What you got correct is that hashing greatly differs from encryption. Hashing is a one way function (which cannot be reversed) whilst encryption is a two way function (designed to be encrypted AND decrypted). By design, hashes are designed so that the same input will always produce the same output (known as the digest). Depending on which hashing function you’re using, your digest will always be a fixed length.

Also, your description of salts is slightly off. While yes, salts are appended to the input (a password in this case) to hashed, they aren’t there to make the password itself longer. The main purpose of salts is to defend against repeating password hashes. When you add a random salt, you’re ensuring that two different users ultimately have different password hashes, even if they are using the same password. Salts also help to safeguard against password-cracking attacks using structures known as “rainbow tables”. A rainbow table is a big list of hashes from commonly used passwords (like “qwerty” and “password”).

An example of how you would actually go about creating hashes (and salts) for passwords is as follows:

  1. Prompt the player to create a password. Send this password to the server.
  2. Create some random data. This will be your salt. Append that to the password.
  3. Hash the password and salt together using a function like SHA-256 (There’s several options, just make sure you follow the guidelines set by NIST FIPS 180-4 and NIST FIPS 202.
  4. Store the UserId, hash digest, and salt together using things like DataStoreService.

An example of how you would actually use hashes after creating them is as follows:

  1. Prompt the player to enter their password. Send their response to the server.
  2. Go back to where you stored the player’s hash digest and salt.
  3. Append the salt you stored before to the password the player provided.
  4. Using your appended password + salt, run the hash function you chose before (like SHA-256).
  5. Compare the output (digest) of this with the one that matches DataStore records. If they match, you know the password is correct. Otherwise, the password provided was incorrect.

A couple things to note:

  • Stay away from things like MD5 and SHA-1. The earliest versions of SHA (which stands for Secure Hashing Algorithm) was designed by the US National Security Agency a very long time ago. These are no longer considered secure by today’s processing power.
  • There are extremely rare edge cases where two different inputs can return the same hash. This is known as a collision. Again, this is extremely rare and you don’t really need to worry about this much with modern algorithms.
  • Depending on where you are working with hashes, you don’t want to send anything out as plaintext (like the passwords to hash). This is because someone else can “sniff” that data in an attack known as a man-in-the-middle (MITM) attack. I don’t think this is a concern within Roblox, but it’s definitely important when working with websites. This is solved when you use HTTPS (originally SSL over HTTP but is usually TLS over HTTP now).

Feel free to checkout @boatbomber’s HashLib module. His implementation features over a dozen different algorithms and is really optimized.

Hopefully this was all helpful! Cryptography is a super cool field and I hope it’s something you continue to dive into.

10 Likes

See my main reply to OP. He hasn’t actually shown a hash- it’s just a random text generator.

I figured as such but I didn’t spend too long actually trying to understand the code. I thought there was something weird going on like the random generation being just for salting/etc, and as long as it was consistent throughout the game state then hashes generated during one server would work correctly.

But part of the reason why I asked about collision resistance was to catch OP in the act if they actually had 0 idea what they were doing trying to make a hash function.

Like all systems, this one has a flaw. The hashes will vary per server, so storing hashed server data would mean that each hash would have to be stored in DataStoreService for this system to work.

This was the big red flag I saw that prompted me to correct OP at 1am.

1 Like

Looking closer at the OP’s explanation this isn’t hashing at all. It’s literally a UUID storage. Whenever an object doesn’t have a UUID it generates one and caches it so that object gets the same UUID in the future.

1 Like

Yes I know. I will update with a proper bit32-orientated hashing algorithm on my SimpleBit module.

Oh, so you’re the SimpleBit dude. That explains a lot.

You keep mentioning this. SimpleBit is not a math module. The 32Bit Adder was just an addon to experiment with and misconsceptions were understood.

If you are going to keep mentioning the module, atleast look fully into it instead of just some functions in it meant for experiments.

I’d like to add out that you could just send the server the prompted password and let the server check it. This is called sanity checks and are way better.

Both of these technically aren’t correct, they can be converted back, but it would take forever. Also I’m not too experienced with hashes and stuff but your function doesn’t look like a hash but rather a random string generator? Hashes seem to use algorithms instead.

So you can’t say it’s not correct, that’s basically saying something you don’t know yourself.

The only way to ‘convert’ hashes are through brute force attacks, aka hashing every possible combination of characters and checking if the hashes match

Yes, it is more to get the basic concept that hashes are a set lenght and cannot be decoded.

And like I mentioned here, I will work on a Bit32-orientated hashing algorithm instead of a cashe-backed string assigner that the basic concept was.

Just cause I’m not experienced in one section doesn’t mean I don’t know the bare basics

Oh okay! Makes more sense now haha

Hashing is definitely a one way function and cannot be reversed. However, if you’re referring to old algorithms like MD5, those are cryptographically insecure. In contrast, modern algorithms are cryptographically secure.

If you’re one of those people who are worried about post-quantum cryptography, NSA put out some great information regarding that:

Edit: To provide some more insight into the latest public cryptanalysis: currently, MD5’s collision resistance can be broken in 2^18 time. MD5 can still be used to make sure a file hasn’t been unintentionally corrupted. SHA256 has some interesting cryptanalysis to look into, but it is still certified by NIST’s Federal Information Processing Standards.

2 Likes