encryption perf

This commit is contained in:
kepler155c@gmail.com
2019-06-30 19:53:26 -04:00
parent 159dc622fd
commit 61a26d7c55
6 changed files with 28 additions and 222 deletions

View File

@@ -1,581 +0,0 @@
-- Concise Binary Object Representation (CBOR)
-- RFC 7049
local function softreq(pkg, field)
local ok, mod = pcall(require, pkg);
if not ok then return end
if field then return mod[field]; end
return mod;
end
local dostring = function (s)
local ok, f = pcall(loadstring or load, s); -- luacheck: read globals loadstring
if ok and f then return f(); end
end
local setmetatable = setmetatable;
local getmetatable = getmetatable;
local dbg_getmetatable = debug.getmetatable;
local assert = assert;
local error = error;
local type = type;
local pairs = pairs;
local ipairs = ipairs;
local tostring = tostring;
local s_char = string.char;
local t_concat = table.concat;
local t_sort = table.sort;
local m_floor = math.floor;
local m_abs = math.abs;
local m_huge = math.huge;
local m_max = math.max;
local maxint = math.maxinteger or 9007199254740992;
local minint = math.mininteger or -9007199254740992;
local NaN = 0/0;
local m_frexp = math.frexp;
local m_ldexp = math.ldexp or function (x, exp) return x * 2.0 ^ exp; end;
local m_type = math.type or function (n) return n % 1 == 0 and n <= maxint and n >= minint and "integer" or "float" end;
local s_pack = string.pack or softreq("struct", "pack");
local s_unpack = string.unpack or softreq("struct", "unpack");
local b_rshift = softreq("bit32", "rshift") or softreq("bit", "rshift") or
dostring "return function(a,b) return a >> b end" or
function (a, b) return m_max(0, m_floor(a / (2 ^ b))); end;
-- sanity check
if s_pack and s_pack(">I2", 0) ~= "\0\0" then
s_pack = nil;
end
if s_unpack and s_unpack(">I2", "\1\2\3\4") ~= 0x102 then
s_unpack = nil;
end
local _ENV = nil; -- luacheck: ignore 211
local encoder = {};
local function encode(obj, opts)
return encoder[type(obj)](obj, opts);
end
-- Major types 0, 1 and length encoding for others
local function integer(num, m)
if m == 0 and num < 0 then
-- negative integer, major type 1
num, m = - num - 1, 32;
end
if num < 24 then
return s_char(m + num);
elseif num < 2 ^ 8 then
return s_char(m + 24, num);
elseif num < 2 ^ 16 then
return s_char(m + 25, b_rshift(num, 8), num % 0x100);
elseif num < 2 ^ 32 then
return s_char(m + 26,
b_rshift(num, 24) % 0x100,
b_rshift(num, 16) % 0x100,
b_rshift(num, 8) % 0x100,
num % 0x100);
elseif num < 2 ^ 64 then
local high = m_floor(num / 2 ^ 32);
num = num % 2 ^ 32;
return s_char(m + 27,
b_rshift(high, 24) % 0x100,
b_rshift(high, 16) % 0x100,
b_rshift(high, 8) % 0x100,
high % 0x100,
b_rshift(num, 24) % 0x100,
b_rshift(num, 16) % 0x100,
b_rshift(num, 8) % 0x100,
num % 0x100);
end
error "int too large";
end
if s_pack then
function integer(num, m)
local fmt;
m = m or 0;
if num < 24 then
fmt, m = ">B", m + num;
elseif num < 256 then
fmt, m = ">BB", m + 24;
elseif num < 65536 then
fmt, m = ">BI2", m + 25;
elseif num < 4294967296 then
fmt, m = ">BI4", m + 26;
else
fmt, m = ">BI8", m + 27;
end
return s_pack(fmt, m, num);
end
end
local simple_mt = {};
function simple_mt:__tostring() return self.name or ("simple(%d)"):format(self.value); end
function simple_mt:__tocbor() return self.cbor or integer(self.value, 224); end
local function simple(value, name, cbor)
assert(value >= 0 and value <= 255, "bad argument #1 to 'simple' (integer in range 0..255 expected)");
return setmetatable({ value = value, name = name, cbor = cbor }, simple_mt);
end
local tagged_mt = {};
function tagged_mt:__tostring() return ("%d(%s)"):format(self.tag, tostring(self.value)); end
function tagged_mt:__tocbor() return integer(self.tag, 192) .. encode(self.value); end
local function tagged(tag, value)
assert(tag >= 0, "bad argument #1 to 'tagged' (positive integer expected)");
return setmetatable({ tag = tag, value = value }, tagged_mt);
end
local null = simple(22, "null"); -- explicit null
local undefined = simple(23, "undefined"); -- undefined or nil
local BREAK = simple(31, "break", "\255");
-- Number types dispatch
function encoder.number(num)
return encoder[m_type(num)](num);
end
-- Major types 0, 1
function encoder.integer(num)
if num < 0 then
return integer(-1 - num, 32);
end
return integer(num, 0);
end
-- Major type 7
function encoder.float(num)
if num ~= num then -- NaN shortcut
return "\251\127\255\255\255\255\255\255\255";
end
local sign = (num > 0 or 1 / num > 0) and 0 or 1;
num = m_abs(num)
if num == m_huge then
return s_char(251, sign * 128 + 128 - 1) .. "\240\0\0\0\0\0\0";
end
local fraction, exponent = m_frexp(num)
if fraction == 0 then
return s_char(251, sign * 128) .. "\0\0\0\0\0\0\0";
end
fraction = fraction * 2;
exponent = exponent + 1024 - 2;
if exponent <= 0 then
fraction = fraction * 2 ^ (exponent - 1)
exponent = 0;
else
fraction = fraction - 1;
end
return s_char(251,
sign * 2 ^ 7 + m_floor(exponent / 2 ^ 4) % 2 ^ 7,
exponent % 2 ^ 4 * 2 ^ 4 +
m_floor(fraction * 2 ^ 4 % 0x100),
m_floor(fraction * 2 ^ 12 % 0x100),
m_floor(fraction * 2 ^ 20 % 0x100),
m_floor(fraction * 2 ^ 28 % 0x100),
m_floor(fraction * 2 ^ 36 % 0x100),
m_floor(fraction * 2 ^ 44 % 0x100),
m_floor(fraction * 2 ^ 52 % 0x100)
)
end
if s_pack then
function encoder.float(num)
return s_pack(">Bd", 251, num);
end
end
-- Major type 2 - byte strings
function encoder.bytestring(s)
return integer(#s, 64) .. s;
end
-- Major type 3 - UTF-8 strings
function encoder.utf8string(s)
return integer(#s, 96) .. s;
end
-- Lua strings are byte strings
encoder.string = encoder.bytestring;
function encoder.boolean(bool)
return bool and "\245" or "\244";
end
encoder["nil"] = function() return "\246"; end
function encoder.userdata(ud, opts)
local mt = dbg_getmetatable(ud);
if mt then
local encode_ud = opts and opts[mt] or mt.__tocbor;
if encode_ud then
return encode_ud(ud, opts);
end
end
error "can't encode userdata";
end
function encoder.table(t, opts)
local mt = getmetatable(t);
if mt then
local encode_t = opts and opts[mt] or mt.__tocbor;
if encode_t then
return encode_t(t, opts);
end
end
-- the table is encoded as an array iff when we iterate over it,
-- we see successive integer keys starting from 1. The lua
-- language doesn't actually guarantee that this will be the case
-- when we iterate over a table with successive integer keys, but
-- due an implementation detail in PUC Rio Lua, this is what we
-- usually observe. See the Lua manual regarding the # (length)
-- operator. In the case that this does not happen, we will fall
-- back to a map with integer keys, which becomes a bit larger.
local array, map, i, p = { integer(#t, 128) }, { "\191" }, 1, 2;
local is_array = true;
for k, v in pairs(t) do
is_array = is_array and i == k;
i = i + 1;
local encoded_v = encode(v, opts);
array[i] = encoded_v;
map[p], p = encode(k, opts), p + 1;
map[p], p = encoded_v, p + 1;
end
-- map[p] = "\255";
map[1] = integer(i - 1, 160);
return t_concat(is_array and array or map);
end
-- Array or dict-only encoders, which can be set as __tocbor metamethod
function encoder.array(t, opts)
local array = { };
for i, v in ipairs(t) do
array[i] = encode(v, opts);
end
return integer(#array, 128) .. t_concat(array);
end
function encoder.map(t, opts)
local map, p, len = { "\191" }, 2, 0;
for k, v in pairs(t) do
map[p], p = encode(k, opts), p + 1;
map[p], p = encode(v, opts), p + 1;
len = len + 1;
end
-- map[p] = "\255";
map[1] = integer(len, 160);
return t_concat(map);
end
encoder.dict = encoder.map; -- COMPAT
function encoder.ordered_map(t, opts)
local map = {};
if not t[1] then -- no predefined order
local i = 0;
for k in pairs(t) do
i = i + 1;
map[i] = k;
end
t_sort(map);
end
for i, k in ipairs(t[1] and t or map) do
map[i] = encode(k, opts) .. encode(t[k], opts);
end
return integer(#map, 160) .. t_concat(map);
end
encoder["function"] = function ()
error "can't encode function";
end
-- Decoder
-- Reads from a file-handle like object
local function read_bytes(fh, len)
return fh:read(len);
end
local function read_byte(fh)
return fh:read(1):byte();
end
local function read_length(fh, mintyp)
if mintyp < 24 then
return mintyp;
elseif mintyp < 28 then
local out = 0;
for _ = 1, 2 ^ (mintyp - 24) do
out = out * 256 + read_byte(fh);
end
return out;
else
error "invalid length";
end
end
local decoder = {};
local function read_type(fh)
local byte = read_byte(fh);
return b_rshift(byte, 5), byte % 32;
end
local function read_object(fh, opts)
local typ, mintyp = read_type(fh);
return decoder[typ](fh, mintyp, opts);
end
local function read_integer(fh, mintyp)
return read_length(fh, mintyp);
end
local function read_negative_integer(fh, mintyp)
return -1 - read_length(fh, mintyp);
end
local function read_string(fh, mintyp)
if mintyp ~= 31 then
return read_bytes(fh, read_length(fh, mintyp));
end
local out = {};
local i = 1;
local v = read_object(fh);
while v ~= BREAK do
out[i], i = v, i + 1;
v = read_object(fh);
end
return t_concat(out);
end
local function read_unicode_string(fh, mintyp)
return read_string(fh, mintyp);
-- local str = read_string(fh, mintyp);
-- if have_utf8 and not utf8.len(str) then
-- TODO How to handle this?
-- end
-- return str;
end
local function read_array(fh, mintyp, opts)
local out = {};
if mintyp == 31 then
local i = 1;
local v = read_object(fh, opts);
while v ~= BREAK do
out[i], i = v, i + 1;
v = read_object(fh, opts);
end
else
local len = read_length(fh, mintyp);
for i = 1, len do
out[i] = read_object(fh, opts);
end
end
return out;
end
local function read_map(fh, mintyp, opts)
local out = {};
local k;
if mintyp == 31 then
local i = 1;
k = read_object(fh, opts);
while k ~= BREAK do
out[k], i = read_object(fh, opts), i + 1;
k = read_object(fh, opts);
end
else
local len = read_length(fh, mintyp);
for _ = 1, len do
k = read_object(fh, opts);
out[k] = read_object(fh, opts);
end
end
return out;
end
local tagged_decoders = {};
local function read_semantic(fh, mintyp, opts)
local tag = read_length(fh, mintyp);
local value = read_object(fh, opts);
local postproc = opts and opts[tag] or tagged_decoders[tag];
if postproc then
return postproc(value);
end
return tagged(tag, value);
end
local function read_half_float(fh)
local exponent = read_byte(fh);
local fraction = read_byte(fh);
local sign = exponent < 128 and 1 or -1; -- sign is highest bit
fraction = fraction + (exponent * 256) % 1024; -- copy two(?) bits from exponent to fraction
exponent = b_rshift(exponent, 2) % 32; -- remove sign bit and two low bits from fraction;
if exponent == 0 then
return sign * m_ldexp(fraction, -24);
elseif exponent ~= 31 then
return sign * m_ldexp(fraction + 1024, exponent - 25);
elseif fraction == 0 then
return sign * m_huge;
else
return NaN;
end
end
local function read_float(fh)
local exponent = read_byte(fh);
local fraction = read_byte(fh);
local sign = exponent < 128 and 1 or -1; -- sign is highest bit
exponent = exponent * 2 % 256 + b_rshift(fraction, 7);
fraction = fraction % 128;
fraction = fraction * 256 + read_byte(fh);
fraction = fraction * 256 + read_byte(fh);
if exponent == 0 then
return sign * m_ldexp(exponent, -149);
elseif exponent ~= 0xff then
return sign * m_ldexp(fraction + 2 ^ 23, exponent - 150);
elseif fraction == 0 then
return sign * m_huge;
else
return NaN;
end
end
local function read_double(fh)
local exponent = read_byte(fh);
local fraction = read_byte(fh);
local sign = exponent < 128 and 1 or -1; -- sign is highest bit
exponent = exponent % 128 * 16 + b_rshift(fraction, 4);
fraction = fraction % 16;
fraction = fraction * 256 + read_byte(fh);
fraction = fraction * 256 + read_byte(fh);
fraction = fraction * 256 + read_byte(fh);
fraction = fraction * 256 + read_byte(fh);
fraction = fraction * 256 + read_byte(fh);
fraction = fraction * 256 + read_byte(fh);
if exponent == 0 then
return sign * m_ldexp(exponent, -149);
elseif exponent ~= 0xff then
return sign * m_ldexp(fraction + 2 ^ 52, exponent - 1075);
elseif fraction == 0 then
return sign * m_huge;
else
return NaN;
end
end
if s_unpack then
function read_float(fh) return s_unpack(">f", read_bytes(fh, 4)) end
function read_double(fh) return s_unpack(">d", read_bytes(fh, 8)) end
end
local function read_simple(fh, value, opts)
if value == 24 then
value = read_byte(fh);
end
if value == 20 then
return false;
elseif value == 21 then
return true;
elseif value == 22 then
return null;
elseif value == 23 then
return undefined;
elseif value == 25 then
return read_half_float(fh);
elseif value == 26 then
return read_float(fh);
elseif value == 27 then
return read_double(fh);
elseif value == 31 then
return BREAK;
end
if opts and opts.simple then
return opts.simple(value);
end
return simple(value);
end
decoder[0] = read_integer;
decoder[1] = read_negative_integer;
decoder[2] = read_string;
decoder[3] = read_unicode_string;
decoder[4] = read_array;
decoder[5] = read_map;
decoder[6] = read_semantic;
decoder[7] = read_simple;
-- opts.more(n) -> want more data
-- opts.simple -> decode simple value
-- opts[int] -> tagged decoder
local function decode(s, opts)
local fh = {};
local pos = 1;
local more;
if type(opts) == "function" then
more = opts;
elseif type(opts) == "table" then
more = opts.more;
elseif opts ~= nil then
error(("bad argument #2 to 'decode' (function or table expected, got %s)"):format(type(opts)));
end
if type(more) ~= "function" then
function more()
error "input too short";
end
end
function fh:read(bytes)
local ret = s:sub(pos, pos + bytes - 1);
if #ret < bytes then
ret = more(bytes - #ret, fh, opts);
if ret then self:write(ret); end
return self:read(bytes);
end
pos = pos + bytes;
return ret;
end
function fh:write(bytes) -- luacheck: no self
s = s .. bytes;
if pos > 256 then
s = s:sub(pos + 1);
pos = 1;
end
return #bytes;
end
return read_object(fh, opts);
end
return {
-- en-/decoder functions
encode = encode;
decode = decode;
decode_file = read_object;
-- tables of per-type en-/decoders
type_encoders = encoder;
type_decoders = decoder;
-- special treatment for tagged values
tagged_decoders = tagged_decoders;
-- constructors for annotated types
simple = simple;
tagged = tagged;
-- pre-defined simple values
null = null;
undefined = undefined;
}

View File

@@ -1,9 +1,8 @@
-- Chacha20 cipher in ComputerCraft
-- By Anavrins
local LZW = require('opus.crypto.lualzw')
local cbor = require('opus.cbor')
local sha2 = require('opus.crypto.sha2')
local Serializer = require('opus.crypto.serializer')
local Util = require('opus.util')
local ROUNDS = 8 -- Adjust this for speed tradeoff
@@ -153,10 +152,10 @@ end
local function encrypt(data, key)
local nonce = genNonce(12)
data = Serializer.serialize(data)
data = LZW.compress(data)
data = cbor.encode(data)
key = sha2.digest(key)
local ctx = crypt(data, key, nonce, 1, ROUNDS)
return { nonce:toHex(), ctx:toHex() }
end
@@ -165,7 +164,7 @@ local function decrypt(data, key)
data = Util.hexToByteArray(data[2])
key = sha2.digest(key)
local ptx = crypt(data, key, nonce, 1, ROUNDS)
return textutils.unserialise(LZW.decompress(tostring(ptx)))
return cbor.decode(tostring(ptx))
end
local obj = {}

View File

@@ -1,164 +0,0 @@
-- see: https://github.com/Rochet2/lualzw
--[[
MIT License
Copyright (c) 2016 Rochet2
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
local char = string.char
local type = type
local sub = string.sub
local tconcat = table.concat
local basedictcompress = {}
local basedictdecompress = {}
for i = 0, 255 do
local ic, iic = char(i), char(i, 0)
basedictcompress[ic] = iic
basedictdecompress[iic] = ic
end
local function dictAddA(str, dict, a, b)
if a >= 256 then
a, b = 0, b+1
if b >= 256 then
dict = {}
b = 1
end
end
dict[str] = char(a,b)
a = a+1
return dict, a, b
end
local function compress(input)
if type(input) ~= "string" then
error ("string expected, got "..type(input))
end
local len = #input
if len <= 1 then
return "u"..input
end
local dict = {}
local a, b = 0, 1
local result = {"c"}
local resultlen = 1
local n = 2
local word = ""
for i = 1, len do
local c = sub(input, i, i)
local wc = word..c
if not (basedictcompress[wc] or dict[wc]) then
local write = basedictcompress[word] or dict[word]
if not write then
error "algorithm error, could not fetch word"
end
result[n] = write
resultlen = resultlen + #write
n = n+1
if len <= resultlen then
return "u"..input
end
dict, a, b = dictAddA(wc, dict, a, b)
word = c
else
word = wc
end
end
result[n] = basedictcompress[word] or dict[word]
resultlen = resultlen+#result[n]
if len <= resultlen then
return "u"..input
end
return tconcat(result)
end
local function dictAddB(str, dict, a, b)
if a >= 256 then
a, b = 0, b+1
if b >= 256 then
dict = {}
b = 1
end
end
dict[char(a,b)] = str
a = a+1
return dict, a, b
end
local function decompress(input)
if type(input) ~= "string" then
error( "string expected, got "..type(input))
end
if #input < 1 then
error("invalid input - not a compressed string")
end
local control = sub(input, 1, 1)
if control == "u" then
return sub(input, 2)
elseif control ~= "c" then
error( "invalid input - not a compressed string")
end
input = sub(input, 2)
local len = #input
if len < 2 then
error( "invalid input - not a compressed string")
end
local dict = {}
local a, b = 0, 1
local result = {}
local n = 1
local last = sub(input, 1, 2)
result[n] = basedictdecompress[last] or dict[last]
n = n+1
for i = 3, len, 2 do
local code = sub(input, i, i+1)
local lastStr = basedictdecompress[last] or dict[last]
if not lastStr then
error( "could not find last from dict. Invalid input?")
end
local toAdd = basedictdecompress[code] or dict[code]
if toAdd then
result[n] = toAdd
n = n+1
dict, a, b = dictAddB(lastStr..sub(toAdd, 1, 1), dict, a, b)
else
local tmp = lastStr..sub(lastStr, 1, 1)
result[n] = tmp
n = n+1
dict, a, b = dictAddB(tmp, dict, a, b)
end
last = code
end
return tconcat(result)
end
return {
compress = compress,
decompress = decompress,
}

View File

@@ -1,50 +0,0 @@
local Serializer = { }
local insert = table.insert
local format = string.format
function Serializer.serialize(tbl)
local output = { }
local function recurse(t)
local sType = type(t)
if sType == 'table' then
if next(t) == nil then
insert(output, '{}')
else
insert(output, '{')
local tSeen = {}
for k, v in ipairs(t) do
tSeen[k] = true
recurse(v)
insert(output, ',')
end
for k, v in pairs(t) do
if not tSeen[k] then
if type(k) == 'string' and string.match(k, '^[%a_][%a%d_]*$') then
insert(output, k .. '=')
recurse(v)
insert(output, ',')
else
insert(output, '[')
recurse(k)
insert(output, ']=')
recurse(v)
insert(output, ',')
end
end
end
insert(output, '}')
end
elseif sType == 'string' then
insert(output, format('%q', t))
else
insert(output, tostring(t))
end
end
recurse(tbl)
return table.concat(output)
end
return Serializer