First thing we need to talk about is hashing. Hashing is taking a string, putting it through an algorithm, and making it into a string of jumbled letters and numbers. For this example, we're going to use SHA, the Secure Hashing Algorithm. We're going to use the adaptation found here. SHA, for example, will take "Hello!" and turn it into "334d016f755cd6dc58c53a86e183882f8ec14f52fb05345887c8a5edd42c87b7".
So, another problem arises is that if someone gets into your password store, if people have the same password, their hashes are going to be the same. Since the algorithm is just math, it's going to produce the same output every time you put in the same string. So how do we combat this? Salting. Salting ensures that each users' hash is different, so that way it's almost impossible to get the password from the hash.
So, here's what we need:
- ComputerCraft Computer
- SHA API (I saved mine to the file "/sha")
- Time and patience
Here's how we start our program:
os.loadAPI("sha") local passPath = "passwords" --Change this if you want a different password file if not fs.exists(passPath) then --Create a password file local f = fs.open(passPath, "w") f.write(textutils.serialize({})) f.close() endThis first code block makes a password file if not given yet. Now we need to make sure that we have a secure input, meaning the user cannot terminate it. I tend to write my own, so I'll include it here. If I remember correctly, you can securely use the read() function if you set os.pullEvent to os.pullEventRaw before the read function.
os.loadAPI("sha") local passPath = "passwords" --Change this if you want a different password file if not fs.exists(passPath) then --Create a password file local f = fs.open(passPath, "w") f.write(textutils.serialize({})) f.close() end local function secureInput( mask, prestring ) local l = true term.setCursorBlink(true) local prestring = prestring or "" local str = "" local sx, sy = term.getCursorPos() while l do local e, a, b, c, d = os.pullEventRaw() if e == "char" then str = str .. a elseif e == "key" then if a == 14 then str = str:sub(1, -2) elseif a == 28 then l = false term.setBackgroundColour( colours.black ) term.setTextColour( colours.white ) print() return str end end term.setCursorPos(sx, sy) term.setBackgroundColour( colours.white ) term.setTextColour( colours.black ) term.clearLine() if mask then write( prestring .. " > " .. string.rep(mask, #str) ) else write( prestring .. " > " .. str ) end end end
I'm going to write this code in API form, so that way, you can use this in scripts other than login scripts.
Final code:
Brief explanation on how this works:
User enters username and password -> program checks to see if user even exists -> if so, it takes the salt, appends it to the end of what the user entered, and check to see if that equals the password.
Why the salt? As previously stated, it prevents two hashes being the same. So we add a salt to the password upon creation (see the script below) so that they do not have remotely similar hashes.
Before we can test, we need to make users. Here's a quick user maker I whipped up:
os.loadAPI("sha") write("username :: ") local u = read() write("password :: ") local p = read() --Again, change passPath here local passPath = "passwords" local f = fs.open(passPath,"r") local usrs = textutils.unserialize(f.readAll()) f.close() if not usrs[u] then local salt = os.time() usrs[u] = { pwd = sha.sha256( p .. salt ), salt = salt, } local f = fs.open(passPath, "w") f.write( textutils.serialize( usrs ) ) f.close() endAs you can see, upon creation, passwords are salted using the os.time(). The salt can be anything, as long as its unique. Though technically in theory os.time() could be similar, it's quite unlikely that there'll be a collision, so it's good enough for now.
Run that script a couple times, make the users, and see your passwords file. It should look something like this:
Try the login script!
In that gif, both users Eric and tutorials have the same password, but have different hashes. That way, a potential intruder won't know their passwords are the same!
Hopefully, this helped someone. If I need to revise something, let me know!
Edited by CompuTech, 31 August 2016 - 06:54 PM.