local function _W(f) local e=setmetatable({}, {__index = _ENV or getfenv()}) if setfenv then setfenv(f, e) end return f(e) or e end local bit=_W(function(_ENV, ...) --[[     This bit API is designed to cope with unsigned integers instead of normal integers       To do this we add checks for overflows: (x > 2^31 ? x - 2 ^ 32 : x)     These are written in long form because no constant folding. ]]   local floor = math.floor   local lshift, rshift   rshift = function(a,disp)     return floor(a % 4294967296 / 2^disp) end   lshift = function(a,disp)     return (a * 2^disp) % 4294967296 end   return {     -- bit operations     bnot = bit.bnot,     band = bit.band,     bor  = bit.bor,     bxor = bit.bxor,     rshift = rshift,     lshift = lshift, } end) local gf=_W(function(_ENV, ...) -- finite field with base 2 and modulo irreducible polynom x^8+x^4+x^3+x+1 = 0x11d local bxor = bit.bxor local lshift = bit.lshift   -- private data of gf local n = 0x100 local ord = 0xff local irrPolynom = 0x11b local exp = {} local log = {}   -- -- add two polynoms (its simply xor) -- local function add(operand1, operand2)     return bxor(operand1,operand2) end   -- -- subtract two polynoms (same as addition) -- local function sub(operand1, operand2)     return bxor(operand1,operand2) end   -- -- inverts element -- a^(-1) = g^(order - log(a)) -- local function invert(operand)     -- special case for 1     if (operand == 1) then         return 1     end     -- normal invert     local exponent = ord - log[operand]     return exp[exponent] end   -- -- multiply two elements using a logarithm table -- a*b = g^(log(a)+log(b)) -- local function mul(operand1, operand2)     if (operand1 == 0 or operand2 == 0) then         return 0     end       local exponent = log[operand1] + log[operand2]     if (exponent >= ord) then         exponent = exponent - ord     end     return  exp[exponent] end   -- -- divide two elements -- a/b = g^(log(a)-log(b)) -- local function div(operand1, operand2)     if (operand1 == 0)  then         return 0     end     -- TODO: exception if operand2 == 0     local exponent = log[operand1] - log[operand2]     if (exponent < 0) then         exponent = exponent + ord     end     return exp[exponent] end   -- -- print logarithmic table -- local function printLog()     for i = 1, n do         print("log(", i-1, ")=", log[i-1])     end end   -- -- print exponentiation table -- local function printExp()     for i = 1, n do         print("exp(", i-1, ")=", exp[i-1])     end end   -- -- calculate logarithmic and exponentiation table -- local function initMulTable()     local a = 1       for i = 0,ord-1 do         exp[i] = a         log[a] = i           -- multiply with generator x+1 -> left shift + 1         a = bxor(lshift(a, 1), a)           -- if a gets larger than order, reduce modulo irreducible polynom         if a > ord then             a = sub(a, irrPolynom)         end     end end   initMulTable()   return {     add = add,     sub = sub,     invert = invert,     mul = mul,     div = dib,     printLog = printLog,     printExp = printExp, } end) util=_W(function(_ENV, ...) -- Cache some bit operators local bxor = bit.bxor local rshift = bit.rshift local band = bit.band local lshift = bit.lshift   local sleepCheckIn -- -- calculate the parity of one byte -- local function byteParity(byte)     byte = bxor(byte, rshift(byte, 4))     byte = bxor(byte, rshift(byte, 2))     byte = bxor(byte, rshift(byte, 1))     return band(byte, 1) end   -- -- get byte at position index -- local function getByte(number, index)     if (index == 0) then         return band(number,0xff)     else         return band(rshift(number, index*8),0xff)     end end     -- -- put number into int at position index -- local function putByte(number, index)     if (index == 0) then         return band(number,0xff)     else         return lshift(band(number,0xff),index*8)     end end   -- -- convert byte array to int array -- local function bytesToInts(bytes, start, n)     local ints = {}     for i = 0, n - 1 do         ints[i + 1] =                 putByte(bytes[start + (i*4)], 3) +                 putByte(bytes[start + (i*4) + 1], 2) +                 putByte(bytes[start + (i*4) + 2], 1) +                 putByte(bytes[start + (i*4) + 3], 0)           if n % 10000 == 0 then sleepCheckIn() end     end     return ints end   -- -- convert int array to byte array -- local function intsToBytes(ints, output, outputOffset, n)     n = n or #ints     for i = 0, n - 1 do         for j = 0,3 do             output[outputOffset + i*4 + (3 - j)] = getByte(ints[i + 1], j)         end           if n % 10000 == 0 then sleepCheckIn() end     end     return output end   -- -- convert bytes to hexString -- local function bytesToHex(bytes)     local hexBytes = ""       for i,byte in ipairs(bytes) do         hexBytes = hexBytes .. string.format("%02x ", byte)     end       return hexBytes end   local function hexToBytes(bytes)     local out = {}     for i = 1, #bytes, 2 do         out[#out + 1] = tonumber(bytes:sub(i, i + 1), 16)     end       return out end   -- -- convert data to hex string -- local function toHexString(data)     local type = type(data)     if (type == "number") then         return string.format("%08x",data)     elseif (type == "table") then         return bytesToHex(data)     elseif (type == "string") then         local bytes = {string.byte(data, 1, #data)}           return bytesToHex(bytes)     else         return data     end end   local function padByteString(data)     local dataLength = #data       local random1 = math.random(0,255)     local random2 = math.random(0,255)       local prefix = string.char(random1,         random2,         random1,         random2,         getByte(dataLength, 3),         getByte(dataLength, 2),         getByte(dataLength, 1),         getByte(dataLength, 0)     )       data = prefix .. data       local paddingLength = math.ceil(#data/16)*16 - #data     local padding = ""     for i=1,paddingLength do         padding = padding .. string.char(math.random(0,255))     end       return data .. padding end   local function properlyDecrypted(data)     local random = {string.byte(data,1,4)}       if (random[1] == random[3] and random[2] == random[4]) then         return true     end       return false end   local function unpadByteString(data)     if (not properlyDecrypted(data)) then         return nil     end       local dataLength = putByte(string.byte(data,5), 3)                      + putByte(string.byte(data,6), 2)                      + putByte(string.byte(data,7), 1)                      + putByte(string.byte(data,8), 0)       return string.sub(data,9,8+dataLength) end   local function xorIV(data, iv)     for i = 1,16 do         data[i] = bxor(data[i], iv[i])     end end   local function increment(data)     local i = 16     while true do         local value = data[i] + 1         if value >= 256 then             data[i] = value - 256             i = (i - 2) % 16 + 1         else             data[i] = value             break         end     end end   -- Called every encryption cycle local push, pull, time = os.queueEvent, coroutine.yield, os.time local oldTime = time() local function sleepCheckIn()     local newTime = time()     if newTime - oldTime >= 0.03 then -- (0.020 * 1.5)         oldTime = newTime         push("sleep")         pull("sleep")     end end   local function getRandomData(bytes)     local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert     local result = {}       for i=1,bytes do         insert(result, random(0,255))         if i % 10240 == 0 then sleep() end     end       return result end   local function getRandomString(bytes)     local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert     local result = {}       for i=1,bytes do         insert(result, char(random(0,255)))         if i % 10240 == 0 then sleep() end     end       return table.concat(result) end   return {     byteParity = byteParity,     getByte = getByte,     putByte = putByte,     bytesToInts = bytesToInts,     intsToBytes = intsToBytes,     bytesToHex = bytesToHex,     hexToBytes = hexToBytes,     toHexString = toHexString,     padByteString = padByteString,     properlyDecrypted = properlyDecrypted,     unpadByteString = unpadByteString,     xorIV = xorIV,     increment = increment,       sleepCheckIn = sleepCheckIn,       getRandomData = getRandomData,     getRandomString = getRandomString, } end) aes=_W(function(_ENV, ...) -- Implementation of AES with nearly pure lua -- AES with lua is slow, really slow :-)   local putByte = util.putByte local getByte = util.getByte   -- some constants local ROUNDS = 'rounds' local KEY_TYPE = "type" local ENCRYPTION_KEY=1 local DECRYPTION_KEY=2   -- aes SBOX local SBox = {} local iSBox = {}   -- aes tables local table0 = {} local table1 = {} local table2 = {} local table3 = {}   local tableInv0 = {} local tableInv1 = {} local tableInv2 = {} local tableInv3 = {}   -- round constants local rCon = {     0x01000000,     0x02000000,     0x04000000,     0x08000000,     0x10000000,     0x20000000,     0x40000000,     0x80000000,     0x1b000000,     0x36000000,     0x6c000000,     0xd8000000,     0xab000000,     0x4d000000,     0x9a000000,     0x2f000000, }   -- -- affine transformation for calculating the S-Box of AES -- local function affinMap(byte)     mask = 0xf8     result = 0     for i = 1,8 do         result = bit.lshift(result,1)           parity = util.byteParity(bit.band(byte,mask))         result = result + parity           -- simulate roll         lastbit = bit.band(mask, 1)         mask = bit.band(bit.rshift(mask, 1),0xff)         if (lastbit ~= 0) then             mask = bit.bor(mask, 0x80)         else             mask = bit.band(mask, 0x7f)         end     end       return bit.bxor(result, 0x63) end   -- -- calculate S-Box and inverse S-Box of AES -- apply affine transformation to inverse in finite field 2^8 -- local function calcSBox()     for i = 0, 255 do     if (i ~= 0) then         inverse = gf.invert(i)     else         inverse = i     end         mapped = affinMap(inverse)         SBox[i] = mapped         iSBox[mapped] = i     end end   -- -- Calculate round tables -- round tables are used to calculate shiftRow, MixColumn and SubBytes -- with 4 table lookups and 4 xor operations. -- local function calcRoundTables()     for x = 0,255 do         byte = SBox[x]         table0[x] = putByte(gf.mul(0x03, byte), 0)                           + putByte(             byte , 1)                           + putByte(             byte , 2)                           + putByte(gf.mul(0x02, byte), 3)         table1[x] = putByte(             byte , 0)                           + putByte(             byte , 1)                           + putByte(gf.mul(0x02, byte), 2)                           + putByte(gf.mul(0x03, byte), 3)         table2[x] = putByte(             byte , 0)                           + putByte(gf.mul(0x02, byte), 1)                           + putByte(gf.mul(0x03, byte), 2)                           + putByte(             byte , 3)         table3[x] = putByte(gf.mul(0x02, byte), 0)                           + putByte(gf.mul(0x03, byte), 1)                           + putByte(             byte , 2)                           + putByte(             byte , 3)     end end   -- -- Calculate inverse round tables -- does the inverse of the normal roundtables for the equivalent -- decryption algorithm. -- local function calcInvRoundTables()     for x = 0,255 do         byte = iSBox[x]         tableInv0[x] = putByte(gf.mul(0x0b, byte), 0)                              + putByte(gf.mul(0x0d, byte), 1)                              + putByte(gf.mul(0x09, byte), 2)                              + putByte(gf.mul(0x0e, byte), 3)         tableInv1[x] = putByte(gf.mul(0x0d, byte), 0)                              + putByte(gf.mul(0x09, byte), 1)                              + putByte(gf.mul(0x0e, byte), 2)                              + putByte(gf.mul(0x0b, byte), 3)         tableInv2[x] = putByte(gf.mul(0x09, byte), 0)                              + putByte(gf.mul(0x0e, byte), 1)                              + putByte(gf.mul(0x0b, byte), 2)                              + putByte(gf.mul(0x0d, byte), 3)         tableInv3[x] = putByte(gf.mul(0x0e, byte), 0)                              + putByte(gf.mul(0x0b, byte), 1)                              + putByte(gf.mul(0x0d, byte), 2)                              + putByte(gf.mul(0x09, byte), 3)     end end     -- -- rotate word: 0xaabbccdd gets 0xbbccddaa -- used for key schedule -- local function rotWord(word)     local tmp = bit.band(word,0xff000000)     return (bit.lshift(word,8) + bit.rshift(tmp,24)) end   -- -- replace all bytes in a word with the SBox. -- used for key schedule -- local function subWord(word)     return putByte(SBox[getByte(word,0)],0)         + putByte(SBox[getByte(word,1)],1)         + putByte(SBox[getByte(word,2)],2)         + putByte(SBox[getByte(word,3)],3) end   -- -- generate key schedule for aes encryption -- -- returns table with all round keys and -- the necessary number of rounds saved in [ROUNDS] -- local function expandEncryptionKey(key)     local keySchedule = {}     local keyWords = math.floor(#key / 4)         if ((keyWords ~= 4 and keyWords ~= 6 and keyWords ~= 8) or (keyWords * 4 ~= #key)) then         error("Invalid key size: " .. tostring(keyWords))         return nil     end       keySchedule[ROUNDS] = keyWords + 6     keySchedule[KEY_TYPE] = ENCRYPTION_KEY       for i = 0,keyWords - 1 do         keySchedule[i] = putByte(key[i*4+1], 3)                        + putByte(key[i*4+2], 2)                        + putByte(key[i*4+3], 1)                        + putByte(key[i*4+4], 0)     end       for i = keyWords, (keySchedule[ROUNDS] + 1)*4 - 1 do         local tmp = keySchedule[i-1]           if ( i % keyWords == 0) then             tmp = rotWord(tmp)             tmp = subWord(tmp)               local index = math.floor(i/keyWords)             tmp = bit.bxor(tmp,rCon[index])         elseif (keyWords > 6 and i % keyWords == 4) then             tmp = subWord(tmp)         end           keySchedule[i] = bit.bxor(keySchedule[(i-keyWords)],tmp)     end       return keySchedule end   -- -- Inverse mix column -- used for key schedule of decryption key -- local function invMixColumnOld(word)     local b0 = getByte(word,3)     local b1 = getByte(word,2)     local b2 = getByte(word,1)     local b3 = getByte(word,0)       return putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b1),                                              gf.mul(0x0d, b2)),                                              gf.mul(0x09, b3)),                                              gf.mul(0x0e, b0)),3)          + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b2),                                              gf.mul(0x0d, b3)),                                              gf.mul(0x09, b0)),                                              gf.mul(0x0e, b1)),2)          + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b3),                                              gf.mul(0x0d, b0)),                                              gf.mul(0x09, b1)),                                              gf.mul(0x0e, b2)),1)          + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b0),                                              gf.mul(0x0d, b1)),                                              gf.mul(0x09, b2)),                                              gf.mul(0x0e, b3)),0) end   -- -- Optimized inverse mix column -- look at http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf -- TODO: make it work -- local function invMixColumn(word)     local b0 = getByte(word,3)     local b1 = getByte(word,2)     local b2 = getByte(word,1)     local b3 = getByte(word,0)       local t = bit.bxor(b3,b2)     local u = bit.bxor(b1,b0)     local v = bit.bxor(t,u)     v = bit.bxor(v,gf.mul(0x08,v))     w = bit.bxor(v,gf.mul(0x04, bit.bxor(b2,b0)))     v = bit.bxor(v,gf.mul(0x04, bit.bxor(b3,b1)))       return putByte( bit.bxor(bit.bxor(b3,v), gf.mul(0x02, bit.bxor(b0,b3))), 0)          + putByte( bit.bxor(bit.bxor(b2,w), gf.mul(0x02, t              )), 1)          + putByte( bit.bxor(bit.bxor(b1,v), gf.mul(0x02, bit.bxor(b0,b3))), 2)          + putByte( bit.bxor(bit.bxor(b0,w), gf.mul(0x02, u              )), 3) end   -- -- generate key schedule for aes decryption -- -- uses key schedule for aes encryption and transforms each -- key by inverse mix column. -- local function expandDecryptionKey(key)     local keySchedule = expandEncryptionKey(key)     if (keySchedule == nil) then         return nil     end       keySchedule[KEY_TYPE] = DECRYPTION_KEY       for i = 4, (keySchedule[ROUNDS] + 1)*4 - 5 do         keySchedule[i] = invMixColumnOld(keySchedule[i])     end       return keySchedule end   -- -- xor round key to state -- local function addRoundKey(state, key, round)     for i = 0, 3 do         state[i + 1] = bit.bxor(state[i + 1], key[round*4+i])     end end   -- -- do encryption round (ShiftRow, SubBytes, MixColumn together) -- local function doRound(origState, dstState)     dstState[1] =  bit.bxor(bit.bxor(bit.bxor(                 table0[getByte(origState[1],3)],                 table1[getByte(origState[2],2)]),                 table2[getByte(origState[3],1)]),                 table3[getByte(origState[4],0)])       dstState[2] =  bit.bxor(bit.bxor(bit.bxor(                 table0[getByte(origState[2],3)],                 table1[getByte(origState[3],2)]),                 table2[getByte(origState[4],1)]),                 table3[getByte(origState[1],0)])       dstState[3] =  bit.bxor(bit.bxor(bit.bxor(                 table0[getByte(origState[3],3)],                 table1[getByte(origState[4],2)]),                 table2[getByte(origState[1],1)]),                 table3[getByte(origState[2],0)])       dstState[4] =  bit.bxor(bit.bxor(bit.bxor(                 table0[getByte(origState[4],3)],                 table1[getByte(origState[1],2)]),                 table2[getByte(origState[2],1)]),                 table3[getByte(origState[3],0)]) end   -- -- do last encryption round (ShiftRow and SubBytes) -- local function doLastRound(origState, dstState)     dstState[1] = putByte(SBox[getByte(origState[1],3)], 3)                 + putByte(SBox[getByte(origState[2],2)], 2)                 + putByte(SBox[getByte(origState[3],1)], 1)                 + putByte(SBox[getByte(origState[4],0)], 0)       dstState[2] = putByte(SBox[getByte(origState[2],3)], 3)                 + putByte(SBox[getByte(origState[3],2)], 2)                 + putByte(SBox[getByte(origState[4],1)], 1)                 + putByte(SBox[getByte(origState[1],0)], 0)       dstState[3] = putByte(SBox[getByte(origState[3],3)], 3)                 + putByte(SBox[getByte(origState[4],2)], 2)                 + putByte(SBox[getByte(origState[1],1)], 1)                 + putByte(SBox[getByte(origState[2],0)], 0)       dstState[4] = putByte(SBox[getByte(origState[4],3)], 3)                 + putByte(SBox[getByte(origState[1],2)], 2)                 + putByte(SBox[getByte(origState[2],1)], 1)                 + putByte(SBox[getByte(origState[3],0)], 0) end   -- -- do decryption round -- local function doInvRound(origState, dstState)     dstState[1] =  bit.bxor(bit.bxor(bit.bxor(                 tableInv0[getByte(origState[1],3)],                 tableInv1[getByte(origState[4],2)]),                 tableInv2[getByte(origState[3],1)]),                 tableInv3[getByte(origState[2],0)])       dstState[2] =  bit.bxor(bit.bxor(bit.bxor(                 tableInv0[getByte(origState[2],3)],                 tableInv1[getByte(origState[1],2)]),                 tableInv2[getByte(origState[4],1)]),                 tableInv3[getByte(origState[3],0)])       dstState[3] =  bit.bxor(bit.bxor(bit.bxor(                 tableInv0[getByte(origState[3],3)],                 tableInv1[getByte(origState[2],2)]),                 tableInv2[getByte(origState[1],1)]),                 tableInv3[getByte(origState[4],0)])       dstState[4] =  bit.bxor(bit.bxor(bit.bxor(                 tableInv0[getByte(origState[4],3)],                 tableInv1[getByte(origState[3],2)]),                 tableInv2[getByte(origState[2],1)]),                 tableInv3[getByte(origState[1],0)]) end   -- -- do last decryption round -- local function doInvLastRound(origState, dstState)     dstState[1] = putByte(iSBox[getByte(origState[1],3)], 3)                 + putByte(iSBox[getByte(origState[4],2)], 2)                 + putByte(iSBox[getByte(origState[3],1)], 1)                 + putByte(iSBox[getByte(origState[2],0)], 0)       dstState[2] = putByte(iSBox[getByte(origState[2],3)], 3)                 + putByte(iSBox[getByte(origState[1],2)], 2)                 + putByte(iSBox[getByte(origState[4],1)], 1)                 + putByte(iSBox[getByte(origState[3],0)], 0)       dstState[3] = putByte(iSBox[getByte(origState[3],3)], 3)                 + putByte(iSBox[getByte(origState[2],2)], 2)                 + putByte(iSBox[getByte(origState[1],1)], 1)                 + putByte(iSBox[getByte(origState[4],0)], 0)       dstState[4] = putByte(iSBox[getByte(origState[4],3)], 3)                 + putByte(iSBox[getByte(origState[3],2)], 2)                 + putByte(iSBox[getByte(origState[2],1)], 1)                 + putByte(iSBox[getByte(origState[1],0)], 0) end   -- -- encrypts 16 Bytes -- key           encryption key schedule -- input         array with input data -- inputOffset   start index for input -- output        array for encrypted data -- outputOffset  start index for output -- local function encrypt(key, input, inputOffset, output, outputOffset)     --default parameters     inputOffset = inputOffset or 1     output = output or {}     outputOffset = outputOffset or 1       local state = {}     local tmpState = {}       if (key[KEY_TYPE] ~= ENCRYPTION_KEY) then         error("No encryption key: " .. tostring(key[KEY_TYPE]) .. ", expected " .. ENCRYPTION_KEY)         return     end       state = util.bytesToInts(input, inputOffset, 4)     addRoundKey(state, key, 0)         local round = 1     while (round < key[ROUNDS] - 1) do         -- do a double round to save temporary assignments         doRound(state, tmpState)         addRoundKey(tmpState, key, round)         round = round + 1           doRound(tmpState, state)         addRoundKey(state, key, round)         round = round + 1     end       doRound(state, tmpState)     addRoundKey(tmpState, key, round)     round = round +1       doLastRound(tmpState, state)     addRoundKey(state, key, round)       util.sleepCheckIn()     return util.intsToBytes(state, output, outputOffset) end   -- -- decrypt 16 bytes -- key           decryption key schedule -- input         array with input data -- inputOffset   start index for input -- output        array for decrypted data -- outputOffset  start index for output --- local function decrypt(key, input, inputOffset, output, outputOffset)     -- default arguments     inputOffset = inputOffset or 1     output = output or {}     outputOffset = outputOffset or 1       local state = {}     local tmpState = {}       if (key[KEY_TYPE] ~= DECRYPTION_KEY) then         error("No decryption key: " .. tostring(key[KEY_TYPE]))         return     end       state = util.bytesToInts(input, inputOffset, 4)     addRoundKey(state, key, key[ROUNDS])       local round = key[ROUNDS] - 1     while (round > 2) do         -- do a double round to save temporary assignments         doInvRound(state, tmpState)         addRoundKey(tmpState, key, round)         round = round - 1           doInvRound(tmpState, state)         addRoundKey(state, key, round)         round = round - 1     end         doInvRound(state, tmpState)     addRoundKey(tmpState, key, round)     round = round - 1       doInvLastRound(tmpState, state)     addRoundKey(state, key, round)       util.sleepCheckIn()     return util.intsToBytes(state, output, outputOffset) end   -- calculate all tables when loading this file calcSBox() calcRoundTables() calcInvRoundTables()   return {     ROUNDS = ROUNDS,     KEY_TYPE = KEY_TYPE,     ENCRYPTION_KEY = ENCRYPTION_KEY,     DECRYPTION_KEY = DECRYPTION_KEY,       expandEncryptionKey = expandEncryptionKey,     expandDecryptionKey = expandDecryptionKey,     encrypt = encrypt,     decrypt = decrypt, } end) local buffer=_W(function(_ENV, ...) local function new ()     return {} end   local function addString (stack, s)     table.insert(stack, s) end   local function toString (stack)     return table.concat(stack) end   return {     new = new,     addString = addString,     toString = toString, } end) ciphermode=_W(function(_ENV, ...) local public = {}   -- -- Encrypt strings -- key - byte array with key -- string - string to encrypt -- modefunction - function for cipher mode to use --   local random = math.random function public.encryptString(key, data, modeFunction, iv)     if iv then         local ivCopy = {}         for i = 1, 16 do ivCopy[i] = iv[i] end         iv = ivCopy     else         iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}     end       local keySched = aes.expandEncryptionKey(key)     local encryptedData = buffer.new()       for i = 1, #data/16 do         local offset = (i-1)*16 + 1         local byteData = {string.byte(data,offset,offset +15)}           iv = modeFunction(keySched, byteData, iv)           buffer.addString(encryptedData, string.char(unpack(byteData)))     end       return buffer.toString(encryptedData) end   -- -- the following 4 functions can be used as -- modefunction for encryptString --   -- Electronic code book mode encrypt function function public.encryptECB(keySched, byteData, iv)     aes.encrypt(keySched, byteData, 1, byteData, 1) end   -- Cipher block chaining mode encrypt function function public.encryptCBC(keySched, byteData, iv)     util.xorIV(byteData, iv)     aes.encrypt(keySched, byteData, 1, byteData, 1)     return byteData end   -- Output feedback mode encrypt function function public.encryptOFB(keySched, byteData, iv)     aes.encrypt(keySched, iv, 1, iv, 1)     util.xorIV(byteData, iv)     return iv end   -- Cipher feedback mode encrypt function function public.encryptCFB(keySched, byteData, iv)     aes.encrypt(keySched, iv, 1, iv, 1)     util.xorIV(byteData, iv)     return byteData end   function public.encryptCTR(keySched, byteData, iv)     local nextIV = {}     for j = 1, 16 do nextIV[j] = iv[j] end       aes.encrypt(keySched, iv, 1, iv, 1)     util.xorIV(byteData, iv)       util.increment(nextIV)       return nextIV end   -- -- Decrypt strings -- key - byte array with key -- string - string to decrypt -- modefunction - function for cipher mode to use -- function public.decryptString(key, data, modeFunction, iv)     if iv then         local ivCopy = {}         for i = 1, 16 do ivCopy[i] = iv[i] end         iv = ivCopy     else         iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}     end       local keySched     if modeFunction == public.decryptOFB or modeFunction == public.decryptCFB or modeFunction == public.decryptCTR then         keySched = aes.expandEncryptionKey(key)     else         keySched = aes.expandDecryptionKey(key)     end       local decryptedData = buffer.new()       for i = 1, #data/16 do         local offset = (i-1)*16 + 1         local byteData = {string.byte(data,offset,offset +15)}           iv = modeFunction(keySched, byteData, iv)           buffer.addString(decryptedData, string.char(unpack(byteData)))     end       return buffer.toString(decryptedData) end   -- -- the following 4 functions can be used as -- modefunction for decryptString --   -- Electronic code book mode decrypt function function public.decryptECB(keySched, byteData, iv)     aes.decrypt(keySched, byteData, 1, byteData, 1)     return iv end   -- Cipher block chaining mode decrypt function function public.decryptCBC(keySched, byteData, iv)     local nextIV = {}     for j = 1, 16 do nextIV[j] = byteData[j] end       aes.decrypt(keySched, byteData, 1, byteData, 1)     util.xorIV(byteData, iv)       return nextIV end   -- Output feedback mode decrypt function function public.decryptOFB(keySched, byteData, iv)     aes.encrypt(keySched, iv, 1, iv, 1)     util.xorIV(byteData, iv)       return iv end   -- Cipher feedback mode decrypt function function public.decryptCFB(keySched, byteData, iv)     local nextIV = {}     for j = 1, 16 do nextIV[j] = byteData[j] end       aes.encrypt(keySched, iv, 1, iv, 1)     util.xorIV(byteData, iv)       return nextIV end   public.decryptCTR = public.encryptCTR   return public end) -- Simple API for encrypting strings. -- AES128 = 16 AES192 = 24 AES256 = 32   ECBMODE = 1 CBCMODE = 2 OFBMODE = 3 CFBMODE = 4 CTRMODE = 4   local function pwToKey(password, keyLength, iv)     local padLength = keyLength     if (keyLength == AES192) then         padLength = 32     end       if (padLength > #password) then         local postfix = ""         for i = 1,padLength - #password do             postfix = postfix .. string.char(0)         end         password = password .. postfix     else         password = string.sub(password, 1, padLength)     end       local pwBytes = {string.byte(password,1,#password)}     password = ciphermode.encryptString(pwBytes, password, ciphermode.encryptCBC, iv)       password = string.sub(password, 1, keyLength)       return {string.byte(password,1,#password)} end   -- -- Encrypts string data with password password. -- password  - the encryption key is generated from this string -- data      - string to encrypt (must not be too large) -- keyLength - length of aes key: 128(default), 192 or 256 Bit -- mode      - mode of encryption: ecb, cbc(default), ofb, cfb -- -- mode and keyLength must be the same for encryption and decryption. -- function encrypt(password, data, keyLength, mode, iv)     assert(password ~= nil, "Empty password.")     assert(password ~= nil, "Empty data.")       local mode = mode or CBCMODE     local keyLength = keyLength or AES128       local key = pwToKey(password, keyLength, iv)       local paddedData = util.padByteString(data)       if mode == ECBMODE then         return ciphermode.encryptString(key, paddedData, ciphermode.encryptECB, iv)     elseif mode == CBCMODE then         return ciphermode.encryptString(key, paddedData, ciphermode.encryptCBC, iv)     elseif mode == OFBMODE then         return ciphermode.encryptString(key, paddedData, ciphermode.encryptOFB, iv)     elseif mode == CFBMODE then         return ciphermode.encryptString(key, paddedData, ciphermode.encryptCFB, iv)     elseif mode == CTRMODE then         return ciphermode.encryptString(key, paddedData, ciphermode.encryptCTR, iv)     else         error("Unknown mode", 2)     end end         -- -- Decrypts string data with password password. -- password  - the decryption key is generated from this string -- data      - string to encrypt -- keyLength - length of aes key: 128(default), 192 or 256 Bit -- mode      - mode of decryption: ecb, cbc(default), ofb, cfb -- -- mode and keyLength must be the same for encryption and decryption. -- function decrypt(password, data, keyLength, mode, iv)     local mode = mode or CBCMODE     local keyLength = keyLength or AES128       local key = pwToKey(password, keyLength, iv)       local plain     if mode == ECBMODE then         plain = ciphermode.decryptString(key, data, ciphermode.decryptECB, iv)     elseif mode == CBCMODE then         plain = ciphermode.decryptString(key, data, ciphermode.decryptCBC, iv)     elseif mode == OFBMODE then         plain = ciphermode.decryptString(key, data, ciphermode.decryptOFB, iv)     elseif mode == CFBMODE then         plain = ciphermode.decryptString(key, data, ciphermode.decryptCFB, iv)     elseif mode == CTRMODE then         plain = ciphermode.decryptString(key, data, ciphermode.decryptCTR, iv)     else         error("Unknown mode", 2)     end       result = util.unpadByteString(plain)       if (result == nil) then         return nil     end       return result end