Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --theinsektAPIs/hsign3
- --experiment3, not tested!
- --have changed so that older or same age messages than the last ok message,
- --will be considered invalid
- --This so that the same command can't be retransmitted by an attacker
- --a signer: signs a message and turns it into a sendable string
- --a verifier: verifies the sendable string and returns ok,message2, where ok is true or false, and message2 is the
- --message that was signed
- --so if you do: local ok, message2=verify(sign(message))
- --then message2 will be equal to message, and ok will true
- --if someone fails at forging a message then ok will be false and message2 will be nil
- --example usage (not tested!):
- --os.loadAPI("theinsektAPIs/sha256")
- --local protocol="myprotocolname"
- --local secret="mysupersecret"
- ----use this for sending
- --local sign=hsign2.getPack(secret,sha256.sha256)--do once
- --rednet.send(id,sign("my message, can be any type of data"),protocol)
- --rednet.send(id,sign("message2"),protocol)
- ----use this for receiving
- --local maxDelay=7 --7 seconds old messages will be considered invalid
- --local verify=hsign2.getUnpack(secret,sha256.sha256,maxDelay)--do once
- --local id, signedMessage,protocol=rednet.receive(protocol,timeout)
- --local ok,message=verify(signedMessage)--call directly after receive, because calculates time received inside
- -- if not ok then print("message was invalid") end
- --id, signedMessage,protocol=rednet.receive(protocol,timeout)
- --ok,message=verify(signedMessage)
- -- if not ok then print("message was invalid") end
- --returns a pack function, that can be used to turn a message into a packet ready for sending
- --over rednet
- function getSigner(secret, hashFunction)
- return function(message)
- --prepare the box that holds the data, and a time stamp
- local box={time0=os.time(),day0=os.day(), data=message,}
- --turn the box into a string
- local serializedBox=textutils.serialize(box)
- --put it in a table, and put hash of it+secret
- local packet={
- ["box"]=serializedBox,
- ["hash"]=hashFunction(serializedBox..secret),
- }
- --return the prepared packet
- return textutils.serialize(packet)
- end
- end
- --might stop working if an admin turns back time
- --returns a unpack function that can unpack a packet, from the correspaonding pack function
- function getVerifier(secret,hashFunction,maxDelay)
- --save some values from the last ok hash
- --so that an attacker can't send copies
- --unless this computer restarts within maxDelay after message
- local lastTime=os.time()
- local lastDay=os.day()
- local lastHash=nil --might be unnecessary
- --this is to protect against resent commands after computer has restarted
- if maxDelay==nil then maxDelay=10 end
- return function(packet)
- --get the time that the packet was received
- local time2=os.time()
- local day2=os.day()
- --NEW
- --check if need to correct last lastTime or lastDay
- --this can happen if admin chamges ingame time to an earlier time value
- --some ok messages will become invalid
- if day2<lastDay or (day2==lastDay and time2<lastTime) then
- lastDay=day2
- lastTime=time2
- end
- if type(packet)~="string" then
- return false,nil
- end
- packet=textutils.unserialize(packet)
- --type check packet and packet fields
- if type(packet)~="table" or type(packet["box"])~="string" or type(packet["hash"])~="string" then
- return false, nil
- end
- --get and unserialize box
- local serializedBox=packet["box"]
- local box=textutils.unserialize(serializedBox)
- --type check box
- if type(box)~="table" or type(box["time0"])~="number" or type(box["day0"])~="number" then
- return false, nil
- end
- --CHANGED
- --check that time stamps aren't to old
- local delay1=timeDiff(time2,day2,box["time0"],box["day0"])
- if delay1>maxDelay then
- return false, nil
- end
- --NEW
- --check that the time stamps in the packet isn't from the future
- --this can happen if a message is created, the ingame time is turned back, and the message is received
- --then previously sent commands could be accepted even though they are old commands
- --This could still happen if attacker resends old new command before maxDelay after the time stamp
- if delay1<0 then
- return false, nil
- end
- --check that the hash is correct
- --this is so that only someone with the secret can send a message that is ok
- local hashValue=hashFunction(serializedBox..secret)
- if hashValue~=packet["hash"] then
- return false, nil
- end
- --check that the same message haven't been sent
- --this is so that the same command message can't be resent by an attacker
- if packet["hash"]==lastHash then
- return false, nil
- end
- --CHANGED
- --check that the time stamp isn't earlier than the last ok message
- --this is so that an earlier command can't be sent by an attacker to override a later command
- local delay2=timeDiff(lastTime,lastDay,box["time0"],box["day0"])
- if delay2>0 then
- return false, nil
- end
- --passed all tests
- --update latest ok message hash
- --update latest ok message time
- lastHash=packet["hash"]
- lastTime=box["time0"]
- lastDay=box["day0"]
- --return ok and message
- return true, box["data"]
- end
- end
- --returns the time difference in seconds
- --is used in verifier
- --the returned value is like taking t1-t2
- function timeDiff(time1,day1,time2,day2)
- --converts to minecraft ingame hours
- local minecraftDiff=(day1-day2)*24+(time1-time2)
- --converts to real seconds
- local secondsDiff=minecraftDiff*((20/24)*60)
- return secondsDiff
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement