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

Encryption help

Started by Saldor010, 28 November 2014 - 10:36 PM
Saldor010 #1
Posted 28 November 2014 - 11:36 PM
Hello people of the interwebs! I could use some help finding a good encryption API to use. I've already tried SquidDev's AES encryption, but it wasn't very useful, due to the fact that it doesn't yield. So when I tried it on a large file, it crashed the computer. So I could really use your guy's help finding a computercraft encryption API (Not hashing. I need to be able to read it back later) that periodically yields.

Thanks in advance!
Edited on 28 November 2014 - 10:37 PM
Exerro #2
Posted 29 November 2014 - 12:03 AM
Well, RC4 is one that comes to mind. First link on google after searching "RC4 lua" was this. Next one I found was this which was actually written for computercraft.

Other than that, I wrote my own a while back, which Nova uses. It's pretty secure I believe, but I've never actually tried to break it. If you'd like to use it, just ask and i'll put it on pastebin and send the link.

(my one yields automatically, but for the others, you'll probably have to add that in)
Edited on 28 November 2014 - 11:07 PM
Saldor010 #3
Posted 29 November 2014 - 12:36 AM
Well, RC4 is one that comes to mind. First link on google after searching "RC4 lua" was this. Next one I found was this which was actually written for computercraft.

Other than that, I wrote my own a while back, which Nova uses. It's pretty secure I believe, but I've never actually tried to break it. If you'd like to use it, just ask and i'll put it on pastebin and send the link.

(my one yields automatically, but for the others, you'll probably have to add that in)

I tried to add it in on AES encryption, but failed horribly. So I'd prefer if it was already added in by the creator.
Exerro #4
Posted 29 November 2014 - 12:56 AM
Spoiler

local function sum( n, ... )
local t = { ... }
for i = 1, #t do
  n = n + t[i]
end
return n
end
local function loop( n, lim )
while n > lim do
  n = n - lim
end
while n < 1 do
  n = n + lim
end
return n
end
local function shift( str, count )
local str = { str:byte( 1, #str ) }
for i = 1, #str do
  str[i] = loop( str[i] + count, 255 )
end
for i = 1, #str do
  str[i] = string.char( str[i] )
end
return table.concat( str, "" )
end
local function tohex( b )
local n = 0
for i = 1, 4 do
  n = n * 2
  n = n + tonumber( b:sub( i, i ) )
end
if n >= 10 then
  local hexes = { "A", "B", "C", "D", "E", "F" }
  return hexes[n - 9]
end
return tostring( n )
end
local function fromhex( h )
local n = tonumber( h )
if not n then
  local hexes = { ["A"] = 10, ["B"] = 11, ["C"] = 12, ["D"] = 13, ["E"] = 14, ["F"] = 15 }
  n = hexes[h]
end
local str = ""
for i = 1, 4 do
  str = str .. n % 2
  n = math.floor( n / 2 )
end
return str:reverse( )
end
local function xor( n1, n2 )
if n1 > 255 or n2 > 255 or n1 < 0 or n2 < 0 then
  return error "expected numbers between 0 and 255"
end
local bit1, bit2 = { }, { }
for i = 1, 8 do
  bit1[9-i] = n1 % 2 == 1
  n1 = math.floor( n1 / 2 )
end
for i = 1, 8 do
  bit2[9-i] = n2 % 2 == 1
  n2 = math.floor( n2 / 2 )
end
local bits = { }
for i = 1, 8 do
  bits[i] = ( bit1[i] and not bit2[i] ) or ( not bit1[i] and bit2[i] )
end
local n = 0
for i = 1, 8 do
  n = n * 2
  n = n + ( bits[i] and 1 or 0 )
end
return n
end
local function nand( n1, n2 )
if n1 > 255 or n2 > 255 or n1 < 0 or n2 < 0 then
  return error "expected numbers between 0 and 255"
end
local bit1, bit2 = { }, { }
for i = 1, 8 do
  bit1[9-i] = n1 % 2 == 1
  n1 = math.floor( n1 / 2 )
end
for i = 1, 8 do
  bit2[9-i] = n2 % 2 == 1
  n2 = math.floor( n2 / 2 )
end
local bits = { }
for i = 1, 8 do
  bits[i] = not bit1[i] == bit2[i]
end
local n = 0
for i = 1, 8 do
  n = n * 2
  n = n + ( bits[i] and 1 or 0 )
end
return n
end
local function tobits( n )
local str = ""
for i = 1, 8 do
  str = str .. n % 2
  n = math.floor( n / 2 )
end
return str:reverse( )
end
local function frombits( b )
local n = 0
for i = 1, 8 do
  n = n * 2
  n = n + tonumber( b:sub( i, i ) )
end
return n
end
local t = os.clock( )
local function start( )
t = os.clock( )
end
local function yield( )
if os.clock( ) - t > .1 then -- change the yield timeout here, by default, it yields every .1 seconds
  coroutine.yield( )
  start( )
end
end
function encrypt( str, key ) -- string text, string key
local enc = ""
start( )
for i = 1, #str do
  math.randomseed( sum( key:byte( 1, #key ) ) )
  key = shift( key, math.random( 1, 100 ) )
  local ki = loop( i, #key )
  local a = str:sub( i, i ):byte( )
  local b = key:sub( ki, ki ):byte( )
  enc = enc .. tobits( xor( a, b ) )
  yield( )
end
local enc2 = ""
for i = 1, #enc / 4 do
  enc2 = enc2 .. tohex( enc:sub( i * 4 - 3, i * 4 ) )
  yield( )
end
return enc2
-- string cipher
end
function decrypt( str, key ) -- string cipher, string key
start( )
local dec2 = ""
for i = 1, #str do
  dec2 = dec2 .. fromhex( str:sub( i, i ) )
  yield( )
end
str = dec2
local dec = ""
local keys = { }
for i = 1, #str / 8 do
  math.randomseed( sum( key:byte( 1, #key ) ) )
  keys[i] = shift( key, math.random( 1, 100 ) )
  key = keys[i]
  yield( )
end
for i = 1, #str / 8 do
  local ki = loop( i, #key )
  local a = frombits( str:sub( ( i - 1 ) * 8 + 1, i * 8 ) )
  local b = string.byte( keys[i]:sub( ki, ki ) )
  dec = dec .. string.char( nand( a, b ) )
  yield( )
end
return dec
-- string text
end

This mine. Not the fastest or most secure I'm sure, but it does yield so it won't TLWY and I can't see any major floors with it. It took about 5 seconds to encrypt a 1KB file I think, although I can remember being impressed, so it might be a bit better than this. The cipher will always be double the length of the text, which is probably a security floor or something, I'm not entirely sure. You'll have to ask an expert.

For you experts…
It is an xor cipher, that shifts the key a random amount before xoring each character of the text with a corresponding character from the key (no the key doesn't have to be the same length, it loops back round). I think this is quite secure, but I really don't know. I'd love to see someone try to hack it though and put it to the test.

Edit: it takes about .1 seconds to encrypt 1KB actually.
Edited on 29 November 2014 - 04:08 PM
Saldor010 #5
Posted 29 November 2014 - 01:23 AM
Spoiler

local function sum( n, ... )
local t = { ... }
for i = 1, #t do
  n = n + t[i]
end
return n
end
local function loop( n, lim )
while n > lim do
  n = n - lim
end
while n < 1 do
  n = n + lim
end
return n
end
local function shift( str, count )
local str = { str:byte( 1, #str ) }
for i = 1, #str do
  str[i] = loop( str[i] + count, 255 )
end
for i = 1, #str do
  str[i] = string.char( str[i] )
end
return table.concat( str, "" )
end
local function tohex( b )
local n = 0
for i = 1, 4 do
  n = n * 2
  n = n + tonumber( b:sub( i, i ) )
end
if n >= 10 then
  local hexes = { "A", "B", "C", "D", "E", "F" }
  return hexes[n - 9]
end
return tostring( n )
end
local function fromhex( h )
local n = tonumber( h )
if not n then
  local hexes = { ["A"] = 10, ["B"] = 11, ["C"] = 12, ["D"] = 13, ["E"] = 14, ["F"] = 15 }
  n = hexes[h]
end
local str = ""
for i = 1, 4 do
  str = str .. n % 2
  n = math.floor( n / 2 )
end
return str:reverse( )
end
local function xor( n1, n2 )
if n1 > 255 or n2 > 255 or n1 < 0 or n2 < 0 then
  return error "expected numbers between 0 and 255"
end
local bit1, bit2 = { }, { }
for i = 1, 8 do
  bit1[9-i] = n1 % 2 == 1
  n1 = math.floor( n1 / 2 )
end
for i = 1, 8 do
  bit2[9-i] = n2 % 2 == 1
  n2 = math.floor( n2 / 2 )
end
local bits = { }
for i = 1, 8 do
  bits[i] = ( bit1[i] and not bit2[i] ) or ( not bit1[i] and bit2[i] )
end
local n = 0
for i = 1, 8 do
  n = n * 2
  n = n + ( bits[i] and 1 or 0 )
end
return n
end
local function nand( n1, n2 )
if n1 > 255 or n2 > 255 or n1 < 0 or n2 < 0 then
  return error "expected numbers between 0 and 255"
end
local bit1, bit2 = { }, { }
for i = 1, 8 do
  bit1[9-i] = n1 % 2 == 1
  n1 = math.floor( n1 / 2 )
end
for i = 1, 8 do
  bit2[9-i] = n2 % 2 == 1
  n2 = math.floor( n2 / 2 )
end
local bits = { }
for i = 1, 8 do
  bits[i] = not bit1[i] == bit2[i]
end
local n = 0
for i = 1, 8 do
  n = n * 2
  n = n + ( bits[i] and 1 or 0 )
end
return n
end
local function tobits( n )
local str = ""
for i = 1, 8 do
  str = str .. n % 2
  n = math.floor( n / 2 )
end
return str:reverse( )
end
local function frombits( b )
local n = 0
for i = 1, 8 do
  n = n * 2
  n = n + tonumber( b:sub( i, i ) )
end
return n
end
local t = os.clock( )
local function start( )
t = os.clock( )
end
local function yield( )
if os.clock( ) - t > .1 then -- change the yield timeout here, by default, it yields every .1 seconds
  coroutine.yield( )
  start( )
end
end
function encrypt( str, key ) -- string text, string key
local enc = ""
start( )
for i = 1, #str do
  math.randomseed( sum( key:byte( 1, #key ) ) )
  key = shift( key, math.random( 1, 100 ) )
  local ki = loop( i, #key )
  local a = str:sub( i, i ):byte( )
  local b = key:sub( ki, ki ):byte( )
  enc = enc .. tobits( xor( a, b ) )
  yield( )
end
local enc2 = ""
for i = 1, #enc / 4 do
  enc2 = enc2 .. tohex( enc:sub( i * 4 - 3, i * 4 ) )
  yield( )
end
return enc2
-- string cipher
end
function decrypt( str, key ) -- string cipher, string key
start( )
local dec2 = ""
for i = 1, #str do
  dec2 = dec2 .. fromhex( str:sub( i, i ) )
  yield( )
end
str = dec2
local dec = ""
local keys = { }
for i = 1, #str / 8 do
  math.randomseed( sum( key:byte( 1, #key ) ) )
  keys[i] = shift( key, math.random( 1, 100 ) )
  key = keys[i]
  yield( )
end
for i = 1, #str / 8 do
  local ki = loop( i, #key )
  local a = frombits( str:sub( ( i - 1 ) * 8 + 1, i * 8 ) )
  local b = string.byte( keys[i]:sub( ki, ki ) )
  dec = dec .. string.char( nand( a, b ) )
  yield( )
end
return dec
-- string text
end

This mine. Not the fastest or most secure I'm sure, but it does yield so it won't TLWY and I can't see any major floors with it. It took about 5 seconds to encrypt a 1KB file I think, although I can remember being impressed, so it might be a bit better than this. The cipher will always be double the length of the text, which is probably a security floor or something, I'm not entirely sure. You'll have to ask an expert.

For you experts…
It is an xor cipher, that shifts the key a random amount before xoring each character of the text with a corresponding character from the key (no the key doesn't have to be the same length, it loops back round). I think this is quite secure, but I really don't know. I'd love to see someone try to hack it though and put it to the test.

I'll try it. ;)/>
Using the functions, not trying to break it.
Edited on 29 November 2014 - 12:23 AM
Saldor010 #6
Posted 29 November 2014 - 01:33 AM

str = str .. n % 2

Got attempt to perform arithmetic __mod on nil and number when I tried to decrypt (Sorry, I said encrypt the first time) the Quest (by oeed).

EDIT: I also get it when I just try to decrypt the word "Test" with key "Test"

EDIT EDIT: Okay, the only reason the above 2 situations didn't work, was because apparently your system doesn't like it when I try to decrypt programs that you haven't already encrypted using said system.
Edited on 29 November 2014 - 12:46 AM
Saldor010 #7
Posted 29 November 2014 - 02:16 AM
Okay, still on the look out for encryption algorithms. Sorry, awsumben, but your encryption algorithm is just too slow.
SquidDev #8
Posted 29 November 2014 - 11:21 AM
Just out of interest, how large files are you using? RainbowDashDC re-wrote the bit library so it should be quicker now. Adding yield support is on my todo list.
Exerro #9
Posted 29 November 2014 - 11:32 AM
You can change the yield time to speed it up. Right now, it yields every .1 seconds (so in Nova the UI can still function) but if you dont need that put it up to 2 or something.
Saldor010 #10
Posted 29 November 2014 - 02:38 PM
Just out of interest, how large files are you using? RainbowDashDC re-wrote the bit library so it should be quicker now. Adding yield support is on my todo list.

well… Depends on how large the user's system is.. :P/>

Maybe 1 to 30 KB? As long as the user doesn't have a huge OS installed (Cough ONEOS Cough), there shouldn't be too much data on it.

And in case the moderators are wondering, NO, this has NO malicious intent. And in fact, is a program trying to prevent malicious intent.
jaredallard #11
Posted 29 November 2014 - 04:53 PM
Just out of interest, how large files are you using? RainbowDashDC re-wrote the bit library so it should be quicker now. Adding yield support is on my todo list.

well… Depends on how large the user's system is.. :P/>

Maybe 1 to 30 KB? As long as the user doesn't have a huge OS installed (Cough ONEOS Cough), there shouldn't be too much data on it.

And in case the moderators are wondering, NO, this has NO malicious intent. And in fact, is a program trying to prevent malicious intent.

aeslua as of right now can do 15 kb in around 3 seconds, which is below the yielding requirements. So, I'd say around 20 kb is the max for now until yielding is properly implemented
SquidDev #12
Posted 29 November 2014 - 05:54 PM
I've pushed a pre-release with yielding enabled. This massively drops the performance (6 to 5 kb/s) on my computer. I can handle 50kb now.
jaredallard #13
Posted 29 November 2014 - 07:04 PM
I've pushed a pre-release with yielding enabled. This massively drops the performance (6 to 5 kb/s) on my computer. I can handle 50kb now.

Still better than before, prehaps it can be slighly enhanced.
Anavrins #14
Posted 29 November 2014 - 11:12 PM
Spoiler

local function sum( n, ... )
local t = { ... }
for i = 1, #t do
  n = n + t[i]
end
return n
end
local function loop( n, lim )
while n > lim do
  n = n - lim
end
while n < 1 do
  n = n + lim
end
return n
end
local function shift( str, count )
local str = { str:byte( 1, #str ) }
for i = 1, #str do
  str[i] = loop( str[i] + count, 255 )
end
for i = 1, #str do
  str[i] = string.char( str[i] )
end
return table.concat( str, "" )
end
local function tohex( b )
local n = 0
for i = 1, 4 do
  n = n * 2
  n = n + tonumber( b:sub( i, i ) )
end
if n >= 10 then
  local hexes = { "A", "B", "C", "D", "E", "F" }
  return hexes[n - 9]
end
return tostring( n )
end
local function fromhex( h )
local n = tonumber( h )
if not n then
  local hexes = { ["A"] = 10, ["B"] = 11, ["C"] = 12, ["D"] = 13, ["E"] = 14, ["F"] = 15 }
  n = hexes[h]
end
local str = ""
for i = 1, 4 do
  str = str .. n % 2
  n = math.floor( n / 2 )
end
return str:reverse( )
end
local function xor( n1, n2 )
if n1 > 255 or n2 > 255 or n1 < 0 or n2 < 0 then
  return error "expected numbers between 0 and 255"
end
local bit1, bit2 = { }, { }
for i = 1, 8 do
  bit1[9-i] = n1 % 2 == 1
  n1 = math.floor( n1 / 2 )
end
for i = 1, 8 do
  bit2[9-i] = n2 % 2 == 1
  n2 = math.floor( n2 / 2 )
end
local bits = { }
for i = 1, 8 do
  bits[i] = ( bit1[i] and not bit2[i] ) or ( not bit1[i] and bit2[i] )
end
local n = 0
for i = 1, 8 do
  n = n * 2
  n = n + ( bits[i] and 1 or 0 )
end
return n
end
local function nand( n1, n2 )
if n1 > 255 or n2 > 255 or n1 < 0 or n2 < 0 then
  return error "expected numbers between 0 and 255"
end
local bit1, bit2 = { }, { }
for i = 1, 8 do
  bit1[9-i] = n1 % 2 == 1
  n1 = math.floor( n1 / 2 )
end
for i = 1, 8 do
  bit2[9-i] = n2 % 2 == 1
  n2 = math.floor( n2 / 2 )
end
local bits = { }
for i = 1, 8 do
  bits[i] = not bit1[i] == bit2[i]
end
local n = 0
for i = 1, 8 do
  n = n * 2
  n = n + ( bits[i] and 1 or 0 )
end
return n
end
local function tobits( n )
local str = ""
for i = 1, 8 do
  str = str .. n % 2
  n = math.floor( n / 2 )
end
return str:reverse( )
end
local function frombits( b )
local n = 0
for i = 1, 8 do
  n = n * 2
  n = n + tonumber( b:sub( i, i ) )
end
return n
end
local t = os.clock( )
local function start( )
t = os.clock( )
end
local function yield( )
if os.clock( ) - t > .1 then -- change the yield timeout here, by default, it yields every .1 seconds
  coroutine.yield( )
  start( )
end
end
function encrypt( str, key ) -- string text, string key
local enc = ""
start( )
for i = 1, #str do
  math.randomseed( sum( key:byte( 1, #key ) ) )
  key = shift( key, math.random( 1, 100 ) )
  local ki = loop( i, #key )
  local a = str:sub( i, i ):byte( )
  local b = key:sub( ki, ki ):byte( )
  enc = enc .. tobits( xor( a, b ) )
  yield( )
end
local enc2 = ""
for i = 1, #enc / 4 do
  enc2 = enc2 .. tohex( enc:sub( i * 4 - 3, i * 4 ) )
  yield( )
end
return enc2
-- string cipher
end
function decrypt( str, key ) -- string cipher, string key
start( )
local dec2 = ""
for i = 1, #str do
  dec2 = dec2 .. fromhex( str:sub( i, i ) )
  yield( )
end
str = dec2
local dec = ""
local keys = { }
for i = 1, #str / 8 do
  math.randomseed( sum( key:byte( 1, #key ) ) )
  keys[i] = shift( key, math.random( 1, 100 ) )
  key = keys[i]
  yield( )
end
for i = 1, #str / 8 do
  local ki = loop( i, #key )
  local a = frombits( str:sub( ( i - 1 ) * 8 + 1, i * 8 ) )
  local b = string.byte( keys[i]:sub( ki, ki ) )
  dec = dec .. string.char( nand( a, b ) )
  yield( )
end
return dec
-- string text
end

This mine. Not the fastest or most secure I'm sure, but it does yield so it won't TLWY and I can't see any major floors with it. It took about 5 seconds to encrypt a 1KB file I think, although I can remember being impressed, so it might be a bit better than this. The cipher will always be double the length of the text, which is probably a security floor or something, I'm not entirely sure. You'll have to ask an expert.

For you experts…
It is an xor cipher, that shifts the key a random amount before xoring each character of the text with a corresponding character from the key (no the key doesn't have to be the same length, it loops back round). I think this is quite secure, but I really don't know. I'd love to see someone try to hack it though and put it to the test.

Edit: it takes about .1 seconds to encrypt 1KB actually.
That is effectively the same thing as the Vigenere Cipher, and is weak, see https://www.youtube....h?v=P4z3jAOzT9I
Edited on 29 November 2014 - 10:18 PM
AgentE382 #15
Posted 06 December 2014 - 05:39 AM
Well, RC4 is one that comes to mind. First link on google after searching "RC4 lua" was this. Next one I found was this which was actually written for computercraft.
<snip>
Just out of interest, how large files are you using? RainbowDashDC re-wrote the bit library so it should be quicker now. Adding yield support is on my todo list.

well… Depends on how large the user's system is.. :P/>

Maybe 1 to 30 KB?
<snip>

I wrote the ComputerCraft RC4 implementation awsumben13 mentioned, and it's extremely optimized for Lua and CC. On my PC, it encrypts about 100KB/s. If you really need to encrypt more than 400KB (too long without yielding), you can encrypt the data in chunks. Since RC4 is a symmetric stream cipher, and my functions save state, you literally just break it into chunks, call the encryption function on each chunk in order, and combine the chunks. It will produce exactly the same ciphertext as if you had fed it all as one chunk.
Edited on 06 December 2014 - 04:40 AM