Hi all,
A very talented colleague of mine has now come up with a lua script that handles the XXTEA encryption algorithm and it works a treat for us! I thought that I could post the code here in case someone else has a similar need. I hope it will help someone as much as it helped us.
There are three files needed (code below):
- xxtea.lua
- bit.lua
- hex.lua
xxtea.lua:
---------------------------------------------------------------------
-- Author: Jørn Skaarud Karlsen
---------------------------------------------------------------------
require("bit")
require("hex")
---------------------------------------------------------------------
-- Constants
---------------------------------------------------------------------
delta = 0x9E3779B9
---------------------------------------------------------------------
-- Conversion
---------------------------------------------------------------------
function convertStringToBytes(str)
local bytes = {}
local strLength = string.len(str)
for i=1,strLength do
table.insert(bytes, string.byte(str, i))
end
return bytes
end
function convertBytesToString(bytes)
local bytesLength = table.getn(bytes)
local str = ""
for i=1,bytesLength do
str = str .. string.char(bytes[i])
end
return str
end
function convertHexStringToBytes(str)
local bytes = {}
local strLength = string.len(str)
for k=2,strLength,2 do
local hexString = "0x" .. string.sub(str, (k - 1), k)
table.insert(bytes, hex.to\_dec(hexString))
end
return bytes
end
function convertBytesToHexString(bytes)
local str = ""
local bytesLength = table.getn(bytes)
for i=1,bytesLength do
local hexString = string.sub(hex.to\_hex(bytes[i]), 3)
if string.len(hexString) == 1 then
hexString = "0" .. hexString
end
str = str .. hexString
end
return str
end
function convertBytesToUIntArray(bytes, includeLength)
local bytesLength = table.getn(bytes)
local result = {}
if includeLength then
local n = bit.brshift(bytesLength, 2) + 1
if bit.band(bytesLength, 3) ~= 0 then
n = n + 1
end
result[n] = bytesLength;
end
for i=0,(bytesLength - 1) do
local resultIndex = bit.brshift(i, 2) + 1
if result[resultIndex] == nil then
result[resultIndex] = 0
end
local resultValue = bit.blshift(bit.band(0x000000ff, bytes[i+1]), bit.blshift(bit.band(i, 3), 3))
result[resultIndex] = bit.bor(result[resultIndex], resultValue);
end
return result
end
function convertUIntArrayToBytes(data, includeLength)
local dataLength = table.getn(data)
local n = bit.blshift(dataLength, 2)
local result = {}
if includeLength then
local m = data[dataLength]
if m \> n then
return nil
end
n = m
end
for i=0,(n-1) do
local value = bit.band(bit.brshift(data[bit.brshift(i, 2) + 1], (bit.blshift(bit.band(i, 3), 3))), 0xff)
table.insert(result, value)
end
return result
end
function convertToUInt32(value)
if value \< 0 then
local absValue = math.abs(value)
local a = math.floor(absValue / 0xFFFFFFFF)
local b = value + a \* 0xFFFFFFFF
local c = 0xFFFFFFFF + b + 1
return c
end
return math.mod(value, 0xFFFFFFFF) - math.floor(value / 0xFFFFFFFF)
end
---------------------------------------------------------------------
-- Encryption/decryption common
---------------------------------------------------------------------
function mx(sum, y, z, p, e, k)
local aa = bit.brshift(z, 5)
local ab = convertToUInt32(bit.blshift(y, 2))
local ac = bit.bxor(aa, ab)
local ba = bit.brshift(y, 3)
local bb = convertToUInt32(bit.blshift(z, 4))
local bc = bit.bxor(ba, bb)
local ca = bit.bxor(sum, y)
local dia = bit.band(p, 3)
local dib = bit.bxor(dia, e)
local da = k[dib + 1]
local db = bit.bxor(da, z)
local ea = convertToUInt32(ca + db)
local fa = convertToUInt32(ac + bc)
local ga = bit.bxor(fa, ea)
return ga
end
---------------------------------------------------------------------
-- Decryption
---------------------------------------------------------------------
function decryptIntArray(v, k)
local n = table.getn(v)
local z = v[n]
local y = v[1]
local e = 0
local p = 0
local q = 6 + math.floor(52 / n)
local sum = convertToUInt32(q \* delta)
while sum ~= 0 do
e = bit.band(bit.brshift(sum, 2), 3)
for p=n,2,-1 do
z = v[p - 1]
v[p] = convertToUInt32(v[p] - mx(sum, y, z, (p-1), e, k))
y = v[p]
end
z = v[n]
v[1] = convertToUInt32(v[1] - mx(sum, y, z, p, e, k))
y = v[1]
local sumBefore = sum
sum = convertToUInt32(sum - delta)
end
return v
end
function decrypt(data, key)
local dataLength = string.len(data)
local keyLength = string.len(key)
if keyLength == 0 then
return data
end
local keyBytes = convertStringToBytes(key)
local encryptedBytes = convertHexStringToBytes(data)
local dataIntArray = convertBytesToUIntArray(encryptedBytes, false)
local keyIntArray = convertBytesToUIntArray(keyBytes, false)
local decryptedIntArray = decryptIntArray(dataIntArray, keyIntArray)
local decryptedBytes = convertUIntArrayToBytes(decryptedIntArray, true)
local decryptedString = convertBytesToString(decryptedBytes)
return decryptedString
end
---------------------------------------------------------------------
-- Encryption
---------------------------------------------------------------------
function encryptIntArray(v, k)
n = table.getn(v)
if n \< 2 then
return v
end
local z = v[n]
local y = v[1]
local sum = 0
local e = 0
local p = 0
local initQ = 6 + math.floor(52 / n)
for q=initQ,1,-1 do
sum = convertToUInt32(sum + delta);
e = bit.band(bit.brshift(sum, 2), 3);
for p=1,(n-1) do
y = v[p + 1];
v[p] = convertToUInt32(v[p] + mx(sum, y, z, (p-1), e, k));
z = v[p]
end
y = v[1];
v[n] = convertToUInt32(v[n] + mx(sum, y, z, (n-1), e, k));
z = v[n]
end
return v;
end
function encrypt(data, key)
local dataLength = string.len(data)
local keyLength = string.len(key)
if (keyLength == 0) then
return data
end
local dataBytes = convertStringToBytes(data)
local keyBytes = convertStringToBytes(key)
local dataIntArray = convertBytesToUIntArray(dataBytes, true)
local keyIntArray = convertBytesToUIntArray(keyBytes, false)
local encryptedIntArray = encryptIntArray(dataIntArray, keyIntArray)
local encryptedBytes = convertUIntArrayToBytes(encryptedIntArray, false)
local encryptedString = convertBytesToHexString(encryptedBytes)
return encryptedString
end
---------------------------------------------------------------------
-- Program: replace
---------------------------------------------------------------------
unencryptedInput = "This is a test"
encryptionKeyInput = "xxxxxxxxxxxxxxxxxxxx" -- Place your encryption key here
encryptedOutput = encrypt(unencryptedInput, encryptionKeyInput)
print(encryptedOutput)
decryptedEncryptedOutput = decrypt(encryptedOutput, encryptionKeyInput)
print(decryptedEncryptedOutput)
bit.lua:
--[[---------------
LuaBit v0.4
-------------------
a bitwise operation lib for lua.
http://luaforge.net/projects/bit/
How to use:
-------------------
bit.bnot(n) -- bitwise not (~n)
bit.band(m, n) -- bitwise and (m & n)
bit.bor(m, n) -- bitwise or (m | n)
bit.bxor(m, n) -- bitwise xor (m ^ n)
bit.brshift(n, bits) -- right shift (n \>\> bits)
bit.blshift(n, bits) -- left shift (n \<\< bits)
bit.blogic\_rshift(n, bits) -- logic right shift(zero fill \>\>\>)
Please note that bit.brshift and bit.blshift only support number within
32 bits.
2 utility functions are provided too:
bit.tobits(n) -- convert n into a bit table(which is a 1/0 sequence)
-- high bits first
bit.tonumb(bit\_tbl) -- convert a bit table into a number
-------------------
Under the MIT license.
copyright(c) 2006~2007 hanzhao (abrash\_han@hotmail.com)
--]]---------------
do
------------------------
-- bit lib implementions
local function check\_int(n)
-- checking not float
if(n - math.floor(n) \> 0) then
error("trying to use bitwise operation on non-integer!")
end
end
local function to\_bits(n)
check\_int(n)
if(n \< 0) then
-- negative
return to\_bits(bit.bnot(math.abs(n)) + 1)
end
-- to bits table
local tbl = {}
local cnt = 1
while (n \> 0) do
local last = math.mod(n,2)
if(last == 1) then
tbl[cnt] = 1
else
tbl[cnt] = 0
end
n = (n-last)/2
cnt = cnt + 1
end
return tbl
end
local function tbl\_to\_number(tbl)
local n = table.getn(tbl)
local rslt = 0
local power = 1
for i = 1, n do
rslt = rslt + tbl[i]\*power
power = power\*2
end
return rslt
end
local function expand(tbl\_m, tbl\_n)
local big = {}
local small = {}
if(table.getn(tbl\_m) \> table.getn(tbl\_n)) then
big = tbl\_m
small = tbl\_n
else
big = tbl\_n
small = tbl\_m
end
-- expand small
for i = table.getn(small) + 1, table.getn(big) do
small[i] = 0
end
end
local function bit\_or(m, n)
local tbl\_m = to\_bits(m)
local tbl\_n = to\_bits(n)
expand(tbl\_m, tbl\_n)
local tbl = {}
local rslt = math.max(table.getn(tbl\_m), table.getn(tbl\_n))
for i = 1, rslt do
if(tbl\_m[i]== 0 and tbl\_n[i] == 0) then
tbl[i] = 0
else
tbl[i] = 1
end
end
return tbl\_to\_number(tbl)
end
local function bit\_and(m, n)
local tbl\_m = to\_bits(m)
local tbl\_n = to\_bits(n)
expand(tbl\_m, tbl\_n)
local tbl = {}
local rslt = math.max(table.getn(tbl\_m), table.getn(tbl\_n))
for i = 1, rslt do
if(tbl\_m[i]== 0 or tbl\_n[i] == 0) then
tbl[i] = 0
else
tbl[i] = 1
end
end
return tbl\_to\_number(tbl)
end
local function bit\_not(n)
local tbl = to\_bits(n)
local size = math.max(table.getn(tbl), 32)
for i = 1, size do
if(tbl[i] == 1) then
tbl[i] = 0
else
tbl[i] = 1
end
end
return tbl\_to\_number(tbl)
end
local function bit\_xor(m, n)
local tbl\_m = to\_bits(m)
local tbl\_n = to\_bits(n)
expand(tbl\_m, tbl\_n)
local tbl = {}
local rslt = math.max(table.getn(tbl\_m), table.getn(tbl\_n))
for i = 1, rslt do
if(tbl\_m[i] ~= tbl\_n[i]) then
tbl[i] = 1
else
tbl[i] = 0
end
end
--table.foreach(tbl, print)
return tbl\_to\_number(tbl)
end
local function bit\_rshift(n, bits)
check\_int(n)
local high\_bit = 0
if(n \< 0) then
-- negative
n = bit\_not(math.abs(n)) + 1
high\_bit = 2147483648 -- 0x80000000
end
for i=1, bits do
n = n/2
n = bit\_or(math.floor(n), high\_bit)
end
return math.floor(n)
end
-- logic rightshift assures zero filling shift
local function bit\_logic\_rshift(n, bits)
check\_int(n)
if(n \< 0) then
-- negative
n = bit\_not(math.abs(n)) + 1
end
for i=1, bits do
n = n/2
end
return math.floor(n)
end
local function bit\_lshift(n, bits)
check\_int(n)
if(n \< 0) then
-- negative
n = bit\_not(math.abs(n)) + 1
end
for i=1, bits do
n = n\*2
end
return bit\_and(n, 4294967295) -- 0xFFFFFFFF
end
local function bit\_xor2(m, n)
local rhs = bit\_or(bit\_not(m), bit\_not(n))
local lhs = bit\_or(m, n)
local rslt = bit\_and(lhs, rhs)
return rslt
end
--------------------
-- bit lib interface
bit = {
-- bit operations
bnot = bit\_not,
band = bit\_and,
bor = bit\_or,
bxor = bit\_xor,
brshift = bit\_rshift,
blshift = bit\_lshift,
bxor2 = bit\_xor2,
blogic\_rshift = bit\_logic\_rshift,
-- utility func
tobits = to\_bits,
tonumb = tbl\_to\_number,
}
end
--[[
for i = 1, 100 do
for j = 1, 100 do
if(bit.bxor(i, j) ~= bit.bxor2(i, j)) then
error("bit.xor failed.")
end
end
end
--]]
hex.lua:
--[[---------------
Hex v0.4
-------------------
Hex conversion lib for lua.
How to use:
hex.to\_hex(n) -- convert a number to a hex string
hex.to\_dec(hex) -- convert a hex string(prefix with '0x' or '0X') to number
Part of LuaBit(http://luaforge.net/projects/bit/).
Under the MIT license.
copyright(c) 2006~2007 hanzhao (abrash\_han@hotmail.com)
--]]---------------
require 'bit'
do
local function to\_hex(n)
if(type(n) ~= "number") then
error("non-number type passed in.")
end
-- checking not float
if(n - math.floor(n) \> 0) then
error("trying to apply bitwise operation on non-integer!")
end
if(n \< 0) then
-- negative
n = bit.tobits(bit.bnot(math.abs(n)) + 1)
n = bit.tonumb(n)
end
hex\_tbl = {'A', 'B', 'C', 'D', 'E', 'F'}
hex\_str = ""
while(n ~= 0) do
last = math.mod(n, 16)
if(last \< 10) then
hex\_str = tostring(last) .. hex\_str
else
hex\_str = hex\_tbl[last-10+1] .. hex\_str
end
n = math.floor(n/16)
end
if(hex\_str == "") then
hex\_str = "0"
end
return "0x" .. hex\_str
end
local function to\_dec(hex)
if(type(hex) ~= "string") then
error("non-string type passed in.")
end
head = string.sub(hex, 1, 2)
if( head ~= "0x" and head ~= "0X") then
error("wrong hex format, should lead by 0x or 0X.")
end
v = tonumber(string.sub(hex, 3), 16)
return v;
end
--------------------
-- hex lib interface
hex = {
to\_dec = to\_dec,
to\_hex = to\_hex,
}
end
--[[
-- test
d = 4341688
h = to\_hex(d)
print(h)
print(to\_dec(h))
for i = 1, 100000 do
h = hex.to\_hex(i)
d = hex.to\_dec(h)
if(d ~= i) then
error("failed " .. i .. ", " .. h)
end
end
--]]
[import]uid: 18203 topic_id: 6291 reply_id: 24664[/import]