-
-
Save looterz/2fe749fffe1f74bd98a7089e8046fffe to your computer and use it in GitHub Desktop.
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 |
@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.
Version 0.5 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
SquidDev's post about his aes.lua: http://www.computercraft.info/forums2/index.php?/topic/18930-aes-encryption/
KillaVanilla's post about his aes.lua: http://www.computercraft.info/forums2/index.php?/topic/12450-killavanillas-various-apis/
@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.
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
Sorry, no idea. Original author nuked their repo for this awhile ago.
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.
Sorry, no idea. Original author nuked their repo for this awhile ago.