This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Cozzimoto's profile picture

Problem Decrypting String To Test If A Valid Table Exists

Started by Cozzimoto, 08 October 2013 - 01:16 AM
Cozzimoto #1
Posted 08 October 2013 - 03:16 AM
Hello all and welcome. i think i am a little confused at the error i am getting so ill let you in on my secret.

First i am building a client server program for a banking system. everything i am writing is my own code and ive got it down to decrypting messages on the server.

the setup i have is two test computers one as the target bank server and the other as a client just to send over encrypted data. my encryption algorithm has two parts to modify the text inputed. it has a key which can be any number, and a password. the password. so on each server and client i have hardcoded in several keys and passwords so i can see if the server can decode the encrypted text given that the client randomly chose a pair key and password to encrypt the important data with.

the current way i have it works, but there is an issue with the textutils.unserialize that i am running into.

the example data i am sending over is: {ptl="cConnect",cid=os.getComputerID(),data={},}

i am basically turning a table into a string then encrypting it which still remains a string to send over rednet.

the server takes the rawdata and runs through the keys and passwords to find a table.

i use the textutils.unserialize for every action then test to see if the function returns a table or a string.

i am only seeing if i get a table then i test to see if i have my two keys in the table i originally sent IE: ptl and cid

like i said it works but there is a wierd error i am getting for the serialize function.

the client does what i need it to the error is happening on the serverside so ill post the server code. if you ask for the client code to test yourselves just let me know.

i am also adding in screenshots of the client and server so show that the code was working in decrypting the data but only on one instance was i getting an error.

Spoiler

local contains = function(tbl,val)
  for k,v in pairs(tbl) do
	if v == val then return true end
  end
  return false
end

local hash = function(str)
  local out = {}
  for s in str:gmatch(".") do
	if not contains(out,s) then out[#out+1] = s end
  end
  return table.concat(out)
end

local encryption = function(decrypt,plainTXT,key,password)
  local cipher,cipherTXT = "",""
  local base = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789=+[]{}-_,." '

  if key ~= nil and key > #base then  -- keep key within bounds of base length
	key = key % #base
  end

  if password ~= nil then  -- place password at front of encryption without duplicates	
	cipher = hash(password)
  end

  for i=1,#base do -- create the cipher
	local CHAR = string.sub(base,(key+i)%#base,(key+i)%#base)

	if password ~= nil then
	  for I=1,#password do -- find the same letter in password & remove it
		local pasChar = string.sub(password,I,I)

		if pasChar == CHAR then
		  CHAR = ""
		end
	  end
	end
	cipher = cipher..CHAR
  end

  if type(plainTXT) == "table" then
	plainTXT = textutils.serialize(plainTXT)
  end

  for i=1,#plainTXT do -- loop through text for encryption
	local letter = string.sub(plainTXT,i,i)

	for I=1,#base do
	  local baseKey = string.sub(base,I,I)
	  local hashKey = string.sub(cipher,I,I)

	  if decrypt == true then -- if decrypting flip flop baseKey & hashKey
		if letter == hashKey then
		  cipherTXT = cipherTXT..baseKey
		end
	  else
		if letter == baseKey then -- encrypt baseKey with hashKey
		  cipherTXT = cipherTXT..hashKey
		end
	  end
	end
  end
  return cipherTXT
end

local keys = {6,117,24,48,372}
local pass = {"squIrrel","ClasSic","BlankeT","challenger"}

local m = peripheral.wrap("top")
m.open(2)

while true do
  local ev = { os.pullEvent() }
  local bfD = ""
  local pkg = {}

  if ev[1] == "modem_message" then
	local rawData = ev[5]

	for i=1,#keys do
	  for I=1,#pass do
		bfD = encryption(true,rawData,keys[i],pass[I])

		local isTable = textutils.unserialize(bfD)
		if type(isTable) == "table" and isTable["ptl"] and isTable["cid"] then
		  pkg["data"] = isTable
		  pkg["key"] = keys[i]
		  pkg["pwd"] = pass[I]
		end
	  end
	end
  end

  print(pkg["data"])
  print("Decrypted w/: "..pkg["key"].."  |"..pkg["pwd"])
end
ElvishJerricco #2
Posted 08 October 2013 - 05:44 AM
Ok when you say you're sending "{ptl="cConnect",cid=os.getComputerID(),data={},}" over the network, are you doing

local s = '{ptl="cConnect",cid=os.getComputerID(),data={},}'
send(s)
or

local t = {ptl="cConnect",cid=os.getComputerID(),data={},}
send(textutils.serialize(t))

If it's the first, the problem is that you're sending a string which calls the function os.getComputerID() when it gets loaded. Problem is, textutils.unserialize doesn't let the loaded table call any APIs, so that "os" table it's trying to index is nil.
jay5476 #3
Posted 08 October 2013 - 05:54 AM
you can actually send tables over rednet so you can do

rednet.send(id,{table1={"moretables"}})
and that should work perfectly fine if your having trouble try loading the table before sending it eg.

yourtable = {tableinfo}
rednet.send(id,yourtable)
Cozzimoto #4
Posted 08 October 2013 - 03:16 PM
Spoiler
Ok when you say you're sending "{ptl="cConnect",cid=os.getComputerID(),data={},}" over the network, are you doing

local s = '{ptl="cConnect",cid=os.getComputerID(),data={},}'
send(s)
or

local t = {ptl="cConnect",cid=os.getComputerID(),data={},}
send(textutils.serialize(t))

If it's the first, the problem is that you're sending a string which calls the function os.getComputerID() when it gets loaded. Problem is, textutils.unserialize doesn't let the loaded table call any APIs, so that "os" table it's trying to index is nil.

i am actually doing the second option. the original data is a table which i then turn into a string then encrypt the string to send over a modem on a specific channel


Spoiler
you can actually send tables over rednet so you can do

rednet.send(id,{table1={"moretables"}})
and that should work perfectly fine if your having trouble try loading the table before sending it eg.

yourtable = {tableinfo}
rednet.send(id,yourtable)

if a send a table over rednet i o not have the option to encrypt it, which is why im turning it into a string before hand
Bomb Bloke #5
Posted 08 October 2013 - 08:50 PM
You attempt to unserialise whatever your decryption attempt returns before deciding whether the decryption was successful, resulting in random gibberish being passed to textutils. Gibberish which can potentially take the form of an equation it may try to resolve, resulting in referrences to variables that don't exist and hence random error messages from the interpretor.

Obviously textutils shouldn't do this, but your answer is to implement your own "does this string represent a table?" check before you try and unserialise.
AgentE382 #6
Posted 08 October 2013 - 10:46 PM
Yeah, basically your encryption function is broken. You don't check its results, either. You should probably do that and add some debug prints to tell you exactly where your encryption function is going wrong.

Or, you could just switch to a real encryption algorithm that has been thoroughly tested. Someone here's got an AES implementation, I've got RC4, and I've seen a few other real algorithms in pure Lua elsewhere on the net.
Cozzimoto #7
Posted 09 October 2013 - 12:09 AM
Spoiler
You attempt to unserialise whatever your decryption attempt returns before deciding whether the decryption was successful, resulting in random gibberish being passed to textutils. Gibberish which can potentially take the form of an equation it may try to resolve, resulting in referrences to variables that don't exist and hence random error messages from the interpretor.

Obviously textutils shouldn't do this, but your answer is to implement your own "does this string represent a table?" check before you try and unserialise.

so how would i go about doing that, using a regEx to see if i can find the arguments i need before i try and pass it through textutils.unserialize?

Spoiler
Yeah, basically your encryption function is broken. You don't check its results, either. You should probably do that and add some debug prints to tell you exactly where your encryption function is going wrong.

Or, you could just switch to a real encryption algorithm that has been thoroughly tested. Someone here's got an AES implementation, I've got RC4, and I've seen a few other real algorithms in pure Lua elsewhere on the net.

well you dont need to go about and say its broken and not suggest anything. i built it myself and ive tested it and it does work, so obviously its not broken, you are not really helping me in finding a solution to the situation by just telling my to give up and go with someone else's code.
Bomb Bloke #8
Posted 09 October 2013 - 01:13 AM
so how would i go about doing that, using a regEx to see if i can find the arguments i need before i try and pass it through textutils.unserialize?
That's probably the best way to do it. I'd just turn this:

			    local isTable = textutils.unserialize(bfD)
			    if type(isTable) == "table" and isTable["ptl"] and isTable["cid"] then
				  pkg["data"] = isTable
				  pkg["key"] = keys[i]
				  pkg["pwd"] = pass[I]
			    end

… to this:

			    if string.sub(bfD,1,1) == "{" and string.sub(bfD,#bfD,#bfD) == "}" then
				  local isTable = textutils.unserialize(bfD)
				  if type(isTable) == "table" and isTable["ptl"] and isTable["cid"] then
				    pkg["data"] = isTable
				    pkg["key"] = keys[i]
				    pkg["pwd"] = pass[I]
				  end
			    end
AgentE382 #9
Posted 09 October 2013 - 05:42 AM
EDIT: I just rewrote this post because I was still being offensive and didn't solve your problem. I apologize if you read it before this edit.

Basically, Bomb Bloke's right. That should fix your problem. A faster way to do it, though, would be:
-- after your encryption function
local isTable
if string.find(bfD, "%b{}") then    -- find a matching set of braces
    isTable = textutils.unserialize(bfD)
end
if type(bfD) == "table" and isTable["pt1"] and isTable["cid"] then
    -- rest of your code here

I'm so sorry for any frustration or anger I have caused. I also apologize for assuming your encryption was broken without any cryptanalysis.

<Edited Original>

Spoiler
You attempt to unserialise whatever your decryption attempt returns before deciding whether the decryption was successful, resulting in random gibberish being passed to textutils. Gibberish which can potentially take the form of an equation it may try to resolve, resulting in referrences to variables that don't exist and hence random error messages from the interpretor.

Obviously textutils shouldn't do this, but your answer is to implement your own "does this string represent a table?" check before you try and unserialise.

so how would i go about doing that, using a regEx to see if i can find the arguments i need before i try and pass it through textutils.unserialize?

Spoiler
Yeah, basically your encryption function is broken. You don't check its results, either. You should probably do that and add some debug prints to tell you exactly where your encryption function is going wrong.

Or, you could just switch to a real encryption algorithm that has been thoroughly tested. Someone here's got an AES implementation, I've got RC4, and I've seen a few other real algorithms in pure Lua elsewhere on the net.

well you dont need to go about and say its broken and not suggest anything. i built it myself and ive tested it and it does work, so obviously its not broken, you are not really helping me in finding a solution to the situation by just telling my to give up and go with someone else's code.

I apologize if I was offensive I wasn't trying to be. It was late.

I did, however, suggest something:
<snip>
You don't check its results.
<snip>
You should probably do that and add some debug prints to tell you exactly where your encryption function is going wrong.

Have you tested that your function works with every combination of inputs you are giving it? If so, why didn't you say that in the first place?

It's good practice to add debug prints to your program if there's an error to see why you're getting the error. That way, you can tell exactly when it failed and what caused it to choke.

I suggest that you go through each line and ask yourself "How can I break this?", then write an error-check for whatever can go wrong. Using a unit testing library would help, too, but that'd kinda' be overkill.

Also, I didn't tell you to use someone else's code. Feel free to re-implement AES. My point is that home-brewed encryption algorithms are never guaranteed to be secure at all, though what you have is better than what I usually see. On principle, as a certified IT security professional, I would never use any encryption algorithm that wasn't subjected to extreme testing and severe academic review by some of the best minds in cryptology.

You know, the number + key input to your algorithm would translate perfectly into an IV + key for AES.

</Edited Original>
Edited on 09 October 2013 - 06:17 AM
Cozzimoto #10
Posted 10 October 2013 - 04:13 PM
Spoiler
so how would i go about doing that, using a regEx to see if i can find the arguments i need before i try and pass it through textutils.unserialize?
That's probably the best way to do it. I'd just turn this:

				local isTable = textutils.unserialize(bfD)
				if type(isTable) == "table" and isTable["ptl"] and isTable["cid"] then
				  pkg["data"] = isTable
				  pkg["key"] = keys[i]
				  pkg["pwd"] = pass[I]
				end

… to this:

				if string.sub(bfD,1,1) == "{" and string.sub(bfD,#bfD,#bfD) == "}" then
				  local isTable = textutils.unserialize(bfD)
				  if type(isTable) == "table" and isTable["ptl"] and isTable["cid"] then
					pkg["data"] = isTable
					pkg["key"] = keys[i]
					pkg["pwd"] = pass[I]
				  end
				end

ok thanks bomb Bloke ill test this later tonight i dont have much free time today, but ill get back with everyone on this after i do some more testing.