Like many big popular websites such as YouTube, Facebook, and ROBLOX, they don't store passwords normally as text(That would be a terrible idea). When you send passwords they go through and become encrypted. That way if there is an attacker or leaks, you don't see: "03_23_2001" as a password. They encrypt it in a semi-random fashion. So the outcome becomes like so: 4wh2sifee2sh45d3
. When you send your password to the server, they don't send your password like it was when you typed it in, they save the encrypted version and they encrypt your password in the same encryption method they used when you signed up. That's why websites don't mind if you don't use correct capitalisation when typing in your username, but when typing in passwords, each letter is different and each capital letter becomes a different letter than a lowercase one. This makes it easy to encrypt a password, but not steal passwords. Think of an encrypter as a math equation:
45*112 = 5040 --45*112 is the password you type in, and 5040 is like the number that comes out after encryption. 5040 --Now let's say you hacked into a site and you find 5040. How can you trace it back to what the user originally typed in when there are so many other possibilities! 1*5040, 5040, 5040+0, 5030+10, 5031+9, 6000-60, 420*12... --The list goes on and on, there are a bunch of possibilities! And you can't just type in 5040 because that will also get encrypted!
So this is what makes password systems so secured. I'm trying to recreate this in ROBLOX but it's more difficult than it seems.
It's really easy to do this with numbers: Just put the numbers through a function and keep repeating it a random number of times, then use DataStores to save that random number and use that number the next time they sign in.
game:GetService("Players").PlayerAdded:connect(function(plyr) local num = math.random(1,100) local ds = game:GetService("DataStoresService") local rnum = ds:GetDataStore("rnum") local pswrd = ds:GetDataStore("PasswordArchive") if rnum:GetAsync(plyr.userId) == nil then rnum:SetAsync(plyr.userId, num) else num = rnum:GetAsync(plyr.userId) end function encrypt(password) local var = password for i = 1,num do var = var*12/32+52^3+i end return var end if not pswrd:GetAsync(plyr.userId) then pswrd:SetAsync(plyr.userId, encrypt(213)) end end)
This would work, but what if the player is using letters in their password? And what if 2 people had completely different passwords, but through pure chance, they got the same encryption?(That one is an easy fix)
Any help is appreciated. Thanks!
YouTube Doesn't Know Your Password - Tom Scott, 5040 and other Anti-Prime Numbers - Numberphile, How NOT to Store Passwords! - Computerphile
Start off by making a key
I'm not saying this key has to be anything complicated, it can be as simple as a single number, or even a table. This key will be what your entire equation is built around. If someone does crack your code, simply change the key.
local key = 45 --Or local keys = {25, 15, 29, 76, 47} local key = keys[4] --76
Create a complicated sequence
This will be the code that converts a password into an encryption, and visa versa. I prefer using string.char
and `string.byte. These are two effective ways of changing letters to numbers and then back to letters again
local function convert(pass, tblnum) return string.char((string.byte(pass) -30+ (-tblnum or tblnum)) % 34+ 60) end
Create a system to Decrypt
Decrypting an encrypted code may be the hardest part of all of this. It ensures that the password you input initially is the same as the password you get back from the database
Final Setup
Now that you have all of the variables to create an encryption, you can start. I recommend using a piece of my encryption for reference, although I do prefer you don't actually use it
-- stringg is the password that you want to be encrypted -- key is a table of numbers that will determine which is used for the code -- convert is the function I displayed earlier -- encrypt would be a variable that determines whether the stirng is being encrypted or not for i=1, #stringg do if(#stringg - key[2] >= i or not encrypt)then for inc = 0,3 do if(i % 4 == inc)then code = code..convert(string.byte(stringg, i, i), key[inc + 2]); break; end end end end
I hope this is what you were looking for!
The best way to do this in my opinion (and many others') is to use a hash. There are many good hashing functions, an example being SHA-256. After a bit of searching, I found this thread on the CompterCraft forums, and more specifically this Lua implementation of the function. Adding a salt to it shouldn't be too difficult either: I would combine the raw password with a salt randomly generated for each user, then hash that. (I'm not sure this is the best way to salt, but it would probably work).