Skip to content

Instantly share code, notes, and snippets.

@looterz
Created December 26, 2017 03:18
Show Gist options
  • Save looterz/2fe749fffe1f74bd98a7089e8046fffe to your computer and use it in GitHub Desktop.
Save looterz/2fe749fffe1f74bd98a7089e8046fffe to your computer and use it in GitHub Desktop.
Pure Lua AES encryption (https://github.com/SquidDev-CC/aeslua)
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
local function e(n)
local s=setmetatable({},{__index=_ENV or getfenv()})if setfenv then setfenv(n,s)end;return n(s)or s end
local t=e(function(n,...)local s=math.floor;local h,r
r=function(d,l)return s(d%4294967296/2^l)end
h=function(d,l)return(d*2^l)%4294967296 end
return{bnot=bit.bnot,band=bit.band,bor=bit.bor,bxor=bit.bxor,rshift=r,lshift=h}end)
local a=e(function(n,...)local s=t.bxor;local h=t.lshift;local r=0x100;local d=0xff;local l=0x11b;local u={}local c={}
local function m(k,q)return s(k,q)end;local function f(k,q)return s(k,q)end
local function w(k)if(k==1)then return 1 end;local q=d-c[k]return u[q]end;local function y(k,q)if(k==0 or q==0)then return 0 end;local j=c[k]+c[q]
if(j>=d)then j=j-d end;return u[j]end
local function p(k,q)
if(k==0)then return 0 end;local j=c[k]-c[q]if(j<0)then j=j+d end;return u[j]end
local function v()for k=1,r do print("log(",k-1,")=",c[k-1])end end
local function b()for k=1,r do print("exp(",k-1,")=",u[k-1])end end;local function g()local k=1
for q=0,d-1 do u[q]=k;c[k]=q;k=s(h(k,1),k)if k>d then k=f(k,l)end end end;g()return
{add=m,sub=f,invert=w,mul=y,div=dib,printLog=v,printExp=b}end)
util=e(function(n,...)local s=t.bxor;local h=t.rshift;local r=t.band;local d=t.lshift;local l;local function u(O)O=s(O,h(O,4))
O=s(O,h(O,2))O=s(O,h(O,1))return r(O,1)end
local function c(O,I)if(I==0)then return
r(O,0xff)else return r(h(O,I*8),0xff)end end;local function m(O,I)
if(I==0)then return r(O,0xff)else return d(r(O,0xff),I*8)end end
local function f(O,I,N)local S={}
for H=0,N-1 do
S[H+1]=
m(O[I+ (H*4)],3)+m(O[I+ (H*4)+1],2)+
m(O[I+ (H*4)+2],1)+m(O[I+ (H*4)+3],0)if N%10000 ==0 then l()end end;return S end;local function w(O,I,N,S)S=S or#O;for H=0,S-1 do
for R=0,3 do I[N+H*4+ (3-R)]=c(O[H+1],R)end;if S%10000 ==0 then l()end end
return I end;local function y(O)local I=""
for N,S in
ipairs(O)do I=I..string.format("%02x ",S)end;return I end
local function p(O)local I={}for N=1,#O,2 do I[#I+1]=tonumber(O:sub(N,
N+1),16)end;return I end
local function v(O)local I=type(O)
if(I=="number")then return string.format("%08x",O)elseif
(I=="table")then return y(O)elseif(I=="string")then local N={string.byte(O,1,#O)}
return y(N)else return O end end
local function b(O)local I=#O;local N=math.random(0,255)local S=math.random(0,255)
local H=string.char(N,S,N,S,c(I,3),c(I,2),c(I,1),c(I,0))O=H..O;local R=math.ceil(#O/16)*16-#O;local D=""for L=1,R do D=D..
string.char(math.random(0,255))end;return O..D end
local function g(O)local I={string.byte(O,1,4)}if
(I[1]==I[3]and I[2]==I[4])then return true end;return false end
local function k(O)if(not g(O))then return nil end
local I=
m(string.byte(O,5),3)+
m(string.byte(O,6),2)+m(string.byte(O,7),1)+m(string.byte(O,8),0)return string.sub(O,9,8+I)end;local function q(O,I)for N=1,16 do O[N]=s(O[N],I[N])end end
local function j(O)
local I=16;while true do local N=O[I]+1
if N>=256 then O[I]=N-256;I=(I-2)%16+1 else O[I]=N;break end end end;local x,z,_=os.queueEvent,coroutine.yield,os.time;local E=_()
local function l()local O=_()if O-E>=0.03 then E=O
x("sleep")z("sleep")end end
local function T(O)local I,N,S,H=string.char,math.random,l,table.insert;local R={}for D=1,O do
H(R,N(0,255))if D%10240 ==0 then S()end end;return R end
local function A(O)local I,N,S,H=string.char,math.random,l,table.insert;local R={}for D=1,O do
H(R,I(N(0,255)))if D%10240 ==0 then S()end end
return table.concat(R)end
return
{byteParity=u,getByte=c,putByte=m,bytesToInts=f,intsToBytes=w,bytesToHex=y,hexToBytes=p,toHexString=v,padByteString=b,properlyDecrypted=g,unpadByteString=k,xorIV=q,increment=j,sleepCheckIn=l,getRandomData=T,getRandomString=A}end)
aes=e(function(n,...)local s=util.putByte;local h=util.getByte;local r='rounds'local d="type"local l=1;local u=2
local c={}local m={}local f={}local w={}local y={}local p={}local v={}local b={}local g={}local k={}
local q={0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,0x20000000,0x40000000,0x80000000,0x1b000000,0x36000000,0x6c000000,0xd8000000,0xab000000,0x4d000000,0x9a000000,0x2f000000}
local function j(M)mask=0xf8;result=0
for F=1,8 do result=t.lshift(result,1)
parity=util.byteParity(t.band(M,mask))result=result+parity;lastbit=t.band(mask,1)
mask=t.band(t.rshift(mask,1),0xff)
if(lastbit~=0)then mask=t.bor(mask,0x80)else mask=t.band(mask,0x7f)end end;return t.bxor(result,0x63)end;local function x()
for M=0,255 do if(M~=0)then inverse=a.invert(M)else inverse=M end
mapped=j(inverse)c[M]=mapped;m[mapped]=M end end
local function z()
for M=0,255 do
byte=c[M]
f[M]=
s(a.mul(0x03,byte),0)+s(byte,1)+s(byte,2)+s(a.mul(0x02,byte),3)w[M]=s(byte,0)+s(byte,1)+s(a.mul(0x02,byte),2)+
s(a.mul(0x03,byte),3)y[M]=
s(byte,0)+s(a.mul(0x02,byte),1)+s(a.mul(0x03,byte),2)+s(byte,3)p[M]=
s(a.mul(0x02,byte),0)+s(a.mul(0x03,byte),1)+s(byte,2)+s(byte,3)end end
local function _()
for M=0,255 do byte=m[M]
v[M]=
s(a.mul(0x0b,byte),0)+s(a.mul(0x0d,byte),1)+s(a.mul(0x09,byte),2)+
s(a.mul(0x0e,byte),3)
b[M]=
s(a.mul(0x0d,byte),0)+s(a.mul(0x09,byte),1)+s(a.mul(0x0e,byte),2)+
s(a.mul(0x0b,byte),3)
g[M]=
s(a.mul(0x09,byte),0)+s(a.mul(0x0e,byte),1)+s(a.mul(0x0b,byte),2)+
s(a.mul(0x0d,byte),3)
k[M]=
s(a.mul(0x0e,byte),0)+s(a.mul(0x0b,byte),1)+s(a.mul(0x0d,byte),2)+
s(a.mul(0x09,byte),3)end end;local function E(M)local F=t.band(M,0xff000000)return
(t.lshift(M,8)+t.rshift(F,24))end
local function T(M)return
s(c[h(M,0)],0)+s(c[h(M,1)],1)+s(c[h(M,2)],2)+
s(c[h(M,3)],3)end
local function A(M)local F={}local W=math.floor(#M/4)if(
(W~=4 and W~=6 and W~=8)or(W*4 ~=#M))then
error("Invalid key size: "..tostring(W))return nil end;F[r]=W+6;F[d]=l;for Y=0,W-1
do
F[Y]=
s(M[Y*4+1],3)+s(M[Y*4+2],2)+s(M[Y*4+3],1)+s(M[Y*4+4],0)end
for Y=W,(F[r]+1)*4-1 do
local P=F[Y-1]
if(Y%W==0)then P=E(P)P=T(P)local V=math.floor(Y/W)P=t.bxor(P,q[V])elseif(
W>6 and Y%W==4)then P=T(P)end;F[Y]=t.bxor(F[(Y-W)],P)end;return F end
local function O(M)local F=h(M,3)local W=h(M,2)local Y=h(M,1)local P=h(M,0)
return
s(a.add(a.add(a.add(a.mul(0x0b,W),a.mul(0x0d,Y)),a.mul(0x09,P)),a.mul(0x0e,F)),3)+
s(a.add(a.add(a.add(a.mul(0x0b,Y),a.mul(0x0d,P)),a.mul(0x09,F)),a.mul(0x0e,W)),2)+
s(a.add(a.add(a.add(a.mul(0x0b,P),a.mul(0x0d,F)),a.mul(0x09,W)),a.mul(0x0e,Y)),1)+
s(a.add(a.add(a.add(a.mul(0x0b,F),a.mul(0x0d,W)),a.mul(0x09,Y)),a.mul(0x0e,P)),0)end
local function I(M)local F=h(M,3)local W=h(M,2)local Y=h(M,1)local P=h(M,0)local V=t.bxor(P,Y)
local B=t.bxor(W,F)local G=t.bxor(V,B)G=t.bxor(G,a.mul(0x08,G))
w=t.bxor(G,a.mul(0x04,t.bxor(Y,F)))G=t.bxor(G,a.mul(0x04,t.bxor(P,W)))
return
s(t.bxor(t.bxor(P,G),a.mul(0x02,t.bxor(F,P))),0)+s(t.bxor(t.bxor(Y,w),a.mul(0x02,V)),1)+
s(t.bxor(t.bxor(W,G),a.mul(0x02,t.bxor(F,P))),2)+
s(t.bxor(t.bxor(F,w),a.mul(0x02,B)),3)end
local function N(M)local F=A(M)if(F==nil)then return nil end;F[d]=u;for W=4,(F[r]+1)*4-5 do
F[W]=O(F[W])end;return F end;local function S(M,F,W)
for Y=0,3 do M[Y+1]=t.bxor(M[Y+1],F[W*4+Y])end end
local function H(M,F)
F[1]=t.bxor(t.bxor(t.bxor(f[h(M[1],3)],w[h(M[2],2)]),y[h(M[3],1)]),p[h(M[4],0)])
F[2]=t.bxor(t.bxor(t.bxor(f[h(M[2],3)],w[h(M[3],2)]),y[h(M[4],1)]),p[h(M[1],0)])
F[3]=t.bxor(t.bxor(t.bxor(f[h(M[3],3)],w[h(M[4],2)]),y[h(M[1],1)]),p[h(M[2],0)])
F[4]=t.bxor(t.bxor(t.bxor(f[h(M[4],3)],w[h(M[1],2)]),y[h(M[2],1)]),p[h(M[3],0)])end
local function R(M,F)
F[1]=s(c[h(M[1],3)],3)+s(c[h(M[2],2)],2)+
s(c[h(M[3],1)],1)+s(c[h(M[4],0)],0)
F[2]=s(c[h(M[2],3)],3)+s(c[h(M[3],2)],2)+
s(c[h(M[4],1)],1)+s(c[h(M[1],0)],0)
F[3]=s(c[h(M[3],3)],3)+s(c[h(M[4],2)],2)+
s(c[h(M[1],1)],1)+s(c[h(M[2],0)],0)
F[4]=s(c[h(M[4],3)],3)+s(c[h(M[1],2)],2)+
s(c[h(M[2],1)],1)+s(c[h(M[3],0)],0)end
local function D(M,F)
F[1]=t.bxor(t.bxor(t.bxor(v[h(M[1],3)],b[h(M[4],2)]),g[h(M[3],1)]),k[h(M[2],0)])
F[2]=t.bxor(t.bxor(t.bxor(v[h(M[2],3)],b[h(M[1],2)]),g[h(M[4],1)]),k[h(M[3],0)])
F[3]=t.bxor(t.bxor(t.bxor(v[h(M[3],3)],b[h(M[2],2)]),g[h(M[1],1)]),k[h(M[4],0)])
F[4]=t.bxor(t.bxor(t.bxor(v[h(M[4],3)],b[h(M[3],2)]),g[h(M[2],1)]),k[h(M[1],0)])end
local function L(M,F)
F[1]=s(m[h(M[1],3)],3)+s(m[h(M[4],2)],2)+
s(m[h(M[3],1)],1)+s(m[h(M[2],0)],0)
F[2]=s(m[h(M[2],3)],3)+s(m[h(M[1],2)],2)+
s(m[h(M[4],1)],1)+s(m[h(M[3],0)],0)
F[3]=s(m[h(M[3],3)],3)+s(m[h(M[2],2)],2)+
s(m[h(M[1],1)],1)+s(m[h(M[4],0)],0)
F[4]=s(m[h(M[4],3)],3)+s(m[h(M[3],2)],2)+
s(m[h(M[2],1)],1)+s(m[h(M[1],0)],0)end
local function U(M,F,W,Y,P)W=W or 1;Y=Y or{}P=P or 1;local V={}local B={}if(M[d]~=l)then
error("No encryption key: "..
tostring(M[d])..", expected "..l)return end
V=util.bytesToInts(F,W,4)S(V,M,0)local G=1;while(G<M[r]-1)do H(V,B)S(B,M,G)G=G+1;H(B,V)S(V,M,G)
G=G+1 end;H(V,B)S(B,M,G)G=G+1;R(B,V)S(V,M,G)
util.sleepCheckIn()return util.intsToBytes(V,Y,P)end
local function C(M,F,W,Y,P)W=W or 1;Y=Y or{}P=P or 1;local V={}local B={}
if(M[d]~=u)then error("No decryption key: "..
tostring(M[d]))return end;V=util.bytesToInts(F,W,4)S(V,M,M[r])local G=M[r]-1;while(G>2)do
D(V,B)S(B,M,G)G=G-1;D(B,V)S(V,M,G)G=G-1 end;D(V,B)
S(B,M,G)G=G-1;L(B,V)S(V,M,G)util.sleepCheckIn()return
util.intsToBytes(V,Y,P)end;x()z()_()
return{ROUNDS=r,KEY_TYPE=d,ENCRYPTION_KEY=l,DECRYPTION_KEY=u,expandEncryptionKey=A,expandDecryptionKey=N,encrypt=U,decrypt=C}end)
local o=e(function(n,...)local function s()return{}end;local function h(d,l)table.insert(d,l)end;local function r(d)return
table.concat(d)end;return{new=s,addString=h,toString=r}end)
ciphermode=e(function(n,...)local s={}local h=math.random
function s.encryptString(r,d,l,u)if u then local f={}for w=1,16 do f[w]=u[w]end;u=f else
u={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}end
local c=aes.expandEncryptionKey(r)local m=o.new()for f=1,#d/16 do local w=(f-1)*16+1
local y={string.byte(d,w,w+15)}u=l(c,y,u)
o.addString(m,string.char(unpack(y)))end
return o.toString(m)end;function s.encryptECB(r,d,l)aes.encrypt(r,d,1,d,1)end;function s.encryptCBC(r,d,l)
util.xorIV(d,l)aes.encrypt(r,d,1,d,1)return d end;function s.encryptOFB(r,d,l)
aes.encrypt(r,l,1,l,1)util.xorIV(d,l)return l end;function s.encryptCFB(r,d,l)
aes.encrypt(r,l,1,l,1)util.xorIV(d,l)return d end
function s.encryptCTR(r,d,l)
local u={}for c=1,16 do u[c]=l[c]end;aes.encrypt(r,l,1,l,1)
util.xorIV(d,l)util.increment(u)return u end
function s.decryptString(r,d,l,u)if u then local f={}for w=1,16 do f[w]=u[w]end;u=f else
u={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}end;local c
if l==s.decryptOFB or
l==s.decryptCFB or l==s.decryptCTR then
c=aes.expandEncryptionKey(r)else c=aes.expandDecryptionKey(r)end;local m=o.new()for f=1,#d/16 do local w=(f-1)*16+1
local y={string.byte(d,w,w+15)}u=l(c,y,u)
o.addString(m,string.char(unpack(y)))end
return o.toString(m)end;function s.decryptECB(r,d,l)aes.decrypt(r,d,1,d,1)return l end;function s.decryptCBC(r,d,l)
local u={}for c=1,16 do u[c]=d[c]end;aes.decrypt(r,d,1,d,1)
util.xorIV(d,l)return u end;function s.decryptOFB(r,d,l)
aes.encrypt(r,l,1,l,1)util.xorIV(d,l)return l end;function s.decryptCFB(r,d,l)
local u={}for c=1,16 do u[c]=d[c]end;aes.encrypt(r,l,1,l,1)
util.xorIV(d,l)return u end
s.decryptCTR=s.encryptCTR;return s end)AES128=16;AES192=24;AES256=32;ECBMODE=1;CBCMODE=2;OFBMODE=3;CFBMODE=4;CTRMODE=4
local function i(n,s,h)local r=s;if(s==
AES192)then r=32 end
if(r>#n)then local l=""for u=1,r-#n do
l=l..string.char(0)end;n=n..l else n=string.sub(n,1,r)end;local d={string.byte(n,1,#n)}
n=ciphermode.encryptString(d,n,ciphermode.encryptCBC,h)n=string.sub(n,1,s)return{string.byte(n,1,#n)}end
function encrypt(n,s,h,r,d)assert(n~=nil,"Empty password.")
assert(n~=nil,"Empty data.")local r=r or CBCMODE;local h=h or AES128;local l=i(n,h,d)
local u=util.padByteString(s)
if r==ECBMODE then
return ciphermode.encryptString(l,u,ciphermode.encryptECB,d)elseif r==CBCMODE then
return ciphermode.encryptString(l,u,ciphermode.encryptCBC,d)elseif r==OFBMODE then
return ciphermode.encryptString(l,u,ciphermode.encryptOFB,d)elseif r==CFBMODE then
return ciphermode.encryptString(l,u,ciphermode.encryptCFB,d)elseif r==CTRMODE then
return ciphermode.encryptString(l,u,ciphermode.encryptCTR,d)else error("Unknown mode",2)end end
function decrypt(n,s,h,r,d)local r=r or CBCMODE;local h=h or AES128;local l=i(n,h,d)local u
if r==ECBMODE then
u=ciphermode.decryptString(l,s,ciphermode.decryptECB,d)elseif r==CBCMODE then
u=ciphermode.decryptString(l,s,ciphermode.decryptCBC,d)elseif r==OFBMODE then
u=ciphermode.decryptString(l,s,ciphermode.decryptOFB,d)elseif r==CFBMODE then
u=ciphermode.decryptString(l,s,ciphermode.decryptCFB,d)elseif r==CTRMODE then
u=ciphermode.decryptString(l,s,ciphermode.decryptCTR,d)else error("Unknown mode",2)end;result=util.unpadByteString(u)
if(result==nil)then return nil end;return result end
@looterz
Copy link
Author

looterz commented Jul 6, 2022

@valentinleistner SquidDev/SquidDev-CC's aes.lua is bases on bighil's aes.lua which is Licensed under the GNU Lesser General Public License. This can also bee seen on the webarchive.

SquidDev's aes.lua is written for ComputerCraft an mod for Minecraft, this is why it might malfunction.

The latest version of SquidDev's aes.lua: https://gist.github.com/Commandcracker/66f4dc5d80459bcbc5b6420ec66aa97b

Other Pure Lua aes implementations: KillaVanilla's aes.lua also for ComputerCraft idiomic's aes.lua

Awesome, thank you. I couldn’t remember where this was sourced from.

@Commandcracker
Copy link

Pure Lua AES encryption (https://github.com/SquidDev-CC/aeslua)

You have the source link in the description of this git but he nuked his repo

@looterz

Sorry, no idea. Original author nuked their repo for this awhile ago.

@Commandcracker
Copy link

Version 0.5 is missing the cipher-mode CTR
this means your coppy of aes.lua is newer
and somehow i used the same version as you in my project

@looterz I think it would be good adding the LICENSE.txt to this git.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment