diff --git a/ccmsi.lua b/ccmsi.lua
index f3f74d1..c2018ac 100644
--- a/ccmsi.lua
+++ b/ccmsi.lua
@@ -20,31 +20,96 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
local function println(message) print(tostring(message)) end
local function print(message) term.write(tostring(message)) end
-local CCMSI_VERSION = "v1.4f"
+local CCMSI_VERSION = "v1.5"
local install_dir = "/.install-cache"
local manifest_path = "https://mikaylafischler.github.io/cc-mek-scada/manifests/"
local repo_path = "http://raw.githubusercontent.com/MikaylaFischler/cc-mek-scada/"
local opts = { ... }
-local mode = nil
-local app = nil
-local target
+local mode, app, target
+local install_manifest = manifest_path .. "main/install_manifest.json"
+
+local function red() term.setTextColor(colors.red) end
+local function orange() term.setTextColor(colors.orange) end
+local function yellow() term.setTextColor(colors.yellow) end
+local function green() term.setTextColor(colors.green) end
+local function blue() term.setTextColor(colors.blue) end
+local function white() term.setTextColor(colors.white) end
+local function lgray() term.setTextColor(colors.lightGray) end
+
+-- get command line option in list
+local function get_opt(opt, options)
+ for _, v in pairs(options) do if opt == v then return v end end
+ return nil
+end
+
+-- ask the user yes or no
+local function ask_y_n(question, default)
+ print(question)
+ if default == true then print(" (Y/n)? ") else print(" (y/N)? ") end
+ local response = read()
+ if response == "" then return default
+ elseif response == "Y" or response == "y" then return true
+ elseif response == "N" or response == "n" then return false
+ else return nil end
+end
+
+-- print out a white + blue text message
+local function pkg_message(message, package) white(); print(message .. " "); blue(); println(package); white() end
+
+-- indicate actions to be taken based on package differences for installs/updates
+local function show_pkg_change(name, v_local, v_remote)
+ if v_local ~= nil then
+ if v_local ~= v_remote then
+ print("[" .. name .. "] updating "); blue(); print(v_local); white(); print(" \xbb "); blue(); println(v_local); white()
+ elseif mode == "install" then
+ pkg_message("[" .. name .. "] reinstalling", v_local)
+ end
+ else
+ pkg_message("[" .. name .. "] new install of", v_remote)
+ end
+end
+
+-- read the local manifest file
+local function read_local_manifest()
+ local local_ok = false
+ local local_manifest = {}
+ local imfile = fs.open("install_manifest.json", "r")
+ if imfile ~= nil then
+ local_ok, local_manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end)
+ imfile.close()
+ end
+ return local_ok, local_manifest
+end
+
+-- get the manifest from GitHub
+local function get_remote_manifest()
+ local response, error = http.get(install_manifest)
+ if response == nil then
+ orange(); println("failed to get installation manifest from GitHub, cannot update or install")
+ red(); println("HTTP error: " .. error); white()
+ return false, {}
+ end
+
+ local ok, manifest = pcall(function () return textutils.unserializeJSON(response.readAll()) end)
+ if not ok then
+ red(); println("error parsing remote installation manifest"); white()
+ end
+
+ return ok, manifest
+end
-- record the local installation manifest
----@param manifest table
----@param dependencies table
local function write_install_manifest(manifest, dependencies)
local versions = {}
for key, value in pairs(manifest.versions) do
local is_dependency = false
for _, dependency in pairs(dependencies) do
if (key == "bootloader" and dependency == "system") or key == dependency then
- is_dependency = true
- break
+ is_dependency = true; break
end
end
-
if key == app or key == "comms" or is_dependency then versions[key] = value end
end
@@ -55,184 +120,66 @@ local function write_install_manifest(manifest, dependencies)
imfile.close()
end
--- ask the user yes or no
----@nodiscard
----@param question string
----@param default boolean
----@return boolean|nil
-local function ask_y_n(question, default)
- print(question)
-
- if default == true then
- print(" (Y/n)? ")
- else
- print(" (y/N)? ")
- end
-
- local response = read(nil, nil)
-
- if response == "" then
- return default
- elseif response == "Y" or response == "y" then
- return true
- elseif response == "N" or response == "n" then
- return false
- else
- return nil
- end
-end
-
--- print out a white + blue text message
--- automatically adds a space
----@param message string message
----@param package string dependency/package/version
-local function pkg_message(message, package)
- term.setTextColor(colors.white)
- print(message .. " ")
- term.setTextColor(colors.blue)
- println(package)
- term.setTextColor(colors.white)
-end
-
--- indicate actions to be taken based on package differences for installs/updates
----@param name string package name
----@param v_local string|nil local version
----@param v_remote string remote version
-local function show_pkg_change(name, v_local, v_remote)
- if v_local ~= nil then
- if v_local ~= v_remote then
- print("[" .. name .. "] updating ")
- term.setTextColor(colors.blue)
- print(v_local)
- term.setTextColor(colors.white)
- print(" \xbb ")
- term.setTextColor(colors.blue)
- println(v_local)
- term.setTextColor(colors.white)
- elseif mode == "install" then
- pkg_message("[" .. name .. "] reinstalling", v_local)
- end
- else
- pkg_message("[" .. name .. "] new install of", v_remote)
- end
-end
-
---
-- get and validate command line options
---
println("-- CC Mekanism SCADA Installer " .. CCMSI_VERSION .. " --")
if #opts == 0 or opts[1] == "help" then
println("usage: ccmsi ")
println("")
- term.setTextColor(colors.lightGray)
+ lgray()
println(" check - check latest versions avilable")
- term.setTextColor(colors.yellow)
+ yellow()
println(" ccmsi check for target")
- term.setTextColor(colors.lightGray)
+ lgray()
println(" install - fresh install, overwrites config")
println(" update - update files EXCEPT for config/logs")
println(" remove - delete files EXCEPT for config/logs")
println(" purge - delete files INCLUDING config/logs")
- term.setTextColor(colors.white)
- println("")
- term.setTextColor(colors.lightGray)
+ white(); println(""); lgray()
println(" reactor-plc - reactor PLC firmware")
println(" rtu - RTU firmware")
println(" supervisor - supervisor server application")
println(" coordinator - coordinator application")
println(" pocket - pocket application")
- term.setTextColor(colors.white)
- println("")
- term.setTextColor(colors.yellow)
+ white(); println(""); yellow()
println(" second parameter when used with check")
- term.setTextColor(colors.lightGray)
- println(" main (default) | latest | devel")
+ lgray(); println(" main (default) | latest | devel"); white()
return
else
- for _, v in pairs({ "check", "install", "update", "remove", "purge" }) do
- if opts[1] == v then
- mode = v
- break
- end
- end
-
+ mode = get_opt(opts[1], { "check", "install", "update", "remove", "purge" })
if mode == nil then
- println("unrecognized mode")
+ red(); println("Unrecognized mode."); white()
return
end
- for _, v in pairs({ "reactor-plc", "rtu", "supervisor", "coordinator", "pocket" }) do
- if opts[2] == v then
- app = v
- break
- end
- end
-
+ app = get_opt(opts[2], { "reactor-plc", "rtu", "supervisor", "coordinator", "pocket" })
if app == nil and mode ~= "check" then
- println("unrecognized application")
+ red(); println("Unrecognized application."); white()
return
end
-- determine target
if mode == "check" then target = opts[2] else target = opts[3] end
if (target ~= "main") and (target ~= "latest") and (target ~= "devel") then
+ if target ~= "" then yellow(); println("Unknown target, defaulting to 'main'"); white() end
target = "main"
- println("unknown target, defaulting to 'main'")
end
+
+ -- set paths
+ install_manifest = manifest_path .. target .. "/install_manifest.json"
+ repo_path = repo_path .. target .. "/"
end
---
-- run selected mode
---
if mode == "check" then
- -------------------------
- -- GET REMOTE MANIFEST --
- -------------------------
-
- manifest_path = manifest_path .. target .. "/"
- local install_manifest = manifest_path .. "install_manifest.json"
-
- local response, error = http.get(install_manifest)
-
- if response == nil then
- term.setTextColor(colors.orange)
- println("failed to get installation manifest from GitHub, cannot update or install")
- term.setTextColor(colors.red)
- println("HTTP error: " .. error)
- term.setTextColor(colors.white)
- return
- end
-
- local ok, manifest = pcall(function () return textutils.unserializeJSON(response.readAll()) end)
-
- if not ok then
- term.setTextColor(colors.red)
- println("error parsing remote installation manifest")
- term.setTextColor(colors.white)
- return
- end
-
- ------------------------
- -- GET LOCAL MANIFEST --
- ------------------------
-
- local imfile = fs.open("install_manifest.json", "r")
- local local_ok = false
- local local_manifest = {}
-
- if imfile ~= nil then
- local_ok, local_manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end)
- imfile.close()
- end
+ local ok, manifest = get_remote_manifest()
+ if not ok then return end
+ local local_ok, local_manifest = read_local_manifest()
if not local_ok then
- term.setTextColor(colors.yellow)
- println("failed to load local installation information")
- term.setTextColor(colors.white)
-
+ yellow(); println("failed to load local installation information"); white()
local_manifest = { versions = { installer = CCMSI_VERSION } }
else
local_manifest.versions.installer = CCMSI_VERSION
@@ -243,84 +190,35 @@ if mode == "check" then
term.setTextColor(colors.purple)
print(string.format("%-14s", "[" .. key .. "]"))
if key == "installer" or (local_ok and (local_manifest.versions[key] ~= nil)) then
- term.setTextColor(colors.blue)
- print(local_manifest.versions[key])
+ blue(); print(local_manifest.versions[key])
if value ~= local_manifest.versions[key] then
- term.setTextColor(colors.white)
- print(" (")
+ white(); print(" (")
term.setTextColor(colors.cyan)
- print(value)
- term.setTextColor(colors.white)
- println(" available)")
- else
- term.setTextColor(colors.green)
- println(" (up to date)")
- end
+ print(value); white(); println(" available)")
+ else green(); println(" (up to date)") end
else
- term.setTextColor(colors.lightGray)
- print("not installed")
- term.setTextColor(colors.white)
- print(" (latest ")
+ lgray(); print("not installed"); white(); print(" (latest ")
term.setTextColor(colors.cyan)
- print(value)
- term.setTextColor(colors.white)
- println(")")
+ print(value); white(); println(")")
end
end
elseif mode == "install" or mode == "update" then
- -------------------------
- -- GET REMOTE MANIFEST --
- -------------------------
-
- repo_path = repo_path .. target .. "/"
- manifest_path = manifest_path .. target .. "/"
- local install_manifest = manifest_path .. "install_manifest.json"
-
- local response, error = http.get(install_manifest)
-
- if response == nil then
- term.setTextColor(colors.orange)
- println("failed to get installation manifest from GitHub, cannot update or install")
- term.setTextColor(colors.red)
- println("HTTP error: " .. error)
- term.setTextColor(colors.white)
- return
- end
-
- local ok, manifest = pcall(function () return textutils.unserializeJSON(response.readAll()) end)
-
- if not ok then
- term.setTextColor(colors.red)
- println("error parsing remote installation manifest")
- term.setTextColor(colors.white)
- end
-
- ------------------------
- -- GET LOCAL MANIFEST --
- ------------------------
+ local ok, manifest = get_remote_manifest()
+ if not ok then return end
local ver = {
app = { v_local = nil, v_remote = nil, changed = false },
boot = { v_local = nil, v_remote = nil, changed = false },
comms = { v_local = nil, v_remote = nil, changed = false },
- graphics = { v_local = nil, v_remote = nil, changed = false }
+ graphics = { v_local = nil, v_remote = nil, changed = false },
+ lockbox = { v_local = nil, v_remote = nil, changed = false }
}
- local imfile = fs.open("install_manifest.json", "r")
- local local_ok = false
- local local_manifest = {}
-
- if imfile ~= nil then
- local_ok, local_manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end)
- imfile.close()
- end
-
-- try to find local versions
+ local local_ok, local_manifest = read_local_manifest()
if not local_ok then
if mode == "update" then
- term.setTextColor(colors.red)
- println("failed to load local installation information, cannot update")
- term.setTextColor(colors.white)
+ red(); println("failed to load local installation information, cannot update"); white()
return
end
else
@@ -328,19 +226,16 @@ elseif mode == "install" or mode == "update" then
ver.app.v_local = local_manifest.versions[app]
ver.comms.v_local = local_manifest.versions.comms
ver.graphics.v_local = local_manifest.versions.graphics
+ ver.lockbox.v_local = local_manifest.versions.lockbox
if local_manifest.versions[app] == nil then
- term.setTextColor(colors.red)
- println("another application is already installed, please purge it before installing a new application")
- term.setTextColor(colors.white)
+ red(); println("another application is already installed, please purge it before installing a new application"); white()
return
end
local_manifest.versions.installer = CCMSI_VERSION
if manifest.versions.installer ~= CCMSI_VERSION then
- term.setTextColor(colors.yellow)
- println("a newer version of the installer is available, consider downloading it")
- term.setTextColor(colors.white)
+ yellow(); println("a newer version of the installer is available, it is recommended to download it"); white()
end
end
@@ -348,14 +243,15 @@ elseif mode == "install" or mode == "update" then
ver.app.v_remote = manifest.versions[app]
ver.comms.v_remote = manifest.versions.comms
ver.graphics.v_remote = manifest.versions.graphics
+ ver.lockbox.v_remote = manifest.versions.lockbox
- term.setTextColor(colors.green)
+ green()
if mode == "install" then
println("Installing " .. app .. " files...")
elseif mode == "update" then
println("Updating " .. app .. " files... (keeping old config.lua)")
end
- term.setTextColor(colors.white)
+ white()
-- display bootloader version change information
show_pkg_change("bootldr", ver.boot.v_local, ver.boot.v_remote)
@@ -369,16 +265,17 @@ elseif mode == "install" or mode == "update" then
show_pkg_change("comms", ver.comms.v_local, ver.comms.v_remote)
ver.comms.changed = ver.comms.v_local ~= ver.comms.v_remote
if ver.comms.changed and ver.comms.v_local ~= nil then
- print("[comms] ")
- term.setTextColor(colors.yellow)
- println("other devices on the network will require an update")
- term.setTextColor(colors.white)
+ print("[comms] "); yellow(); println("other devices on the network will require an update"); white()
end
-- display graphics version change information
show_pkg_change("graphics", ver.graphics.v_local, ver.graphics.v_remote)
ver.graphics.changed = ver.graphics.v_local ~= ver.graphics.v_remote
+ -- display lockbox version change information
+ show_pkg_change("lockbox", ver.lockbox.v_local, ver.lockbox.v_remote)
+ ver.lockbox.changed = ver.lockbox.v_local ~= ver.lockbox.v_remote
+
-- ask for confirmation
if not ask_y_n("Continue?", false) then return end
@@ -405,11 +302,9 @@ elseif mode == "install" or mode == "update" then
-- check space constraints
if space_available < space_required then
single_file_mode = true
- term.setTextColor(colors.yellow)
- println("WARNING: Insufficient space available for a full download!")
- term.setTextColor(colors.white)
+ yellow(); println("WARNING: Insufficient space available for a full download!"); white()
println("Files can be downloaded one by one, so if you are replacing a current install this will not be a problem unless installation fails.")
- if mode == "update" then println("If installation still fails, delete this device's log file and try again.") end
+ if mode == "update" then println("If installation still fails, delete this device's log file or uninstall the app (not purge) and try again.") end
if not ask_y_n("Do you wish to continue?", false) then
println("Operation cancelled.")
return
@@ -419,12 +314,11 @@ elseif mode == "install" or mode == "update" then
local success = true
-- helper function to check if a dependency is unchanged
- ---@nodiscard
- ---@param dependency string
- ---@return boolean
local function unchanged(dependency)
if dependency == "system" then return not ver.boot.changed
elseif dependency == "graphics" then return not ver.graphics.changed
+ elseif dependency == "lockbox" then return not ver.lockbox.changed
+ elseif dependency == "common" then return not (ver.app.changed or ver.comms.changed)
elseif dependency == app then return not ver.app.changed
else return true end
end
@@ -441,7 +335,7 @@ elseif mode == "install" or mode == "update" then
pkg_message("skipping download of unchanged package", dependency)
else
pkg_message("downloading package", dependency)
- term.setTextColor(colors.lightGray)
+ lgray()
local files = file_list[dependency]
for _, file in pairs(files) do
@@ -449,8 +343,7 @@ elseif mode == "install" or mode == "update" then
local dl, err = http.get(repo_path .. file)
if dl == nil then
- term.setTextColor(colors.red)
- println("GET HTTP Error " .. err)
+ red(); println("GET HTTP Error " .. err)
success = false
break
else
@@ -469,7 +362,7 @@ elseif mode == "install" or mode == "update" then
pkg_message("skipping install of unchanged package", dependency)
else
pkg_message("installing package", dependency)
- term.setTextColor(colors.lightGray)
+ lgray()
local files = file_list[dependency]
for _, file in pairs(files) do
@@ -486,23 +379,15 @@ elseif mode == "install" or mode == "update" then
fs.delete(install_dir)
if success then
- -- if we made it here, then none of the file system functions threw exceptions
- -- that means everything is OK
write_install_manifest(manifest, dependencies)
- term.setTextColor(colors.green)
+ green()
if mode == "install" then
println("Installation completed successfully.")
- else
- println("Update completed successfully.")
- end
+ else println("Update completed successfully.") end
else
if mode == "install" then
- term.setTextColor(colors.red)
- println("Installation failed.")
- else
- term.setTextColor(colors.orange)
- println("Update failed, existing files unmodified.")
- end
+ red(); println("Installation failed.")
+ else orange(); println("Update failed, existing files unmodified.") end
end
else
-- go through all files and replace one by one
@@ -511,7 +396,7 @@ elseif mode == "install" or mode == "update" then
pkg_message("skipping install of unchanged package", dependency)
else
pkg_message("installing package", dependency)
- term.setTextColor(colors.lightGray)
+ lgray()
local files = file_list[dependency]
for _, file in pairs(files) do
@@ -520,7 +405,7 @@ elseif mode == "install" or mode == "update" then
local dl, err = http.get(repo_path .. file)
if dl == nil then
- println("GET HTTP Error " .. err)
+ red(); println("GET HTTP Error " .. err)
success = false
break
else
@@ -534,51 +419,33 @@ elseif mode == "install" or mode == "update" then
end
if success then
- -- if we made it here, then none of the file system functions threw exceptions
- -- that means everything is OK
write_install_manifest(manifest, dependencies)
- term.setTextColor(colors.green)
+ green()
if mode == "install" then
println("Installation completed successfully.")
- else
- println("Update completed successfully.")
- end
+ else println("Update completed successfully.") end
else
- term.setTextColor(colors.red)
+ red()
if mode == "install" then
println("Installation failed, files may have been skipped.")
- else
- println("Update failed, files may have been skipped.")
- end
+ else println("Update failed, files may have been skipped.") end
end
end
elseif mode == "remove" or mode == "purge" then
- local imfile = fs.open("install_manifest.json", "r")
- local ok = false
- local manifest = {}
-
- if imfile ~= nil then
- ok, manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end)
- imfile.close()
- end
-
+ local ok, manifest = read_local_manifest()
if not ok then
- term.setTextColor(colors.red)
- println("error parsing local installation manifest")
- term.setTextColor(colors.white)
+ red(); println("Error parsing local installation manifest."); white()
return
elseif mode == "remove" and manifest.versions[app] == nil then
- term.setTextColor(colors.red)
- println(app .. " is not installed")
- term.setTextColor(colors.white)
+ red(); println(app .. " is not installed, cannot remove."); white()
return
end
- term.setTextColor(colors.orange)
+ orange()
if mode == "remove" then
- println("removing all " .. app .. " files except for config.lua and log.txt...")
+ println("Removing all " .. app .. " files except for config and log...")
elseif mode == "purge" then
- println("purging all " .. app .. " files...")
+ println("Purging all " .. app .. " files including config and log...")
end
-- ask for confirmation
@@ -590,9 +457,8 @@ elseif mode == "remove" or mode == "purge" then
table.insert(dependencies, app)
- term.setTextColor(colors.lightGray)
-
-- delete log file if purging
+ lgray()
if mode == "purge" and fs.exists(config_file) then
local log_deleted = pcall(function ()
local config = require(app .. ".config")
@@ -603,11 +469,9 @@ elseif mode == "remove" or mode == "purge" then
end)
if not log_deleted then
- term.setTextColor(colors.red)
- println("failed to delete log file")
- term.setTextColor(colors.lightGray)
----@diagnostic disable-next-line: undefined-field
- os.sleep(1)
+ red(); println("failed to delete log file")
+ white(); println("press enter to continue...")
+ read(); lgray()
end
end
@@ -628,11 +492,7 @@ elseif mode == "remove" or mode == "purge" then
local folder = files[1]
while true do
local dir = fs.getDir(folder)
- if dir == "" or dir == ".." then
- break
- else
- folder = dir
- end
+ if dir == "" or dir == ".." then break else folder = dir end
end
if fs.isDir(folder) then
@@ -640,14 +500,11 @@ elseif mode == "remove" or mode == "purge" then
println("deleted directory " .. folder)
end
elseif dependency == app then
+ -- delete individual subdirectories so we can leave the config
for _, folder in pairs(files) do
while true do
local dir = fs.getDir(folder)
- if dir == "" or dir == ".." or dir == app then
- break
- else
- folder = dir
- end
+ if dir == "" or dir == ".." or dir == app then break else folder = dir end
end
if folder ~= app and fs.isDir(folder) then
@@ -665,13 +522,12 @@ elseif mode == "remove" or mode == "purge" then
else
-- remove all data from versions list to show nothing is installed
manifest.versions = {}
- imfile = fs.open("install_manifest.json", "w")
+ local imfile = fs.open("install_manifest.json", "w")
imfile.write(textutils.serializeJSON(manifest))
imfile.close()
end
- term.setTextColor(colors.green)
- println("Done!")
+ green(); println("Done!")
end
-term.setTextColor(colors.white)
+white()
diff --git a/coordinator/config.lua b/coordinator/config.lua
index ecb7599..7ea6ea2 100644
--- a/coordinator/config.lua
+++ b/coordinator/config.lua
@@ -11,6 +11,10 @@ config.TRUSTED_RANGE = 0
-- time in seconds (>= 2) before assuming a remote device is no longer active
config.SV_TIMEOUT = 5
config.API_TIMEOUT = 5
+-- facility authentication key (do NOT use one of your passwords)
+-- this enables verifying that messages are authentic
+-- all devices on the same network must use the same key
+-- config.AUTH_KEY = "SCADAfacility123"
-- expected number of reactor units, used only to require that number of unit monitors
config.NUM_UNITS = 4
diff --git a/coordinator/coordinator.lua b/coordinator/coordinator.lua
index f6e8038..ff81e5d 100644
--- a/coordinator/coordinator.lua
+++ b/coordinator/coordinator.lua
@@ -183,7 +183,8 @@ local function log_dmesg(message, dmesg_tag, working)
GRAPHICS = colors.green,
SYSTEM = colors.cyan,
BOOT = colors.blue,
- COMMS = colors.purple
+ COMMS = colors.purple,
+ CRYPTO = colors.yellow
}
if working then
@@ -197,6 +198,7 @@ function coordinator.log_graphics(message) log_dmesg(message, "GRAPHICS") end
function coordinator.log_sys(message) log_dmesg(message, "SYSTEM") end
function coordinator.log_boot(message) log_dmesg(message, "BOOT") end
function coordinator.log_comms(message) log_dmesg(message, "COMMS") end
+function coordinator.log_crypto(message) log_dmesg(message, "CRYPTO") end
-- log a message for communications connecting, providing access to progress indication control functions
---@nodiscard
@@ -212,13 +214,13 @@ end
-- coordinator communications
---@nodiscard
---@param version string coordinator version
----@param modem table modem device
+---@param nic nic network interface device
---@param crd_channel integer port of configured supervisor
---@param svr_channel integer listening port for supervisor replys
---@param pkt_channel integer listening port for pocket API
---@param range integer trusted device connection range
---@param sv_watchdog watchdog
-function coordinator.comms(version, modem, crd_channel, svr_channel, pkt_channel, range, sv_watchdog)
+function coordinator.comms(version, nic, crd_channel, svr_channel, pkt_channel, range, sv_watchdog)
local self = {
sv_linked = false,
sv_addr = comms.BROADCAST,
@@ -234,16 +236,12 @@ function coordinator.comms(version, modem, crd_channel, svr_channel, pkt_channel
-- PRIVATE FUNCTIONS --
- -- configure modem channels
- local function _conf_channels()
- modem.closeAll()
- modem.open(crd_channel)
- end
+ -- configure network channels
+ nic.closeAll()
+ nic.open(crd_channel)
- _conf_channels()
-
- -- link modem to apisessions
- apisessions.init(modem)
+ -- link nic to apisessions
+ apisessions.init(nic)
-- send a packet to the supervisor
---@param msg_type SCADA_MGMT_TYPE|SCADA_CRDN_TYPE
@@ -263,7 +261,7 @@ function coordinator.comms(version, modem, crd_channel, svr_channel, pkt_channel
pkt.make(msg_type, msg)
s_pkt.make(self.sv_addr, self.sv_seq_num, protocol, pkt.raw_sendable())
- modem.transmit(svr_channel, crd_channel, s_pkt.raw_sendable())
+ nic.transmit(svr_channel, crd_channel, s_pkt)
self.sv_seq_num = self.sv_seq_num + 1
end
@@ -277,7 +275,7 @@ function coordinator.comms(version, modem, crd_channel, svr_channel, pkt_channel
m_pkt.make(SCADA_MGMT_TYPE.ESTABLISH, { ack })
s_pkt.make(packet.src_addr(), packet.seq_num() + 1, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
- modem.transmit(pkt_channel, crd_channel, s_pkt.raw_sendable())
+ nic.transmit(pkt_channel, crd_channel, s_pkt)
self.last_api_est_acks[packet.src_addr()] = ack
end
@@ -297,14 +295,6 @@ function coordinator.comms(version, modem, crd_channel, svr_channel, pkt_channel
---@class coord_comms
local public = {}
- -- reconnect a newly connected modem
- ---@param new_modem table
- function public.reconnect_modem(new_modem)
- modem = new_modem
- apisessions.relink_modem(new_modem)
- _conf_channels()
- end
-
-- close the connection to the server
function public.close()
sv_watchdog.cancel()
@@ -402,13 +392,10 @@ function coordinator.comms(version, modem, crd_channel, svr_channel, pkt_channel
---@param distance integer
---@return mgmt_frame|crdn_frame|capi_frame|nil packet
function public.parse_packet(side, sender, reply_to, message, distance)
+ local s_pkt = nic.receive(side, sender, reply_to, message, distance)
local pkt = nil
- local s_pkt = comms.scada_packet()
- -- parse packet as generic SCADA packet
- s_pkt.receive(side, sender, reply_to, message, distance)
-
- if s_pkt.is_valid() then
+ if s_pkt then
-- get as SCADA management packet
if s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
local mgmt_pkt = comms.mgmt_packet()
diff --git a/coordinator/session/apisessions.lua b/coordinator/session/apisessions.lua
index 17988f5..1ea1beb 100644
--- a/coordinator/session/apisessions.lua
+++ b/coordinator/session/apisessions.lua
@@ -10,7 +10,7 @@ local pocket = require("coordinator.session.pocket")
local apisessions = {}
local self = {
- modem = nil,
+ nic = nil,
next_id = 0,
sessions = {}
}
@@ -31,7 +31,7 @@ local function _api_handle_outq(session)
if msg ~= nil then
if msg.qtype == mqueue.TYPE.PACKET then
-- handle a packet to be sent
- self.modem.transmit(config.PKT_CHANNEL, config.CRD_CHANNEL, msg.message.raw_sendable())
+ self.nic.transmit(config.PKT_CHANNEL, config.CRD_CHANNEL, msg.message)
elseif msg.qtype == mqueue.TYPE.COMMAND then
-- handle instruction/notification
elseif msg.qtype == mqueue.TYPE.DATA then
@@ -58,7 +58,7 @@ local function _shutdown(session)
while session.out_queue.ready() do
local msg = session.out_queue.pop()
if msg ~= nil and msg.qtype == mqueue.TYPE.PACKET then
- self.modem.transmit(config.PKT_CHANNEL, config.CRD_CHANNEL, msg.message.raw_sendable())
+ self.nic.transmit(config.PKT_CHANNEL, config.CRD_CHANNEL, msg.message)
end
end
@@ -68,15 +68,9 @@ end
-- PUBLIC FUNCTIONS --
-- initialize apisessions
----@param modem table
-function apisessions.init(modem)
- self.modem = modem
-end
-
--- re-link the modem
----@param modem table
-function apisessions.relink_modem(modem)
- self.modem = modem
+---@param nic nic
+function apisessions.init(nic)
+ self.nic = nic
end
-- find a session by remote port
diff --git a/coordinator/startup.lua b/coordinator/startup.lua
index 838d9ec..8bbc550 100644
--- a/coordinator/startup.lua
+++ b/coordinator/startup.lua
@@ -6,6 +6,7 @@ require("/initenv").init_env()
local crash = require("scada-common.crash")
local log = require("scada-common.log")
+local network = require("scada-common.network")
local ppm = require("scada-common.ppm")
local tcd = require("scada-common.tcd")
local util = require("scada-common.util")
@@ -20,7 +21,7 @@ local sounder = require("coordinator.sounder")
local apisessions = require("coordinator.session.apisessions")
-local COORDINATOR_VERSION = "v0.16.2"
+local COORDINATOR_VERSION = "v0.17.1"
local println = util.println
local println_ts = util.println_ts
@@ -30,6 +31,7 @@ local log_sys = coordinator.log_sys
local log_boot = coordinator.log_boot
local log_comms = coordinator.log_comms
local log_comms_connecting = coordinator.log_comms_connecting
+local log_crypto = coordinator.log_crypto
----------------------------------------
-- config validation
@@ -131,6 +133,12 @@ local function main()
-- setup communications
----------------------------------------
+ -- message authentication init
+ if type(config.AUTH_KEY) == "string" then
+ local init_time = network.init_mac(config.AUTH_KEY)
+ log_crypto("HMAC init took " .. init_time .. "ms")
+ end
+
-- get the communications modem
local modem = ppm.get_wireless_modem()
if modem == nil then
@@ -147,8 +155,9 @@ local function main()
conn_watchdog.cancel()
log.debug("startup> conn watchdog created")
- -- start comms, open all channels
- local coord_comms = coordinator.comms(COORDINATOR_VERSION, modem, config.CRD_CHANNEL, config.SVR_CHANNEL,
+ -- create network interface then setup comms
+ local nic = network.nic(modem)
+ local coord_comms = coordinator.comms(COORDINATOR_VERSION, nic, config.CRD_CHANNEL, config.SVR_CHANNEL,
config.PKT_CHANNEL, config.TRUSTED_RANGE, conn_watchdog)
log.debug("startup> comms init")
log_comms("comms initialized")
@@ -218,8 +227,6 @@ local function main()
local date_format = util.trinary(config.TIME_24_HOUR, "%X \x04 %A, %B %d %Y", "%r \x04 %A, %B %d %Y")
- local no_modem = false
-
if ui_ok then
-- start connection watchdog
conn_watchdog.feed()
@@ -239,8 +246,9 @@ local function main()
if type ~= nil and device ~= nil then
if type == "modem" then
-- we only really care if this is our wireless modem
- if device == modem then
- no_modem = true
+ -- if it is another modem, handle other peripheral losses separately
+ if nic.is_modem(device) then
+ nic.disconnect()
log_sys("comms modem disconnected")
println_ts("wireless modem disconnected!")
@@ -254,6 +262,7 @@ local function main()
end
elseif type == "monitor" then
if renderer.is_monitor_used(device) then
+ ---@todo will be handled properly in #249
-- "halt and catch fire" style handling
local msg = "lost a configured monitor, system will now exit"
println_ts(msg)
@@ -275,9 +284,7 @@ local function main()
if type == "modem" then
if device.isWireless() then
-- reconnected modem
- no_modem = false
- modem = device
- coord_comms.reconnect_modem(modem)
+ nic.connect(device)
log_sys("comms modem reconnected")
println_ts("wireless modem reconnected.")
@@ -289,6 +296,7 @@ local function main()
log_sys("wired modem reconnected")
end
-- elseif type == "monitor" then
+ ---@todo will be handled properly in #249
-- not supported, system will exit on loss of in-use monitors
elseif type == "speaker" then
local msg = "alarm sounder speaker reconnected"
@@ -322,7 +330,7 @@ local function main()
renderer.close_ui()
sounder.stop()
- if not no_modem then
+ if nic.connected() then
-- try to re-connect to the supervisor
if not init_connect_sv() then break end
ui_ok = init_start_ui()
@@ -350,7 +358,7 @@ local function main()
renderer.close_ui()
sounder.stop()
- if not no_modem then
+ if nic.connected() then
-- try to re-connect to the supervisor
if not init_connect_sv() then break end
ui_ok = init_start_ui()
diff --git a/imgen.py b/imgen.py
index 63f28cf..046fc36 100644
--- a/imgen.py
+++ b/imgen.py
@@ -50,6 +50,7 @@ def make_manifest(size):
"bootloader" : get_version("./startup.lua"),
"comms" : get_version("./scada-common/comms.lua", True),
"graphics" : get_version("./graphics/core.lua", True),
+ "lockbox" : get_version("./lockbox/init.lua", True),
"reactor-plc" : get_version("./reactor-plc/startup.lua"),
"rtu" : get_version("./rtu/startup.lua"),
"supervisor" : get_version("./supervisor/startup.lua"),
@@ -70,11 +71,11 @@ def make_manifest(size):
"pocket" : list_files("./pocket"),
},
"depends" : {
- "reactor-plc" : [ "system", "common", "graphics" ],
- "rtu" : [ "system", "common", "graphics" ],
- "supervisor" : [ "system", "common", "graphics" ],
- "coordinator" : [ "system", "common", "graphics" ],
- "pocket" : [ "system", "common", "graphics" ]
+ "reactor-plc" : [ "system", "common", "graphics", "lockbox" ],
+ "rtu" : [ "system", "common", "graphics", "lockbox" ],
+ "supervisor" : [ "system", "common", "graphics", "lockbox" ],
+ "coordinator" : [ "system", "common", "graphics", "lockbox" ],
+ "pocket" : [ "system", "common", "graphics", "lockbox" ]
},
"sizes" : {
# manifest file estimate
diff --git a/install_manifest.json b/install_manifest.json
index b6c4c60..0d4a88f 100644
--- a/install_manifest.json
+++ b/install_manifest.json
@@ -1 +1 @@
-{"versions": {"installer": "v1.4f", "bootloader": "0.2", "comms": "2.0.0", "graphics": "1.0.0", "reactor-plc": "v1.4.7", "rtu": "v1.3.7", "supervisor": "v0.17.10", "coordinator": "v0.16.2", "pocket": "alpha-v0.4.6"}, "files": {"system": ["initenv.lua", "startup.lua"], "common": ["scada-common/constants.lua", "scada-common/crypto.lua", "scada-common/types.lua", "scada-common/comms.lua", "scada-common/mqueue.lua", "scada-common/util.lua", "scada-common/psil.lua", "scada-common/crash.lua", "scada-common/tcd.lua", "scada-common/rsio.lua", "scada-common/ppm.lua", "scada-common/log.lua"], "graphics": ["graphics/core.lua", "graphics/flasher.lua", "graphics/element.lua", "graphics/events.lua", "graphics/elements/div.lua", "graphics/elements/colormap.lua", "graphics/elements/textbox.lua", "graphics/elements/pipenet.lua", "graphics/elements/listbox.lua", "graphics/elements/multipane.lua", "graphics/elements/displaybox.lua", "graphics/elements/rectangle.lua", "graphics/elements/tiling.lua", "graphics/elements/controls/tabbar.lua", "graphics/elements/controls/radio_button.lua", "graphics/elements/controls/spinbox_numeric.lua", "graphics/elements/controls/switch_button.lua", "graphics/elements/controls/sidebar.lua", "graphics/elements/controls/multi_button.lua", "graphics/elements/controls/push_button.lua", "graphics/elements/controls/hazard_button.lua", "graphics/elements/animations/waiting.lua", "graphics/elements/indicators/ledpair.lua", "graphics/elements/indicators/state.lua", "graphics/elements/indicators/icon.lua", "graphics/elements/indicators/hbar.lua", "graphics/elements/indicators/light.lua", "graphics/elements/indicators/led.lua", "graphics/elements/indicators/data.lua", "graphics/elements/indicators/rad.lua", "graphics/elements/indicators/trilight.lua", "graphics/elements/indicators/vbar.lua", "graphics/elements/indicators/coremap.lua", "graphics/elements/indicators/power.lua", "graphics/elements/indicators/ledrgb.lua", "graphics/elements/indicators/alight.lua"], "lockbox": ["lockbox/LICENSE", "lockbox/init.lua", "lockbox/digest/sha1.lua", "lockbox/digest/sha2_256.lua", "lockbox/digest/sha2_224.lua", "lockbox/cipher/aes128.lua", "lockbox/cipher/aes192.lua", "lockbox/cipher/aes256.lua", "lockbox/cipher/mode/cfb.lua", "lockbox/cipher/mode/cbc.lua", "lockbox/cipher/mode/ofb.lua", "lockbox/cipher/mode/ctr.lua", "lockbox/mac/hmac.lua", "lockbox/kdf/pbkdf2.lua", "lockbox/padding/ansix923.lua", "lockbox/padding/isoiec7816.lua", "lockbox/padding/zero.lua", "lockbox/padding/pkcs7.lua", "lockbox/util/stream.lua", "lockbox/util/bit.lua", "lockbox/util/queue.lua", "lockbox/util/array.lua"], "reactor-plc": ["reactor-plc/config.lua", "reactor-plc/plc.lua", "reactor-plc/renderer.lua", "reactor-plc/databus.lua", "reactor-plc/startup.lua", "reactor-plc/threads.lua", "reactor-plc/panel/style.lua", "reactor-plc/panel/front_panel.lua"], "rtu": ["rtu/modbus.lua", "rtu/rtu.lua", "rtu/config.lua", "rtu/renderer.lua", "rtu/databus.lua", "rtu/startup.lua", "rtu/threads.lua", "rtu/dev/redstone_rtu.lua", "rtu/dev/sps_rtu.lua", "rtu/dev/turbinev_rtu.lua", "rtu/dev/envd_rtu.lua", "rtu/dev/boilerv_rtu.lua", "rtu/dev/imatrix_rtu.lua", "rtu/dev/sna_rtu.lua", "rtu/panel/style.lua", "rtu/panel/front_panel.lua"], "supervisor": ["supervisor/unit.lua", "supervisor/supervisor.lua", "supervisor/config.lua", "supervisor/renderer.lua", "supervisor/databus.lua", "supervisor/startup.lua", "supervisor/facility.lua", "supervisor/unitlogic.lua", "supervisor/panel/style.lua", "supervisor/panel/front_panel.lua", "supervisor/panel/pgi.lua", "supervisor/panel/components/pdg_entry.lua", "supervisor/panel/components/rtu_entry.lua", "supervisor/session/coordinator.lua", "supervisor/session/rtu.lua", "supervisor/session/plc.lua", "supervisor/session/svsessions.lua", "supervisor/session/pocket.lua", "supervisor/session/svqtypes.lua", "supervisor/session/rsctl.lua", "supervisor/session/rtu/redstone.lua", "supervisor/session/rtu/imatrix.lua", "supervisor/session/rtu/envd.lua", "supervisor/session/rtu/qtypes.lua", "supervisor/session/rtu/txnctrl.lua", "supervisor/session/rtu/turbinev.lua", "supervisor/session/rtu/sna.lua", "supervisor/session/rtu/unit_session.lua", "supervisor/session/rtu/boilerv.lua", "supervisor/session/rtu/sps.lua"], "coordinator": ["coordinator/coordinator.lua", "coordinator/iocontrol.lua", "coordinator/config.lua", "coordinator/renderer.lua", "coordinator/startup.lua", "coordinator/sounder.lua", "coordinator/process.lua", "coordinator/session/pocket.lua", "coordinator/session/apisessions.lua", "coordinator/ui/style.lua", "coordinator/ui/dialog.lua", "coordinator/ui/components/processctl.lua", "coordinator/ui/components/turbine.lua", "coordinator/ui/components/reactor.lua", "coordinator/ui/components/imatrix.lua", "coordinator/ui/components/boiler.lua", "coordinator/ui/components/unit_detail.lua", "coordinator/ui/components/unit_overview.lua", "coordinator/ui/layout/main_view.lua", "coordinator/ui/layout/unit_view.lua"], "pocket": ["pocket/config.lua", "pocket/renderer.lua", "pocket/startup.lua", "pocket/coreio.lua", "pocket/pocket.lua", "pocket/ui/style.lua", "pocket/ui/main.lua", "pocket/ui/pages/reactor_page.lua", "pocket/ui/pages/boiler_page.lua", "pocket/ui/pages/home_page.lua", "pocket/ui/pages/unit_page.lua", "pocket/ui/pages/turbine_page.lua", "pocket/ui/components/conn_waiting.lua"]}, "depends": {"reactor-plc": ["system", "common", "graphics"], "rtu": ["system", "common", "graphics"], "supervisor": ["system", "common", "graphics"], "coordinator": ["system", "common", "graphics"], "pocket": ["system", "common", "graphics"]}, "sizes": {"manifest": 5804, "system": 1991, "common": 93200, "graphics": 144556, "lockbox": 100797, "reactor-plc": 97317, "rtu": 102353, "supervisor": 315477, "coordinator": 197991, "pocket": 37581}}
\ No newline at end of file
+{"versions": {"installer": "v1.5", "bootloader": "0.2", "comms": "2.1.0", "graphics": "1.0.0", "lockbox": "1.0", "reactor-plc": "v1.5.0", "rtu": "v1.4.0", "supervisor": "v0.18.0", "coordinator": "v0.17.1", "pocket": "alpha-v0.5.1"}, "files": {"system": ["initenv.lua", "startup.lua"], "common": ["scada-common/ppm.lua", "scada-common/comms.lua", "scada-common/psil.lua", "scada-common/rsio.lua", "scada-common/constants.lua", "scada-common/mqueue.lua", "scada-common/tcd.lua", "scada-common/crash.lua", "scada-common/log.lua", "scada-common/types.lua", "scada-common/util.lua", "scada-common/network.lua"], "graphics": ["graphics/element.lua", "graphics/events.lua", "graphics/flasher.lua", "graphics/core.lua", "graphics/elements/listbox.lua", "graphics/elements/textbox.lua", "graphics/elements/displaybox.lua", "graphics/elements/pipenet.lua", "graphics/elements/rectangle.lua", "graphics/elements/div.lua", "graphics/elements/multipane.lua", "graphics/elements/tiling.lua", "graphics/elements/colormap.lua", "graphics/elements/indicators/alight.lua", "graphics/elements/indicators/icon.lua", "graphics/elements/indicators/power.lua", "graphics/elements/indicators/rad.lua", "graphics/elements/indicators/state.lua", "graphics/elements/indicators/light.lua", "graphics/elements/indicators/vbar.lua", "graphics/elements/indicators/led.lua", "graphics/elements/indicators/coremap.lua", "graphics/elements/indicators/data.lua", "graphics/elements/indicators/ledpair.lua", "graphics/elements/indicators/hbar.lua", "graphics/elements/indicators/trilight.lua", "graphics/elements/indicators/ledrgb.lua", "graphics/elements/controls/switch_button.lua", "graphics/elements/controls/spinbox_numeric.lua", "graphics/elements/controls/hazard_button.lua", "graphics/elements/controls/push_button.lua", "graphics/elements/controls/radio_button.lua", "graphics/elements/controls/multi_button.lua", "graphics/elements/controls/tabbar.lua", "graphics/elements/controls/sidebar.lua", "graphics/elements/animations/waiting.lua"], "lockbox": ["lockbox/init.lua", "lockbox/LICENSE", "lockbox/kdf/pbkdf2.lua", "lockbox/util/bit.lua", "lockbox/util/array.lua", "lockbox/util/stream.lua", "lockbox/util/queue.lua", "lockbox/digest/sha2_224.lua", "lockbox/digest/sha1.lua", "lockbox/digest/sha2_256.lua", "lockbox/digest/md5.lua", "lockbox/mac/hmac.lua"], "reactor-plc": ["reactor-plc/renderer.lua", "reactor-plc/threads.lua", "reactor-plc/databus.lua", "reactor-plc/plc.lua", "reactor-plc/config.lua", "reactor-plc/startup.lua", "reactor-plc/panel/front_panel.lua", "reactor-plc/panel/style.lua"], "rtu": ["rtu/renderer.lua", "rtu/threads.lua", "rtu/rtu.lua", "rtu/databus.lua", "rtu/modbus.lua", "rtu/config.lua", "rtu/startup.lua", "rtu/panel/front_panel.lua", "rtu/panel/style.lua", "rtu/dev/sps_rtu.lua", "rtu/dev/envd_rtu.lua", "rtu/dev/boilerv_rtu.lua", "rtu/dev/redstone_rtu.lua", "rtu/dev/sna_rtu.lua", "rtu/dev/imatrix_rtu.lua", "rtu/dev/turbinev_rtu.lua"], "supervisor": ["supervisor/renderer.lua", "supervisor/databus.lua", "supervisor/supervisor.lua", "supervisor/unit.lua", "supervisor/config.lua", "supervisor/startup.lua", "supervisor/unitlogic.lua", "supervisor/facility.lua", "supervisor/panel/pgi.lua", "supervisor/panel/front_panel.lua", "supervisor/panel/style.lua", "supervisor/panel/components/rtu_entry.lua", "supervisor/panel/components/pdg_entry.lua", "supervisor/session/coordinator.lua", "supervisor/session/svqtypes.lua", "supervisor/session/pocket.lua", "supervisor/session/svsessions.lua", "supervisor/session/rtu.lua", "supervisor/session/plc.lua", "supervisor/session/rsctl.lua", "supervisor/session/rtu/boilerv.lua", "supervisor/session/rtu/txnctrl.lua", "supervisor/session/rtu/unit_session.lua", "supervisor/session/rtu/turbinev.lua", "supervisor/session/rtu/envd.lua", "supervisor/session/rtu/imatrix.lua", "supervisor/session/rtu/sps.lua", "supervisor/session/rtu/qtypes.lua", "supervisor/session/rtu/sna.lua", "supervisor/session/rtu/redstone.lua"], "coordinator": ["coordinator/coordinator.lua", "coordinator/renderer.lua", "coordinator/iocontrol.lua", "coordinator/sounder.lua", "coordinator/config.lua", "coordinator/startup.lua", "coordinator/process.lua", "coordinator/ui/dialog.lua", "coordinator/ui/style.lua", "coordinator/ui/layout/main_view.lua", "coordinator/ui/layout/unit_view.lua", "coordinator/ui/components/reactor.lua", "coordinator/ui/components/processctl.lua", "coordinator/ui/components/unit_overview.lua", "coordinator/ui/components/boiler.lua", "coordinator/ui/components/unit_detail.lua", "coordinator/ui/components/imatrix.lua", "coordinator/ui/components/turbine.lua", "coordinator/session/pocket.lua", "coordinator/session/apisessions.lua"], "pocket": ["pocket/pocket.lua", "pocket/renderer.lua", "pocket/config.lua", "pocket/coreio.lua", "pocket/startup.lua", "pocket/ui/main.lua", "pocket/ui/style.lua", "pocket/ui/components/conn_waiting.lua", "pocket/ui/pages/turbine_page.lua", "pocket/ui/pages/reactor_page.lua", "pocket/ui/pages/home_page.lua", "pocket/ui/pages/unit_page.lua", "pocket/ui/pages/boiler_page.lua"]}, "depends": {"reactor-plc": ["system", "common", "graphics", "lockbox"], "rtu": ["system", "common", "graphics", "lockbox"], "supervisor": ["system", "common", "graphics", "lockbox"], "coordinator": ["system", "common", "graphics", "lockbox"], "pocket": ["system", "common", "graphics", "lockbox"]}, "sizes": {"manifest": 5567, "system": 1991, "common": 97110, "graphics": 144556, "lockbox": 34900, "reactor-plc": 97698, "rtu": 102350, "supervisor": 315528, "coordinator": 198291, "pocket": 37736}}
\ No newline at end of file
diff --git a/lockbox/cipher/aes128.lua b/lockbox/cipher/aes128.lua
deleted file mode 100644
index 0726ac4..0000000
--- a/lockbox/cipher/aes128.lua
+++ /dev/null
@@ -1,415 +0,0 @@
-local Array = require("lockbox.util.array");
-local Bit = require("lockbox.util.bit");
-
-local XOR = Bit.bxor;
-
-local SBOX = {
- [0] = 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
- 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
- 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
- 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
- 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
- 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
- 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
- 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
- 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
- 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
- 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
- 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
- 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
- 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
- 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
- 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16};
-
-local ISBOX = {
- [0] = 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
- 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
- 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
- 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
- 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
- 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
- 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
- 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
- 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
- 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
- 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
- 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
- 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
- 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
- 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
- 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D};
-
-local ROW_SHIFT = { 1, 6, 11, 16, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, };
-local IROW_SHIFT = { 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3, 16, 13, 10, 7, 4, };
-
-local ETABLE = {
- [0] = 0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, 0x96, 0xA1, 0xF8, 0x13, 0x35,
- 0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, 0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA,
- 0xE5, 0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, 0x90, 0xAB, 0xE6, 0x31,
- 0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, 0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD,
- 0x4C, 0xD4, 0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, 0x28, 0x78, 0x88,
- 0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, 0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A,
- 0xB5, 0xC4, 0x57, 0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, 0x61, 0xA3,
- 0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, 0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0,
- 0xFB, 0x16, 0x3A, 0x4E, 0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, 0x41,
- 0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, 0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75,
- 0x9F, 0xBA, 0xD5, 0x64, 0xAC, 0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80,
- 0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, 0xB1, 0xC8, 0x43, 0xC5, 0x54,
- 0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, 0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA,
- 0x45, 0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, 0xC6, 0x51, 0xF3, 0x0E,
- 0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, 0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17,
- 0x39, 0x4B, 0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, 0x52, 0xF6, 0x01};
-
-local LTABLE = {
- [0] = 0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1A, 0xC6, 0x4B, 0xC7, 0x1B, 0x68, 0x33, 0xEE, 0xDF, 0x03,
- 0x64, 0x04, 0xE0, 0x0E, 0x34, 0x8D, 0x81, 0xEF, 0x4C, 0x71, 0x08, 0xC8, 0xF8, 0x69, 0x1C, 0xC1,
- 0x7D, 0xC2, 0x1D, 0xB5, 0xF9, 0xB9, 0x27, 0x6A, 0x4D, 0xE4, 0xA6, 0x72, 0x9A, 0xC9, 0x09, 0x78,
- 0x65, 0x2F, 0x8A, 0x05, 0x21, 0x0F, 0xE1, 0x24, 0x12, 0xF0, 0x82, 0x45, 0x35, 0x93, 0xDA, 0x8E,
- 0x96, 0x8F, 0xDB, 0xBD, 0x36, 0xD0, 0xCE, 0x94, 0x13, 0x5C, 0xD2, 0xF1, 0x40, 0x46, 0x83, 0x38,
- 0x66, 0xDD, 0xFD, 0x30, 0xBF, 0x06, 0x8B, 0x62, 0xB3, 0x25, 0xE2, 0x98, 0x22, 0x88, 0x91, 0x10,
- 0x7E, 0x6E, 0x48, 0xC3, 0xA3, 0xB6, 0x1E, 0x42, 0x3A, 0x6B, 0x28, 0x54, 0xFA, 0x85, 0x3D, 0xBA,
- 0x2B, 0x79, 0x0A, 0x15, 0x9B, 0x9F, 0x5E, 0xCA, 0x4E, 0xD4, 0xAC, 0xE5, 0xF3, 0x73, 0xA7, 0x57,
- 0xAF, 0x58, 0xA8, 0x50, 0xF4, 0xEA, 0xD6, 0x74, 0x4F, 0xAE, 0xE9, 0xD5, 0xE7, 0xE6, 0xAD, 0xE8,
- 0x2C, 0xD7, 0x75, 0x7A, 0xEB, 0x16, 0x0B, 0xF5, 0x59, 0xCB, 0x5F, 0xB0, 0x9C, 0xA9, 0x51, 0xA0,
- 0x7F, 0x0C, 0xF6, 0x6F, 0x17, 0xC4, 0x49, 0xEC, 0xD8, 0x43, 0x1F, 0x2D, 0xA4, 0x76, 0x7B, 0xB7,
- 0xCC, 0xBB, 0x3E, 0x5A, 0xFB, 0x60, 0xB1, 0x86, 0x3B, 0x52, 0xA1, 0x6C, 0xAA, 0x55, 0x29, 0x9D,
- 0x97, 0xB2, 0x87, 0x90, 0x61, 0xBE, 0xDC, 0xFC, 0xBC, 0x95, 0xCF, 0xCD, 0x37, 0x3F, 0x5B, 0xD1,
- 0x53, 0x39, 0x84, 0x3C, 0x41, 0xA2, 0x6D, 0x47, 0x14, 0x2A, 0x9E, 0x5D, 0x56, 0xF2, 0xD3, 0xAB,
- 0x44, 0x11, 0x92, 0xD9, 0x23, 0x20, 0x2E, 0x89, 0xB4, 0x7C, 0xB8, 0x26, 0x77, 0x99, 0xE3, 0xA5,
- 0x67, 0x4A, 0xED, 0xDE, 0xC5, 0x31, 0xFE, 0x18, 0x0D, 0x63, 0x8C, 0x80, 0xC0, 0xF7, 0x70, 0x07};
-
-local MIXTABLE = {
- 0x02, 0x03, 0x01, 0x01,
- 0x01, 0x02, 0x03, 0x01,
- 0x01, 0x01, 0x02, 0x03,
- 0x03, 0x01, 0x01, 0x02};
-
-local IMIXTABLE = {
- 0x0E, 0x0B, 0x0D, 0x09,
- 0x09, 0x0E, 0x0B, 0x0D,
- 0x0D, 0x09, 0x0E, 0x0B,
- 0x0B, 0x0D, 0x09, 0x0E};
-
-local RCON = {
-[0] = 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
-0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
-0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
-0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
-0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
-0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
-0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
-0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
-0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
-0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
-0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
-0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
-0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
-0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
-0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
-0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d};
-
-
-local GMUL = function(A, B)
- if(A == 0x01) then return B; end
- if(B == 0x01) then return A; end
- if(A == 0x00) then return 0; end
- if(B == 0x00) then return 0; end
-
- local LA = LTABLE[A];
- local LB = LTABLE[B];
-
- local sum = LA + LB;
- if (sum > 0xFF) then sum = sum - 0xFF; end
-
- return ETABLE[sum];
-end
-
-local byteSub = Array.substitute;
-
-local shiftRow = Array.permute;
-
-local mixCol = function(i, mix)
- local out = {};
-
- local a, b, c, d;
-
- a = GMUL(i[ 1], mix[ 1]);
- b = GMUL(i[ 2], mix[ 2]);
- c = GMUL(i[ 3], mix[ 3]);
- d = GMUL(i[ 4], mix[ 4]);
- out[ 1] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 1], mix[ 5]);
- b = GMUL(i[ 2], mix[ 6]);
- c = GMUL(i[ 3], mix[ 7]);
- d = GMUL(i[ 4], mix[ 8]);
- out[ 2] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 1], mix[ 9]);
- b = GMUL(i[ 2], mix[10]);
- c = GMUL(i[ 3], mix[11]);
- d = GMUL(i[ 4], mix[12]);
- out[ 3] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 1], mix[13]);
- b = GMUL(i[ 2], mix[14]);
- c = GMUL(i[ 3], mix[15]);
- d = GMUL(i[ 4], mix[16]);
- out[ 4] = XOR(XOR(a, b), XOR(c, d));
-
-
- a = GMUL(i[ 5], mix[ 1]);
- b = GMUL(i[ 6], mix[ 2]);
- c = GMUL(i[ 7], mix[ 3]);
- d = GMUL(i[ 8], mix[ 4]);
- out[ 5] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 5], mix[ 5]);
- b = GMUL(i[ 6], mix[ 6]);
- c = GMUL(i[ 7], mix[ 7]);
- d = GMUL(i[ 8], mix[ 8]);
- out[ 6] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 5], mix[ 9]);
- b = GMUL(i[ 6], mix[10]);
- c = GMUL(i[ 7], mix[11]);
- d = GMUL(i[ 8], mix[12]);
- out[ 7] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 5], mix[13]);
- b = GMUL(i[ 6], mix[14]);
- c = GMUL(i[ 7], mix[15]);
- d = GMUL(i[ 8], mix[16]);
- out[ 8] = XOR(XOR(a, b), XOR(c, d));
-
-
- a = GMUL(i[ 9], mix[ 1]);
- b = GMUL(i[10], mix[ 2]);
- c = GMUL(i[11], mix[ 3]);
- d = GMUL(i[12], mix[ 4]);
- out[ 9] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 9], mix[ 5]);
- b = GMUL(i[10], mix[ 6]);
- c = GMUL(i[11], mix[ 7]);
- d = GMUL(i[12], mix[ 8]);
- out[10] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 9], mix[ 9]);
- b = GMUL(i[10], mix[10]);
- c = GMUL(i[11], mix[11]);
- d = GMUL(i[12], mix[12]);
- out[11] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 9], mix[13]);
- b = GMUL(i[10], mix[14]);
- c = GMUL(i[11], mix[15]);
- d = GMUL(i[12], mix[16]);
- out[12] = XOR(XOR(a, b), XOR(c, d));
-
-
- a = GMUL(i[13], mix[ 1]);
- b = GMUL(i[14], mix[ 2]);
- c = GMUL(i[15], mix[ 3]);
- d = GMUL(i[16], mix[ 4]);
- out[13] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[13], mix[ 5]);
- b = GMUL(i[14], mix[ 6]);
- c = GMUL(i[15], mix[ 7]);
- d = GMUL(i[16], mix[ 8]);
- out[14] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[13], mix[ 9]);
- b = GMUL(i[14], mix[10]);
- c = GMUL(i[15], mix[11]);
- d = GMUL(i[16], mix[12]);
- out[15] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[13], mix[13]);
- b = GMUL(i[14], mix[14]);
- c = GMUL(i[15], mix[15]);
- d = GMUL(i[16], mix[16]);
- out[16] = XOR(XOR(a, b), XOR(c, d));
-
- return out;
-end
-
-local keyRound = function(key, round)
- local out = {};
-
- out[ 1] = XOR(key[ 1], XOR(SBOX[key[14]], RCON[round]));
- out[ 2] = XOR(key[ 2], SBOX[key[15]]);
- out[ 3] = XOR(key[ 3], SBOX[key[16]]);
- out[ 4] = XOR(key[ 4], SBOX[key[13]]);
-
- out[ 5] = XOR(out[ 1], key[ 5]);
- out[ 6] = XOR(out[ 2], key[ 6]);
- out[ 7] = XOR(out[ 3], key[ 7]);
- out[ 8] = XOR(out[ 4], key[ 8]);
-
- out[ 9] = XOR(out[ 5], key[ 9]);
- out[10] = XOR(out[ 6], key[10]);
- out[11] = XOR(out[ 7], key[11]);
- out[12] = XOR(out[ 8], key[12]);
-
- out[13] = XOR(out[ 9], key[13]);
- out[14] = XOR(out[10], key[14]);
- out[15] = XOR(out[11], key[15]);
- out[16] = XOR(out[12], key[16]);
-
- return out;
-end
-
-local keyExpand = function(key)
- local keys = {};
-
- local temp = key;
-
- keys[1] = temp;
-
- for i = 1, 10 do
- temp = keyRound(temp, i);
- keys[i + 1] = temp;
- end
-
- return keys;
-
-end
-
-local addKey = Array.XOR;
-
-
-
-local AES = {};
-
-AES.blockSize = 16;
-
-AES.encrypt = function(_key, block)
-
- local key = keyExpand(_key);
-
- --round 0
- block = addKey(block, key[1]);
-
- --round 1
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[2]);
-
- --round 2
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[3]);
-
- --round 3
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[4]);
-
- --round 4
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[5]);
-
- --round 5
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[6]);
-
- --round 6
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[7]);
-
- --round 7
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[8]);
-
- --round 8
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[9]);
-
- --round 9
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[10]);
-
- --round 10
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = addKey(block, key[11]);
-
- return block;
-
-end
-
-AES.decrypt = function(_key, block)
-
- local key = keyExpand(_key);
-
- --round 0
- block = addKey(block, key[11]);
-
- --round 1
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[10]);
- block = mixCol(block, IMIXTABLE);
-
- --round 2
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[9]);
- block = mixCol(block, IMIXTABLE);
-
- --round 3
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[8]);
- block = mixCol(block, IMIXTABLE);
-
- --round 4
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[7]);
- block = mixCol(block, IMIXTABLE);
-
- --round 5
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[6]);
- block = mixCol(block, IMIXTABLE);
-
- --round 6
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[5]);
- block = mixCol(block, IMIXTABLE);
-
- --round 7
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[4]);
- block = mixCol(block, IMIXTABLE);
-
- --round 8
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[3]);
- block = mixCol(block, IMIXTABLE);
-
- --round 9
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[2]);
- block = mixCol(block, IMIXTABLE);
-
- --round 10
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[1]);
-
- return block;
-end
-
-return AES;
diff --git a/lockbox/cipher/aes192.lua b/lockbox/cipher/aes192.lua
deleted file mode 100644
index 5f55b0e..0000000
--- a/lockbox/cipher/aes192.lua
+++ /dev/null
@@ -1,462 +0,0 @@
-
-local Array = require("lockbox.util.array");
-local Bit = require("lockbox.util.bit");
-
-local XOR = Bit.bxor;
-
-local SBOX = {
- [0] = 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
- 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
- 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
- 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
- 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
- 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
- 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
- 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
- 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
- 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
- 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
- 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
- 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
- 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
- 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
- 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16};
-
-local ISBOX = {
- [0] = 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
- 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
- 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
- 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
- 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
- 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
- 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
- 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
- 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
- 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
- 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
- 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
- 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
- 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
- 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
- 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D};
-
-local ROW_SHIFT = { 1, 6, 11, 16, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, };
-local IROW_SHIFT = { 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3, 16, 13, 10, 7, 4, };
-
-local ETABLE = {
- [0] = 0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, 0x96, 0xA1, 0xF8, 0x13, 0x35,
- 0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, 0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA,
- 0xE5, 0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, 0x90, 0xAB, 0xE6, 0x31,
- 0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, 0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD,
- 0x4C, 0xD4, 0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, 0x28, 0x78, 0x88,
- 0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, 0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A,
- 0xB5, 0xC4, 0x57, 0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, 0x61, 0xA3,
- 0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, 0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0,
- 0xFB, 0x16, 0x3A, 0x4E, 0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, 0x41,
- 0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, 0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75,
- 0x9F, 0xBA, 0xD5, 0x64, 0xAC, 0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80,
- 0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, 0xB1, 0xC8, 0x43, 0xC5, 0x54,
- 0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, 0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA,
- 0x45, 0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, 0xC6, 0x51, 0xF3, 0x0E,
- 0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, 0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17,
- 0x39, 0x4B, 0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, 0x52, 0xF6, 0x01};
-
-local LTABLE = {
- [0] = 0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1A, 0xC6, 0x4B, 0xC7, 0x1B, 0x68, 0x33, 0xEE, 0xDF, 0x03,
- 0x64, 0x04, 0xE0, 0x0E, 0x34, 0x8D, 0x81, 0xEF, 0x4C, 0x71, 0x08, 0xC8, 0xF8, 0x69, 0x1C, 0xC1,
- 0x7D, 0xC2, 0x1D, 0xB5, 0xF9, 0xB9, 0x27, 0x6A, 0x4D, 0xE4, 0xA6, 0x72, 0x9A, 0xC9, 0x09, 0x78,
- 0x65, 0x2F, 0x8A, 0x05, 0x21, 0x0F, 0xE1, 0x24, 0x12, 0xF0, 0x82, 0x45, 0x35, 0x93, 0xDA, 0x8E,
- 0x96, 0x8F, 0xDB, 0xBD, 0x36, 0xD0, 0xCE, 0x94, 0x13, 0x5C, 0xD2, 0xF1, 0x40, 0x46, 0x83, 0x38,
- 0x66, 0xDD, 0xFD, 0x30, 0xBF, 0x06, 0x8B, 0x62, 0xB3, 0x25, 0xE2, 0x98, 0x22, 0x88, 0x91, 0x10,
- 0x7E, 0x6E, 0x48, 0xC3, 0xA3, 0xB6, 0x1E, 0x42, 0x3A, 0x6B, 0x28, 0x54, 0xFA, 0x85, 0x3D, 0xBA,
- 0x2B, 0x79, 0x0A, 0x15, 0x9B, 0x9F, 0x5E, 0xCA, 0x4E, 0xD4, 0xAC, 0xE5, 0xF3, 0x73, 0xA7, 0x57,
- 0xAF, 0x58, 0xA8, 0x50, 0xF4, 0xEA, 0xD6, 0x74, 0x4F, 0xAE, 0xE9, 0xD5, 0xE7, 0xE6, 0xAD, 0xE8,
- 0x2C, 0xD7, 0x75, 0x7A, 0xEB, 0x16, 0x0B, 0xF5, 0x59, 0xCB, 0x5F, 0xB0, 0x9C, 0xA9, 0x51, 0xA0,
- 0x7F, 0x0C, 0xF6, 0x6F, 0x17, 0xC4, 0x49, 0xEC, 0xD8, 0x43, 0x1F, 0x2D, 0xA4, 0x76, 0x7B, 0xB7,
- 0xCC, 0xBB, 0x3E, 0x5A, 0xFB, 0x60, 0xB1, 0x86, 0x3B, 0x52, 0xA1, 0x6C, 0xAA, 0x55, 0x29, 0x9D,
- 0x97, 0xB2, 0x87, 0x90, 0x61, 0xBE, 0xDC, 0xFC, 0xBC, 0x95, 0xCF, 0xCD, 0x37, 0x3F, 0x5B, 0xD1,
- 0x53, 0x39, 0x84, 0x3C, 0x41, 0xA2, 0x6D, 0x47, 0x14, 0x2A, 0x9E, 0x5D, 0x56, 0xF2, 0xD3, 0xAB,
- 0x44, 0x11, 0x92, 0xD9, 0x23, 0x20, 0x2E, 0x89, 0xB4, 0x7C, 0xB8, 0x26, 0x77, 0x99, 0xE3, 0xA5,
- 0x67, 0x4A, 0xED, 0xDE, 0xC5, 0x31, 0xFE, 0x18, 0x0D, 0x63, 0x8C, 0x80, 0xC0, 0xF7, 0x70, 0x07};
-
-local MIXTABLE = {
- 0x02, 0x03, 0x01, 0x01,
- 0x01, 0x02, 0x03, 0x01,
- 0x01, 0x01, 0x02, 0x03,
- 0x03, 0x01, 0x01, 0x02};
-
-local IMIXTABLE = {
- 0x0E, 0x0B, 0x0D, 0x09,
- 0x09, 0x0E, 0x0B, 0x0D,
- 0x0D, 0x09, 0x0E, 0x0B,
- 0x0B, 0x0D, 0x09, 0x0E};
-
-local RCON = {
-[0] = 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
-0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
-0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
-0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
-0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
-0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
-0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
-0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
-0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
-0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
-0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
-0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
-0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
-0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
-0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
-0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d};
-
-
-local GMUL = function(A, B)
- if(A == 0x01) then return B; end
- if(B == 0x01) then return A; end
- if(A == 0x00) then return 0; end
- if(B == 0x00) then return 0; end
-
- local LA = LTABLE[A];
- local LB = LTABLE[B];
-
- local sum = LA + LB;
- if (sum > 0xFF) then sum = sum - 0xFF; end
-
- return ETABLE[sum];
-end
-
-local byteSub = Array.substitute;
-
-local shiftRow = Array.permute;
-
-local mixCol = function(i, mix)
- local out = {};
-
- local a, b, c, d;
-
- a = GMUL(i[ 1], mix[ 1]);
- b = GMUL(i[ 2], mix[ 2]);
- c = GMUL(i[ 3], mix[ 3]);
- d = GMUL(i[ 4], mix[ 4]);
- out[ 1] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 1], mix[ 5]);
- b = GMUL(i[ 2], mix[ 6]);
- c = GMUL(i[ 3], mix[ 7]);
- d = GMUL(i[ 4], mix[ 8]);
- out[ 2] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 1], mix[ 9]);
- b = GMUL(i[ 2], mix[10]);
- c = GMUL(i[ 3], mix[11]);
- d = GMUL(i[ 4], mix[12]);
- out[ 3] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 1], mix[13]);
- b = GMUL(i[ 2], mix[14]);
- c = GMUL(i[ 3], mix[15]);
- d = GMUL(i[ 4], mix[16]);
- out[ 4] = XOR(XOR(a, b), XOR(c, d));
-
-
- a = GMUL(i[ 5], mix[ 1]);
- b = GMUL(i[ 6], mix[ 2]);
- c = GMUL(i[ 7], mix[ 3]);
- d = GMUL(i[ 8], mix[ 4]);
- out[ 5] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 5], mix[ 5]);
- b = GMUL(i[ 6], mix[ 6]);
- c = GMUL(i[ 7], mix[ 7]);
- d = GMUL(i[ 8], mix[ 8]);
- out[ 6] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 5], mix[ 9]);
- b = GMUL(i[ 6], mix[10]);
- c = GMUL(i[ 7], mix[11]);
- d = GMUL(i[ 8], mix[12]);
- out[ 7] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 5], mix[13]);
- b = GMUL(i[ 6], mix[14]);
- c = GMUL(i[ 7], mix[15]);
- d = GMUL(i[ 8], mix[16]);
- out[ 8] = XOR(XOR(a, b), XOR(c, d));
-
-
- a = GMUL(i[ 9], mix[ 1]);
- b = GMUL(i[10], mix[ 2]);
- c = GMUL(i[11], mix[ 3]);
- d = GMUL(i[12], mix[ 4]);
- out[ 9] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 9], mix[ 5]);
- b = GMUL(i[10], mix[ 6]);
- c = GMUL(i[11], mix[ 7]);
- d = GMUL(i[12], mix[ 8]);
- out[10] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 9], mix[ 9]);
- b = GMUL(i[10], mix[10]);
- c = GMUL(i[11], mix[11]);
- d = GMUL(i[12], mix[12]);
- out[11] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 9], mix[13]);
- b = GMUL(i[10], mix[14]);
- c = GMUL(i[11], mix[15]);
- d = GMUL(i[12], mix[16]);
- out[12] = XOR(XOR(a, b), XOR(c, d));
-
-
- a = GMUL(i[13], mix[ 1]);
- b = GMUL(i[14], mix[ 2]);
- c = GMUL(i[15], mix[ 3]);
- d = GMUL(i[16], mix[ 4]);
- out[13] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[13], mix[ 5]);
- b = GMUL(i[14], mix[ 6]);
- c = GMUL(i[15], mix[ 7]);
- d = GMUL(i[16], mix[ 8]);
- out[14] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[13], mix[ 9]);
- b = GMUL(i[14], mix[10]);
- c = GMUL(i[15], mix[11]);
- d = GMUL(i[16], mix[12]);
- out[15] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[13], mix[13]);
- b = GMUL(i[14], mix[14]);
- c = GMUL(i[15], mix[15]);
- d = GMUL(i[16], mix[16]);
- out[16] = XOR(XOR(a, b), XOR(c, d));
-
- return out;
-end
-
-local keyRound = function(key, round)
- local i = (round - 1) * 24;
- local out = key;
-
- out[25 + i] = XOR(key[ 1 + i], XOR(SBOX[key[22 + i]], RCON[round]));
- out[26 + i] = XOR(key[ 2 + i], SBOX[key[23 + i]]);
- out[27 + i] = XOR(key[ 3 + i], SBOX[key[24 + i]]);
- out[28 + i] = XOR(key[ 4 + i], SBOX[key[21 + i]]);
-
- out[29 + i] = XOR(out[25 + i], key[ 5 + i]);
- out[30 + i] = XOR(out[26 + i], key[ 6 + i]);
- out[31 + i] = XOR(out[27 + i], key[ 7 + i]);
- out[32 + i] = XOR(out[28 + i], key[ 8 + i]);
-
- out[33 + i] = XOR(out[29 + i], key[ 9 + i]);
- out[34 + i] = XOR(out[30 + i], key[10 + i]);
- out[35 + i] = XOR(out[31 + i], key[11 + i]);
- out[36 + i] = XOR(out[32 + i], key[12 + i]);
-
- out[37 + i] = XOR(out[33 + i], key[13 + i]);
- out[38 + i] = XOR(out[34 + i], key[14 + i]);
- out[39 + i] = XOR(out[35 + i], key[15 + i]);
- out[40 + i] = XOR(out[36 + i], key[16 + i]);
-
- out[41 + i] = XOR(out[37 + i], key[17 + i]);
- out[42 + i] = XOR(out[38 + i], key[18 + i]);
- out[43 + i] = XOR(out[39 + i], key[19 + i]);
- out[44 + i] = XOR(out[40 + i], key[20 + i]);
-
- out[45 + i] = XOR(out[41 + i], key[21 + i]);
- out[46 + i] = XOR(out[42 + i], key[22 + i]);
- out[47 + i] = XOR(out[43 + i], key[23 + i]);
- out[48 + i] = XOR(out[44 + i], key[24 + i]);
-
- return out;
-end
-
-local keyExpand = function(key)
- local bytes = Array.copy(key);
-
- for i = 1, 8 do
- keyRound(bytes, i);
- end
-
- local keys = {};
-
- keys[ 1] = Array.slice(bytes, 1, 16);
- keys[ 2] = Array.slice(bytes, 17, 32);
- keys[ 3] = Array.slice(bytes, 33, 48);
- keys[ 4] = Array.slice(bytes, 49, 64);
- keys[ 5] = Array.slice(bytes, 65, 80);
- keys[ 6] = Array.slice(bytes, 81, 96);
- keys[ 7] = Array.slice(bytes, 97, 112);
- keys[ 8] = Array.slice(bytes, 113, 128);
- keys[ 9] = Array.slice(bytes, 129, 144);
- keys[10] = Array.slice(bytes, 145, 160);
- keys[11] = Array.slice(bytes, 161, 176);
- keys[12] = Array.slice(bytes, 177, 192);
- keys[13] = Array.slice(bytes, 193, 208);
-
- return keys;
-
-end
-
-local addKey = Array.XOR;
-
-
-
-local AES = {};
-
-AES.blockSize = 16;
-
-AES.encrypt = function(_key, block)
-
- local key = keyExpand(_key);
-
- --round 0
- block = addKey(block, key[1]);
-
- --round 1
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[2]);
-
- --round 2
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[3]);
-
- --round 3
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[4]);
-
- --round 4
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[5]);
-
- --round 5
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[6]);
-
- --round 6
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[7]);
-
- --round 7
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[8]);
-
- --round 8
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[9]);
-
- --round 9
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[10]);
-
- --round 10
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[11]);
-
- --round 11
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[12]);
-
- --round 12
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = addKey(block, key[13]);
-
- return block;
-
-end
-
-AES.decrypt = function(_key, block)
-
- local key = keyExpand(_key);
-
- --round 0
- block = addKey(block, key[13]);
-
- --round 1
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[12]);
- block = mixCol(block, IMIXTABLE);
-
- --round 2
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[11]);
- block = mixCol(block, IMIXTABLE);
-
- --round 3
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[10]);
- block = mixCol(block, IMIXTABLE);
-
- --round 4
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[9]);
- block = mixCol(block, IMIXTABLE);
-
- --round 5
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[8]);
- block = mixCol(block, IMIXTABLE);
-
- --round 6
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[7]);
- block = mixCol(block, IMIXTABLE);
-
- --round 7
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[6]);
- block = mixCol(block, IMIXTABLE);
-
- --round 8
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[5]);
- block = mixCol(block, IMIXTABLE);
-
- --round 9
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[4]);
- block = mixCol(block, IMIXTABLE);
-
- --round 10
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[3]);
- block = mixCol(block, IMIXTABLE);
-
- --round 11
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[2]);
- block = mixCol(block, IMIXTABLE);
-
- --round 12
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[1]);
-
- return block;
-end
-
-return AES;
diff --git a/lockbox/cipher/aes256.lua b/lockbox/cipher/aes256.lua
deleted file mode 100644
index 854bae9..0000000
--- a/lockbox/cipher/aes256.lua
+++ /dev/null
@@ -1,498 +0,0 @@
-local Array = require("lockbox.util.array");
-local Bit = require("lockbox.util.bit");
-
-local XOR = Bit.bxor;
-
-local SBOX = {
- [0] = 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
- 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
- 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
- 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
- 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
- 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
- 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
- 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
- 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
- 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
- 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
- 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
- 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
- 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
- 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
- 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16};
-
-local ISBOX = {
- [0] = 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
- 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
- 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
- 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
- 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
- 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
- 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
- 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
- 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
- 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
- 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
- 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
- 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
- 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
- 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
- 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D};
-
-local ROW_SHIFT = { 1, 6, 11, 16, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, };
-local IROW_SHIFT = { 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3, 16, 13, 10, 7, 4, };
-
-local ETABLE = {
- [0] = 0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, 0x96, 0xA1, 0xF8, 0x13, 0x35,
- 0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, 0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA,
- 0xE5, 0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, 0x90, 0xAB, 0xE6, 0x31,
- 0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, 0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD,
- 0x4C, 0xD4, 0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, 0x28, 0x78, 0x88,
- 0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, 0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A,
- 0xB5, 0xC4, 0x57, 0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, 0x61, 0xA3,
- 0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, 0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0,
- 0xFB, 0x16, 0x3A, 0x4E, 0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, 0x41,
- 0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, 0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75,
- 0x9F, 0xBA, 0xD5, 0x64, 0xAC, 0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80,
- 0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, 0xB1, 0xC8, 0x43, 0xC5, 0x54,
- 0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, 0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA,
- 0x45, 0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, 0xC6, 0x51, 0xF3, 0x0E,
- 0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, 0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17,
- 0x39, 0x4B, 0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, 0x52, 0xF6, 0x01};
-
-local LTABLE = {
- [0] = 0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1A, 0xC6, 0x4B, 0xC7, 0x1B, 0x68, 0x33, 0xEE, 0xDF, 0x03,
- 0x64, 0x04, 0xE0, 0x0E, 0x34, 0x8D, 0x81, 0xEF, 0x4C, 0x71, 0x08, 0xC8, 0xF8, 0x69, 0x1C, 0xC1,
- 0x7D, 0xC2, 0x1D, 0xB5, 0xF9, 0xB9, 0x27, 0x6A, 0x4D, 0xE4, 0xA6, 0x72, 0x9A, 0xC9, 0x09, 0x78,
- 0x65, 0x2F, 0x8A, 0x05, 0x21, 0x0F, 0xE1, 0x24, 0x12, 0xF0, 0x82, 0x45, 0x35, 0x93, 0xDA, 0x8E,
- 0x96, 0x8F, 0xDB, 0xBD, 0x36, 0xD0, 0xCE, 0x94, 0x13, 0x5C, 0xD2, 0xF1, 0x40, 0x46, 0x83, 0x38,
- 0x66, 0xDD, 0xFD, 0x30, 0xBF, 0x06, 0x8B, 0x62, 0xB3, 0x25, 0xE2, 0x98, 0x22, 0x88, 0x91, 0x10,
- 0x7E, 0x6E, 0x48, 0xC3, 0xA3, 0xB6, 0x1E, 0x42, 0x3A, 0x6B, 0x28, 0x54, 0xFA, 0x85, 0x3D, 0xBA,
- 0x2B, 0x79, 0x0A, 0x15, 0x9B, 0x9F, 0x5E, 0xCA, 0x4E, 0xD4, 0xAC, 0xE5, 0xF3, 0x73, 0xA7, 0x57,
- 0xAF, 0x58, 0xA8, 0x50, 0xF4, 0xEA, 0xD6, 0x74, 0x4F, 0xAE, 0xE9, 0xD5, 0xE7, 0xE6, 0xAD, 0xE8,
- 0x2C, 0xD7, 0x75, 0x7A, 0xEB, 0x16, 0x0B, 0xF5, 0x59, 0xCB, 0x5F, 0xB0, 0x9C, 0xA9, 0x51, 0xA0,
- 0x7F, 0x0C, 0xF6, 0x6F, 0x17, 0xC4, 0x49, 0xEC, 0xD8, 0x43, 0x1F, 0x2D, 0xA4, 0x76, 0x7B, 0xB7,
- 0xCC, 0xBB, 0x3E, 0x5A, 0xFB, 0x60, 0xB1, 0x86, 0x3B, 0x52, 0xA1, 0x6C, 0xAA, 0x55, 0x29, 0x9D,
- 0x97, 0xB2, 0x87, 0x90, 0x61, 0xBE, 0xDC, 0xFC, 0xBC, 0x95, 0xCF, 0xCD, 0x37, 0x3F, 0x5B, 0xD1,
- 0x53, 0x39, 0x84, 0x3C, 0x41, 0xA2, 0x6D, 0x47, 0x14, 0x2A, 0x9E, 0x5D, 0x56, 0xF2, 0xD3, 0xAB,
- 0x44, 0x11, 0x92, 0xD9, 0x23, 0x20, 0x2E, 0x89, 0xB4, 0x7C, 0xB8, 0x26, 0x77, 0x99, 0xE3, 0xA5,
- 0x67, 0x4A, 0xED, 0xDE, 0xC5, 0x31, 0xFE, 0x18, 0x0D, 0x63, 0x8C, 0x80, 0xC0, 0xF7, 0x70, 0x07};
-
-local MIXTABLE = {
- 0x02, 0x03, 0x01, 0x01,
- 0x01, 0x02, 0x03, 0x01,
- 0x01, 0x01, 0x02, 0x03,
- 0x03, 0x01, 0x01, 0x02};
-
-local IMIXTABLE = {
- 0x0E, 0x0B, 0x0D, 0x09,
- 0x09, 0x0E, 0x0B, 0x0D,
- 0x0D, 0x09, 0x0E, 0x0B,
- 0x0B, 0x0D, 0x09, 0x0E};
-
-local RCON = {
-[0] = 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
-0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
-0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
-0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
-0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
-0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
-0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
-0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
-0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
-0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
-0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
-0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
-0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
-0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
-0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
-0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d};
-
-
-local GMUL = function(A, B)
- if(A == 0x01) then return B; end
- if(B == 0x01) then return A; end
- if(A == 0x00) then return 0; end
- if(B == 0x00) then return 0; end
-
- local LA = LTABLE[A];
- local LB = LTABLE[B];
-
- local sum = LA + LB;
- if (sum > 0xFF) then sum = sum - 0xFF; end
-
- return ETABLE[sum];
-end
-
-local byteSub = Array.substitute;
-
-local shiftRow = Array.permute;
-
-local mixCol = function(i, mix)
- local out = {};
-
- local a, b, c, d;
-
- a = GMUL(i[ 1], mix[ 1]);
- b = GMUL(i[ 2], mix[ 2]);
- c = GMUL(i[ 3], mix[ 3]);
- d = GMUL(i[ 4], mix[ 4]);
- out[ 1] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 1], mix[ 5]);
- b = GMUL(i[ 2], mix[ 6]);
- c = GMUL(i[ 3], mix[ 7]);
- d = GMUL(i[ 4], mix[ 8]);
- out[ 2] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 1], mix[ 9]);
- b = GMUL(i[ 2], mix[10]);
- c = GMUL(i[ 3], mix[11]);
- d = GMUL(i[ 4], mix[12]);
- out[ 3] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 1], mix[13]);
- b = GMUL(i[ 2], mix[14]);
- c = GMUL(i[ 3], mix[15]);
- d = GMUL(i[ 4], mix[16]);
- out[ 4] = XOR(XOR(a, b), XOR(c, d));
-
-
- a = GMUL(i[ 5], mix[ 1]);
- b = GMUL(i[ 6], mix[ 2]);
- c = GMUL(i[ 7], mix[ 3]);
- d = GMUL(i[ 8], mix[ 4]);
- out[ 5] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 5], mix[ 5]);
- b = GMUL(i[ 6], mix[ 6]);
- c = GMUL(i[ 7], mix[ 7]);
- d = GMUL(i[ 8], mix[ 8]);
- out[ 6] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 5], mix[ 9]);
- b = GMUL(i[ 6], mix[10]);
- c = GMUL(i[ 7], mix[11]);
- d = GMUL(i[ 8], mix[12]);
- out[ 7] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 5], mix[13]);
- b = GMUL(i[ 6], mix[14]);
- c = GMUL(i[ 7], mix[15]);
- d = GMUL(i[ 8], mix[16]);
- out[ 8] = XOR(XOR(a, b), XOR(c, d));
-
-
- a = GMUL(i[ 9], mix[ 1]);
- b = GMUL(i[10], mix[ 2]);
- c = GMUL(i[11], mix[ 3]);
- d = GMUL(i[12], mix[ 4]);
- out[ 9] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 9], mix[ 5]);
- b = GMUL(i[10], mix[ 6]);
- c = GMUL(i[11], mix[ 7]);
- d = GMUL(i[12], mix[ 8]);
- out[10] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 9], mix[ 9]);
- b = GMUL(i[10], mix[10]);
- c = GMUL(i[11], mix[11]);
- d = GMUL(i[12], mix[12]);
- out[11] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[ 9], mix[13]);
- b = GMUL(i[10], mix[14]);
- c = GMUL(i[11], mix[15]);
- d = GMUL(i[12], mix[16]);
- out[12] = XOR(XOR(a, b), XOR(c, d));
-
-
- a = GMUL(i[13], mix[ 1]);
- b = GMUL(i[14], mix[ 2]);
- c = GMUL(i[15], mix[ 3]);
- d = GMUL(i[16], mix[ 4]);
- out[13] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[13], mix[ 5]);
- b = GMUL(i[14], mix[ 6]);
- c = GMUL(i[15], mix[ 7]);
- d = GMUL(i[16], mix[ 8]);
- out[14] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[13], mix[ 9]);
- b = GMUL(i[14], mix[10]);
- c = GMUL(i[15], mix[11]);
- d = GMUL(i[16], mix[12]);
- out[15] = XOR(XOR(a, b), XOR(c, d));
- a = GMUL(i[13], mix[13]);
- b = GMUL(i[14], mix[14]);
- c = GMUL(i[15], mix[15]);
- d = GMUL(i[16], mix[16]);
- out[16] = XOR(XOR(a, b), XOR(c, d));
-
- return out;
-end
-
-local keyRound = function(key, round)
- local i = (round - 1) * 32;
- local out = key;
-
- out[33 + i] = XOR(key[ 1 + i], XOR(SBOX[key[30 + i]], RCON[round]));
- out[34 + i] = XOR(key[ 2 + i], SBOX[key[31 + i]]);
- out[35 + i] = XOR(key[ 3 + i], SBOX[key[32 + i]]);
- out[36 + i] = XOR(key[ 4 + i], SBOX[key[29 + i]]);
-
- out[37 + i] = XOR(out[33 + i], key[ 5 + i]);
- out[38 + i] = XOR(out[34 + i], key[ 6 + i]);
- out[39 + i] = XOR(out[35 + i], key[ 7 + i]);
- out[40 + i] = XOR(out[36 + i], key[ 8 + i]);
-
- out[41 + i] = XOR(out[37 + i], key[ 9 + i]);
- out[42 + i] = XOR(out[38 + i], key[10 + i]);
- out[43 + i] = XOR(out[39 + i], key[11 + i]);
- out[44 + i] = XOR(out[40 + i], key[12 + i]);
-
- out[45 + i] = XOR(out[41 + i], key[13 + i]);
- out[46 + i] = XOR(out[42 + i], key[14 + i]);
- out[47 + i] = XOR(out[43 + i], key[15 + i]);
- out[48 + i] = XOR(out[44 + i], key[16 + i]);
-
-
- out[49 + i] = XOR(SBOX[out[45 + i]], key[17 + i]);
- out[50 + i] = XOR(SBOX[out[46 + i]], key[18 + i]);
- out[51 + i] = XOR(SBOX[out[47 + i]], key[19 + i]);
- out[52 + i] = XOR(SBOX[out[48 + i]], key[20 + i]);
-
- out[53 + i] = XOR(out[49 + i], key[21 + i]);
- out[54 + i] = XOR(out[50 + i], key[22 + i]);
- out[55 + i] = XOR(out[51 + i], key[23 + i]);
- out[56 + i] = XOR(out[52 + i], key[24 + i]);
-
- out[57 + i] = XOR(out[53 + i], key[25 + i]);
- out[58 + i] = XOR(out[54 + i], key[26 + i]);
- out[59 + i] = XOR(out[55 + i], key[27 + i]);
- out[60 + i] = XOR(out[56 + i], key[28 + i]);
-
- out[61 + i] = XOR(out[57 + i], key[29 + i]);
- out[62 + i] = XOR(out[58 + i], key[30 + i]);
- out[63 + i] = XOR(out[59 + i], key[31 + i]);
- out[64 + i] = XOR(out[60 + i], key[32 + i]);
-
- return out;
-end
-
-local keyExpand = function(key)
- local bytes = Array.copy(key);
-
- for i = 1, 7 do
- keyRound(bytes, i);
- end
-
- local keys = {};
-
- keys[ 1] = Array.slice(bytes, 1, 16);
- keys[ 2] = Array.slice(bytes, 17, 32);
- keys[ 3] = Array.slice(bytes, 33, 48);
- keys[ 4] = Array.slice(bytes, 49, 64);
- keys[ 5] = Array.slice(bytes, 65, 80);
- keys[ 6] = Array.slice(bytes, 81, 96);
- keys[ 7] = Array.slice(bytes, 97, 112);
- keys[ 8] = Array.slice(bytes, 113, 128);
- keys[ 9] = Array.slice(bytes, 129, 144);
- keys[10] = Array.slice(bytes, 145, 160);
- keys[11] = Array.slice(bytes, 161, 176);
- keys[12] = Array.slice(bytes, 177, 192);
- keys[13] = Array.slice(bytes, 193, 208);
- keys[14] = Array.slice(bytes, 209, 224);
- keys[15] = Array.slice(bytes, 225, 240);
-
- return keys;
-
-end
-
-local addKey = Array.XOR;
-
-
-
-local AES = {};
-
-AES.blockSize = 16;
-
-AES.encrypt = function(_key, block)
-
- local key = keyExpand(_key);
-
- --round 0
- block = addKey(block, key[1]);
-
- --round 1
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[2]);
-
- --round 2
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[3]);
-
- --round 3
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[4]);
-
- --round 4
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[5]);
-
- --round 5
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[6]);
-
- --round 6
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[7]);
-
- --round 7
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[8]);
-
- --round 8
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[9]);
-
- --round 9
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[10]);
-
- --round 10
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[11]);
-
- --round 11
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[12]);
-
- --round 12
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[13]);
-
- --round 13
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = mixCol(block, MIXTABLE);
- block = addKey(block, key[14]);
-
- --round 14
- block = byteSub(block, SBOX);
- block = shiftRow(block, ROW_SHIFT);
- block = addKey(block, key[15]);
-
- return block;
-
-end
-
-AES.decrypt = function(_key, block)
-
- local key = keyExpand(_key);
-
- --round 0
- block = addKey(block, key[15]);
-
- --round 1
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[14]);
- block = mixCol(block, IMIXTABLE);
-
- --round 2
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[13]);
- block = mixCol(block, IMIXTABLE);
-
- --round 3
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[12]);
- block = mixCol(block, IMIXTABLE);
-
- --round 4
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[11]);
- block = mixCol(block, IMIXTABLE);
-
- --round 5
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[10]);
- block = mixCol(block, IMIXTABLE);
-
- --round 6
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[9]);
- block = mixCol(block, IMIXTABLE);
-
- --round 7
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[8]);
- block = mixCol(block, IMIXTABLE);
-
- --round 8
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[7]);
- block = mixCol(block, IMIXTABLE);
-
- --round 9
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[6]);
- block = mixCol(block, IMIXTABLE);
-
- --round 10
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[5]);
- block = mixCol(block, IMIXTABLE);
-
- --round 11
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[4]);
- block = mixCol(block, IMIXTABLE);
-
- --round 12
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[3]);
- block = mixCol(block, IMIXTABLE);
-
- --round 13
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[2]);
- block = mixCol(block, IMIXTABLE);
-
- --round 14
- block = shiftRow(block, IROW_SHIFT);
- block = byteSub(block, ISBOX);
- block = addKey(block, key[1]);
-
- return block;
-end
-
-return AES;
diff --git a/lockbox/cipher/mode/cbc.lua b/lockbox/cipher/mode/cbc.lua
deleted file mode 100644
index a02ff2e..0000000
--- a/lockbox/cipher/mode/cbc.lua
+++ /dev/null
@@ -1,164 +0,0 @@
-local Array = require("lockbox.util.array");
-local Stream = require("lockbox.util.stream");
-local Queue = require("lockbox.util.queue");
-
-local CBC = {};
-
-CBC.Cipher = function()
-
- local public = {};
-
- local key;
- local blockCipher;
- local padding;
- local inputQueue;
- local outputQueue;
- local iv;
-
- public.setKey = function(keyBytes)
- key = keyBytes;
- return public;
- end
-
- public.setBlockCipher = function(cipher)
- blockCipher = cipher;
- return public;
- end
-
- public.setPadding = function(paddingMode)
- padding = paddingMode;
- return public;
- end
-
- public.init = function()
- inputQueue = Queue();
- outputQueue = Queue();
- iv = nil;
- return public;
- end
-
- public.update = function(messageStream)
- local byte = messageStream();
- while (byte ~= nil) do
- inputQueue.push(byte);
- if(inputQueue.size() >= blockCipher.blockSize) then
- local block = Array.readFromQueue(inputQueue, blockCipher.blockSize);
-
- if(iv == nil) then
- iv = block;
- else
- local out = Array.XOR(iv, block);
- out = blockCipher.encrypt(key, out);
- Array.writeToQueue(outputQueue, out);
- iv = out;
- end
- end
- byte = messageStream();
- end
- return public;
- end
-
- public.finish = function()
- local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead());
- public.update(paddingStream);
-
- return public;
- end
-
- public.getOutputQueue = function()
- return outputQueue;
- end
-
- public.asHex = function()
- return Stream.toHex(outputQueue.pop);
- end
-
- public.asBytes = function()
- return Stream.toArray(outputQueue.pop);
- end
-
- return public;
-
-end
-
-
-CBC.Decipher = function()
-
- local public = {};
-
- local key;
- local blockCipher;
- local padding;
- local inputQueue;
- local outputQueue;
- local iv;
-
- public.setKey = function(keyBytes)
- key = keyBytes;
- return public;
- end
-
- public.setBlockCipher = function(cipher)
- blockCipher = cipher;
- return public;
- end
-
- public.setPadding = function(paddingMode)
- padding = paddingMode;
- return public;
- end
-
- public.init = function()
- inputQueue = Queue();
- outputQueue = Queue();
- iv = nil;
- return public;
- end
-
- public.update = function(messageStream)
- local byte = messageStream();
- while (byte ~= nil) do
- inputQueue.push(byte);
- if(inputQueue.size() >= blockCipher.blockSize) then
- local block = Array.readFromQueue(inputQueue, blockCipher.blockSize);
-
- if(iv == nil) then
- iv = block;
- else
- local out = block;
- out = blockCipher.decrypt(key, out);
- out = Array.XOR(iv, out);
- Array.writeToQueue(outputQueue, out);
- iv = block;
- end
- end
- byte = messageStream();
- end
- return public;
- end
-
- public.finish = function()
- local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead());
- public.update(paddingStream);
-
- return public;
- end
-
- public.getOutputQueue = function()
- return outputQueue;
- end
-
- public.asHex = function()
- return Stream.toHex(outputQueue.pop);
- end
-
- public.asBytes = function()
- return Stream.toArray(outputQueue.pop);
- end
-
- return public;
-
-end
-
-return CBC;
-
diff --git a/lockbox/cipher/mode/cfb.lua b/lockbox/cipher/mode/cfb.lua
deleted file mode 100644
index c736d52..0000000
--- a/lockbox/cipher/mode/cfb.lua
+++ /dev/null
@@ -1,163 +0,0 @@
-local Array = require("lockbox.util.array");
-local Stream = require("lockbox.util.stream");
-local Queue = require("lockbox.util.queue");
-
-local CFB = {};
-
-CFB.Cipher = function()
-
- local public = {};
-
- local key;
- local blockCipher;
- local padding;
- local inputQueue;
- local outputQueue;
- local iv;
-
- public.setKey = function(keyBytes)
- key = keyBytes;
- return public;
- end
-
- public.setBlockCipher = function(cipher)
- blockCipher = cipher;
- return public;
- end
-
- public.setPadding = function(paddingMode)
- padding = paddingMode;
- return public;
- end
-
- public.init = function()
- inputQueue = Queue();
- outputQueue = Queue();
- iv = nil;
- return public;
- end
-
- public.update = function(messageStream)
- local byte = messageStream();
- while (byte ~= nil) do
- inputQueue.push(byte);
- if(inputQueue.size() >= blockCipher.blockSize) then
- local block = Array.readFromQueue(inputQueue, blockCipher.blockSize);
-
- if(iv == nil) then
- iv = block;
- else
- local out = iv;
- out = blockCipher.encrypt(key, out);
- out = Array.XOR(out, block);
- Array.writeToQueue(outputQueue, out);
- iv = out;
- end
- end
- byte = messageStream();
- end
- return public;
- end
-
- public.finish = function()
- local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead());
- public.update(paddingStream);
-
- return public;
- end
-
- public.getOutputQueue = function()
- return outputQueue;
- end
-
- public.asHex = function()
- return Stream.toHex(outputQueue.pop);
- end
-
- public.asBytes = function()
- return Stream.toArray(outputQueue.pop);
- end
-
- return public;
-
-end
-
-CFB.Decipher = function()
-
- local public = {};
-
- local key;
- local blockCipher;
- local padding;
- local inputQueue;
- local outputQueue;
- local iv;
-
- public.setKey = function(keyBytes)
- key = keyBytes;
- return public;
- end
-
- public.setBlockCipher = function(cipher)
- blockCipher = cipher;
- return public;
- end
-
- public.setPadding = function(paddingMode)
- padding = paddingMode;
- return public;
- end
-
- public.init = function()
- inputQueue = Queue();
- outputQueue = Queue();
- iv = nil;
- return public;
- end
-
- public.update = function(messageStream)
- local byte = messageStream();
- while (byte ~= nil) do
- inputQueue.push(byte);
- if(inputQueue.size() >= blockCipher.blockSize) then
- local block = Array.readFromQueue(inputQueue, blockCipher.blockSize);
-
- if(iv == nil) then
- iv = block;
- else
- local out = iv;
- out = blockCipher.encrypt(key, out);
- out = Array.XOR(out, block);
- Array.writeToQueue(outputQueue, out);
- iv = block;
- end
- end
- byte = messageStream();
- end
- return public;
- end
-
- public.finish = function()
- local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead());
- public.update(paddingStream);
-
- return public;
- end
-
- public.getOutputQueue = function()
- return outputQueue;
- end
-
- public.asHex = function()
- return Stream.toHex(outputQueue.pop);
- end
-
- public.asBytes = function()
- return Stream.toArray(outputQueue.pop);
- end
-
- return public;
-
-end
-
-return CFB;
diff --git a/lockbox/cipher/mode/ctr.lua b/lockbox/cipher/mode/ctr.lua
deleted file mode 100644
index beb8ef0..0000000
--- a/lockbox/cipher/mode/ctr.lua
+++ /dev/null
@@ -1,248 +0,0 @@
-local Array = require("lockbox.util.array");
-local Stream = require("lockbox.util.stream");
-local Queue = require("lockbox.util.queue");
-
-local Bit = require("lockbox.util.bit");
-
-local AND = Bit.band;
-
-local CTR = {};
-
-CTR.Cipher = function()
-
- local public = {};
-
- local key;
- local blockCipher;
- local padding;
- local inputQueue;
- local outputQueue;
- local iv;
-
- public.setKey = function(keyBytes)
- key = keyBytes;
- return public;
- end
-
- public.setBlockCipher = function(cipher)
- blockCipher = cipher;
- return public;
- end
-
- public.setPadding = function(paddingMode)
- padding = paddingMode;
- return public;
- end
-
- public.init = function()
- inputQueue = Queue();
- outputQueue = Queue();
- iv = nil;
- return public;
- end
-
- local updateIV = function()
- iv[16] = iv[16] + 1;
- if iv[16] <= 0xFF then return; end
- iv[16] = AND(iv[16], 0xFF);
-
- iv[15] = iv[15] + 1;
- if iv[15] <= 0xFF then return; end
- iv[15] = AND(iv[15], 0xFF);
-
- iv[14] = iv[14] + 1;
- if iv[14] <= 0xFF then return; end
- iv[14] = AND(iv[14], 0xFF);
-
- iv[13] = iv[13] + 1;
- if iv[13] <= 0xFF then return; end
- iv[13] = AND(iv[13], 0xFF);
-
- iv[12] = iv[12] + 1;
- if iv[12] <= 0xFF then return; end
- iv[12] = AND(iv[12], 0xFF);
-
- iv[11] = iv[11] + 1;
- if iv[11] <= 0xFF then return; end
- iv[11] = AND(iv[11], 0xFF);
-
- iv[10] = iv[10] + 1;
- if iv[10] <= 0xFF then return; end
- iv[10] = AND(iv[10], 0xFF);
-
- iv[9] = iv[9] + 1;
- if iv[9] <= 0xFF then return; end
- iv[9] = AND(iv[9], 0xFF);
-
- return;
- end
-
- public.update = function(messageStream)
- local byte = messageStream();
- while (byte ~= nil) do
- inputQueue.push(byte);
-
- if(inputQueue.size() >= blockCipher.blockSize) then
- local block = Array.readFromQueue(inputQueue, blockCipher.blockSize);
-
- if(iv == nil) then
- iv = block;
- else
- local out = iv;
- out = blockCipher.encrypt(key, out);
-
- out = Array.XOR(out, block);
- Array.writeToQueue(outputQueue, out);
- updateIV();
- end
- end
- byte = messageStream();
- end
- return public;
- end
-
- public.finish = function()
- local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead());
- public.update(paddingStream);
-
- return public;
- end
-
- public.getOutputQueue = function()
- return outputQueue;
- end
-
- public.asHex = function()
- return Stream.toHex(outputQueue.pop);
- end
-
- public.asBytes = function()
- return Stream.toArray(outputQueue.pop);
- end
-
- return public;
-
-end
-
-
-CTR.Decipher = function()
-
- local public = {};
-
- local key;
- local blockCipher;
- local padding;
- local inputQueue;
- local outputQueue;
- local iv;
-
- public.setKey = function(keyBytes)
- key = keyBytes;
- return public;
- end
-
- public.setBlockCipher = function(cipher)
- blockCipher = cipher;
- return public;
- end
-
- public.setPadding = function(paddingMode)
- padding = paddingMode;
- return public;
- end
-
- public.init = function()
- inputQueue = Queue();
- outputQueue = Queue();
- iv = nil;
- return public;
- end
-
- local updateIV = function()
- iv[16] = iv[16] + 1;
- if iv[16] <= 0xFF then return; end
- iv[16] = AND(iv[16], 0xFF);
-
- iv[15] = iv[15] + 1;
- if iv[15] <= 0xFF then return; end
- iv[15] = AND(iv[15], 0xFF);
-
- iv[14] = iv[14] + 1;
- if iv[14] <= 0xFF then return; end
- iv[14] = AND(iv[14], 0xFF);
-
- iv[13] = iv[13] + 1;
- if iv[13] <= 0xFF then return; end
- iv[13] = AND(iv[13], 0xFF);
-
- iv[12] = iv[12] + 1;
- if iv[12] <= 0xFF then return; end
- iv[12] = AND(iv[12], 0xFF);
-
- iv[11] = iv[11] + 1;
- if iv[11] <= 0xFF then return; end
- iv[11] = AND(iv[11], 0xFF);
-
- iv[10] = iv[10] + 1;
- if iv[10] <= 0xFF then return; end
- iv[10] = AND(iv[10], 0xFF);
-
- iv[9] = iv[9] + 1;
- if iv[9] <= 0xFF then return; end
- iv[9] = AND(iv[9], 0xFF);
-
- return;
- end
-
- public.update = function(messageStream)
- local byte = messageStream();
- while (byte ~= nil) do
- inputQueue.push(byte);
-
- if(inputQueue.size() >= blockCipher.blockSize) then
- local block = Array.readFromQueue(inputQueue, blockCipher.blockSize);
-
- if(iv == nil) then
- iv = block;
- else
- local out = iv;
- out = blockCipher.encrypt(key, out);
-
- out = Array.XOR(out, block);
- Array.writeToQueue(outputQueue, out);
- updateIV();
- end
- end
- byte = messageStream();
- end
- return public;
- end
-
- public.finish = function()
- local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead());
- public.update(paddingStream);
-
- return public;
- end
-
- public.getOutputQueue = function()
- return outputQueue;
- end
-
- public.asHex = function()
- return Stream.toHex(outputQueue.pop);
- end
-
- public.asBytes = function()
- return Stream.toArray(outputQueue.pop);
- end
-
- return public;
-
-end
-
-
-
-
-return CTR;
-
diff --git a/lockbox/cipher/mode/ofb.lua b/lockbox/cipher/mode/ofb.lua
deleted file mode 100644
index a824846..0000000
--- a/lockbox/cipher/mode/ofb.lua
+++ /dev/null
@@ -1,164 +0,0 @@
-local Array = require("lockbox.util.array");
-local Stream = require("lockbox.util.stream");
-local Queue = require("lockbox.util.queue");
-
-local OFB = {};
-
-OFB.Cipher = function()
-
- local public = {};
-
- local key;
- local blockCipher;
- local padding;
- local inputQueue;
- local outputQueue;
- local iv;
-
- public.setKey = function(keyBytes)
- key = keyBytes;
- return public;
- end
-
- public.setBlockCipher = function(cipher)
- blockCipher = cipher;
- return public;
- end
-
- public.setPadding = function(paddingMode)
- padding = paddingMode;
- return public;
- end
-
- public.init = function()
- inputQueue = Queue();
- outputQueue = Queue();
- iv = nil;
- return public;
- end
-
- public.update = function(messageStream)
- local byte = messageStream();
- while (byte ~= nil) do
- inputQueue.push(byte);
- if(inputQueue.size() >= blockCipher.blockSize) then
- local block = Array.readFromQueue(inputQueue, blockCipher.blockSize);
-
- if(iv == nil) then
- iv = block;
- else
- local out = iv;
- out = blockCipher.encrypt(key, out);
- iv = out;
- out = Array.XOR(out, block);
- Array.writeToQueue(outputQueue, out);
- end
- end
- byte = messageStream();
- end
- return public;
- end
-
- public.finish = function()
- local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead());
- public.update(paddingStream);
-
- return public;
- end
-
- public.getOutputQueue = function()
- return outputQueue;
- end
-
- public.asHex = function()
- return Stream.toHex(outputQueue.pop);
- end
-
- public.asBytes = function()
- return Stream.toArray(outputQueue.pop);
- end
-
- return public;
-
-end
-
-OFB.Decipher = function()
-
- local public = {};
-
- local key;
- local blockCipher;
- local padding;
- local inputQueue;
- local outputQueue;
- local iv;
-
- public.setKey = function(keyBytes)
- key = keyBytes;
- return public;
- end
-
- public.setBlockCipher = function(cipher)
- blockCipher = cipher;
- return public;
- end
-
- public.setPadding = function(paddingMode)
- padding = paddingMode;
- return public;
- end
-
- public.init = function()
- inputQueue = Queue();
- outputQueue = Queue();
- iv = nil;
- return public;
- end
-
- public.update = function(messageStream)
- local byte = messageStream();
- while (byte ~= nil) do
- inputQueue.push(byte);
- if(inputQueue.size() >= blockCipher.blockSize) then
- local block = Array.readFromQueue(inputQueue, blockCipher.blockSize);
-
- if(iv == nil) then
- iv = block;
- else
- local out = iv;
- out = blockCipher.encrypt(key, out);
- iv = out;
- out = Array.XOR(out, block);
- Array.writeToQueue(outputQueue, out);
- end
- end
- byte = messageStream();
- end
- return public;
- end
-
- public.finish = function()
- local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead());
- public.update(paddingStream);
-
- return public;
- end
-
- public.getOutputQueue = function()
- return outputQueue;
- end
-
- public.asHex = function()
- return Stream.toHex(outputQueue.pop);
- end
-
- public.asBytes = function()
- return Stream.toArray(outputQueue.pop);
- end
-
- return public;
-
-end
-
-
-return OFB;
diff --git a/lockbox/digest/md5.lua b/lockbox/digest/md5.lua
new file mode 100644
index 0000000..6ce1df2
--- /dev/null
+++ b/lockbox/digest/md5.lua
@@ -0,0 +1,201 @@
+require("lockbox").insecure();
+
+local Bit = require("lockbox.util.bit");
+local String = require("string");
+local Math = require("math");
+local Queue = require("lockbox.util.queue");
+
+local SHIFT = {
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+ 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
+ 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+ 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
+
+local CONSTANTS = {
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
+
+local AND = Bit.band;
+local OR = Bit.bor;
+local NOT = Bit.bnot;
+local XOR = Bit.bxor;
+local LROT = Bit.lrotate;
+local LSHIFT = Bit.lshift;
+local RSHIFT = Bit.rshift;
+
+--MD5 is little-endian
+local bytes2word = function(b0, b1, b2, b3)
+ local i = b3; i = LSHIFT(i, 8);
+ i = OR(i, b2); i = LSHIFT(i, 8);
+ i = OR(i, b1); i = LSHIFT(i, 8);
+ i = OR(i, b0);
+ return i;
+end
+
+local word2bytes = function(word)
+ local b0, b1, b2, b3;
+ b0 = AND(word, 0xFF); word = RSHIFT(word, 8);
+ b1 = AND(word, 0xFF); word = RSHIFT(word, 8);
+ b2 = AND(word, 0xFF); word = RSHIFT(word, 8);
+ b3 = AND(word, 0xFF);
+ return b0, b1, b2, b3;
+end
+
+local dword2bytes = function(i)
+ local b4, b5, b6, b7 = word2bytes(Math.floor(i / 0x100000000));
+ local b0, b1, b2, b3 = word2bytes(i);
+ return b0, b1, b2, b3, b4, b5, b6, b7;
+end
+
+local F = function(x, y, z) return OR(AND(x, y), AND(NOT(x), z)); end
+local G = function(x, y, z) return OR(AND(x, z), AND(y, NOT(z))); end
+local H = function(x, y, z) return XOR(x, XOR(y, z)); end
+local I = function(x, y, z) return XOR(y, OR(x, NOT(z))); end
+
+local MD5 = function()
+
+ local queue = Queue();
+
+ local A = 0x67452301;
+ local B = 0xefcdab89;
+ local C = 0x98badcfe;
+ local D = 0x10325476;
+ local public = {};
+
+ local processBlock = function()
+ local a = A;
+ local b = B;
+ local c = C;
+ local d = D;
+
+ local X = {};
+
+ for i = 1, 16 do
+ X[i] = bytes2word(queue.pop(), queue.pop(), queue.pop(), queue.pop());
+ end
+
+ for i = 0, 63 do
+ local f, g, temp;
+
+ if (0 <= i) and (i <= 15) then
+ f = F(b, c, d);
+ g = i;
+ elseif (16 <= i) and (i <= 31) then
+ f = G(b, c, d);
+ g = (5 * i + 1) % 16;
+ elseif (32 <= i) and (i <= 47) then
+ f = H(b, c, d);
+ g = (3 * i + 5) % 16;
+ elseif (48 <= i) and (i <= 63) then
+ f = I(b, c, d);
+ g = (7 * i) % 16;
+ end
+ temp = d;
+ d = c;
+ c = b;
+ b = b + LROT((a + f + CONSTANTS[i + 1] + X[g + 1]), SHIFT[i + 1]);
+ a = temp;
+ end
+
+ A = AND(A + a, 0xFFFFFFFF);
+ B = AND(B + b, 0xFFFFFFFF);
+ C = AND(C + c, 0xFFFFFFFF);
+ D = AND(D + d, 0xFFFFFFFF);
+ end
+
+ public.init = function()
+ queue.reset();
+
+ A = 0x67452301;
+ B = 0xefcdab89;
+ C = 0x98badcfe;
+ D = 0x10325476;
+
+ return public;
+ end
+
+ public.update = function(bytes)
+ for b in bytes do
+ queue.push(b);
+ if(queue.size() >= 64) then processBlock(); end
+ end
+
+ return public;
+ end
+
+ public.finish = function()
+ local bits = queue.getHead() * 8;
+
+ queue.push(0x80);
+ while ((queue.size() + 7) % 64) < 63 do
+ queue.push(0x00);
+ end
+
+ local b0, b1, b2, b3, b4, b5, b6, b7 = dword2bytes(bits);
+
+ queue.push(b0);
+ queue.push(b1);
+ queue.push(b2);
+ queue.push(b3);
+ queue.push(b4);
+ queue.push(b5);
+ queue.push(b6);
+ queue.push(b7);
+
+ while queue.size() > 0 do
+ processBlock();
+ end
+
+ return public;
+ end
+
+ public.asBytes = function()
+ local b0, b1, b2, b3 = word2bytes(A);
+ local b4, b5, b6, b7 = word2bytes(B);
+ local b8, b9, b10, b11 = word2bytes(C);
+ local b12, b13, b14, b15 = word2bytes(D);
+
+ return {b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15};
+ end
+
+ public.asHex = function()
+ local b0, b1, b2, b3 = word2bytes(A);
+ local b4, b5, b6, b7 = word2bytes(B);
+ local b8, b9, b10, b11 = word2bytes(C);
+ local b12, b13, b14, b15 = word2bytes(D);
+
+ return String.format("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15);
+ end
+
+ public.asString = function()
+ local b0, b1, b2, b3 = word2bytes(A);
+ local b4, b5, b6, b7 = word2bytes(B);
+ local b8, b9, b10, b11 = word2bytes(C);
+ local b12, b13, b14, b15 = word2bytes(D);
+
+ return string.pack(string.rep('B', 16),
+ b0, b1, b2, b3, b4, b5, b6, b7, b8,
+ b9, b10, b11, b12, b13, b14, b15
+ )
+ end
+
+ return public;
+
+end
+
+return MD5;
diff --git a/lockbox/init.lua b/lockbox/init.lua
index 0031a50..caee6c0 100644
--- a/lockbox/init.lua
+++ b/lockbox/init.lua
@@ -1,5 +1,8 @@
local Lockbox = {};
+-- cc-mek-scada lockbox version
+Lockbox.version = "1.0"
+
--[[
package.path = "./?.lua;"
.. "./cipher/?.lua;"
diff --git a/lockbox/padding/ansix923.lua b/lockbox/padding/ansix923.lua
deleted file mode 100644
index 83702c6..0000000
--- a/lockbox/padding/ansix923.lua
+++ /dev/null
@@ -1,22 +0,0 @@
-local ANSIX923Padding = function(blockSize, byteCount)
-
- local paddingCount = blockSize - (byteCount % blockSize);
- local bytesLeft = paddingCount;
-
- local stream = function()
- if bytesLeft > 1 then
- bytesLeft = bytesLeft - 1;
- return 0x00;
- elseif bytesLeft > 0 then
- bytesLeft = bytesLeft - 1;
- return paddingCount;
- else
- return nil;
- end
- end
-
- return stream;
-
-end
-
-return ANSIX923Padding;
diff --git a/lockbox/padding/isoiec7816.lua b/lockbox/padding/isoiec7816.lua
deleted file mode 100644
index 3dc255d..0000000
--- a/lockbox/padding/isoiec7816.lua
+++ /dev/null
@@ -1,22 +0,0 @@
-local ISOIEC7816Padding = function(blockSize, byteCount)
-
- local paddingCount = blockSize - (byteCount % blockSize);
- local bytesLeft = paddingCount;
-
- local stream = function()
- if bytesLeft == paddingCount then
- bytesLeft = bytesLeft - 1;
- return 0x80;
- elseif bytesLeft > 0 then
- bytesLeft = bytesLeft - 1;
- return 0x00;
- else
- return nil;
- end
- end
-
- return stream;
-
-end
-
-return ISOIEC7816Padding;
diff --git a/lockbox/padding/pkcs7.lua b/lockbox/padding/pkcs7.lua
deleted file mode 100644
index 3b635ab..0000000
--- a/lockbox/padding/pkcs7.lua
+++ /dev/null
@@ -1,18 +0,0 @@
-local PKCS7Padding = function(blockSize, byteCount)
-
- local paddingCount = blockSize - ((byteCount -1) % blockSize) + 1;
- local bytesLeft = paddingCount;
-
- local stream = function()
- if bytesLeft > 0 then
- bytesLeft = bytesLeft - 1;
- return paddingCount;
- else
- return nil;
- end
- end
-
- return stream;
-end
-
-return PKCS7Padding;
diff --git a/lockbox/padding/zero.lua b/lockbox/padding/zero.lua
deleted file mode 100644
index d42a9b7..0000000
--- a/lockbox/padding/zero.lua
+++ /dev/null
@@ -1,19 +0,0 @@
-local ZeroPadding = function(blockSize, byteCount)
-
- local paddingCount = blockSize - ((byteCount -1) % blockSize) + 1;
- local bytesLeft = paddingCount;
-
- local stream = function()
- if bytesLeft > 0 then
- bytesLeft = bytesLeft - 1;
- return 0x00;
- else
- return nil;
- end
- end
-
- return stream;
-
-end
-
-return ZeroPadding;
diff --git a/lockbox/util/bit.lua b/lockbox/util/bit.lua
index b17238e..1de5f8b 100644
--- a/lockbox/util/bit.lua
+++ b/lockbox/util/bit.lua
@@ -1,25 +1,19 @@
-local ok, e
-ok = nil
-if not ok then
- ok, e = pcall(require, "bit") -- the LuaJIT one ?
-end
+-- modified (simplified) for ComputerCraft
+
+local ok, e = nil, nil
+
if not ok then
ok, e = pcall(require, "bit32") -- Lua 5.2
end
+
if not ok then
- ok, e = pcall(require, "bit.numberlua") -- for Lua 5.1, https://github.com/tst2005/lua-bit-numberlua/
+ ok, e = pcall(require, "bit")
end
+
if not ok then
error("no bitwise support found", 2)
end
+
assert(type(e) == "table", "invalid bit module")
--- Workaround to support Lua 5.2 bit32 API with the LuaJIT bit one
-if e.rol and not e.lrotate then
- e.lrotate = e.rol
-end
-if e.ror and not e.rrotate then
- e.rrotate = e.ror
-end
-
return e
diff --git a/pocket/config.lua b/pocket/config.lua
index 0c35b59..72625f4 100644
--- a/pocket/config.lua
+++ b/pocket/config.lua
@@ -10,6 +10,10 @@ config.PKT_CHANNEL = 16244
config.TRUSTED_RANGE = 0
-- time in seconds (>= 2) before assuming a remote device is no longer active
config.COMMS_TIMEOUT = 5
+-- facility authentication key (do NOT use one of your passwords)
+-- this enables verifying that messages are authentic
+-- all devices on the same network must use the same key
+-- config.AUTH_KEY = "SCADAfacility123"
-- log path
config.LOG_PATH = "/log.txt"
diff --git a/pocket/pocket.lua b/pocket/pocket.lua
index 0281e92..b0432cf 100644
--- a/pocket/pocket.lua
+++ b/pocket/pocket.lua
@@ -17,14 +17,14 @@ local pocket = {}
-- pocket coordinator + supervisor communications
---@nodiscard
---@param version string pocket version
----@param modem table modem device
+---@param nic nic network interface device
---@param pkt_channel integer pocket comms channel
---@param svr_channel integer supervisor access channel
---@param crd_channel integer coordinator access channel
---@param range integer trusted device connection range
---@param sv_watchdog watchdog
---@param api_watchdog watchdog
-function pocket.comms(version, modem, pkt_channel, svr_channel, crd_channel, range, sv_watchdog, api_watchdog)
+function pocket.comms(version, nic, pkt_channel, svr_channel, crd_channel, range, sv_watchdog, api_watchdog)
local self = {
sv = {
linked = false,
@@ -47,13 +47,9 @@ function pocket.comms(version, modem, pkt_channel, svr_channel, crd_channel, ran
-- PRIVATE FUNCTIONS --
- -- configure modem channels
- local function _conf_channels()
- modem.closeAll()
- modem.open(pkt_channel)
- end
-
- _conf_channels()
+ -- configure network channels
+ nic.closeAll()
+ nic.open(pkt_channel)
-- send a management packet to the supervisor
---@param msg_type SCADA_MGMT_TYPE
@@ -65,7 +61,7 @@ function pocket.comms(version, modem, pkt_channel, svr_channel, crd_channel, ran
pkt.make(msg_type, msg)
s_pkt.make(self.sv.addr, self.sv.seq_num, PROTOCOL.SCADA_MGMT, pkt.raw_sendable())
- modem.transmit(svr_channel, pkt_channel, s_pkt.raw_sendable())
+ nic.transmit(svr_channel, pkt_channel, s_pkt)
self.sv.seq_num = self.sv.seq_num + 1
end
@@ -79,7 +75,7 @@ function pocket.comms(version, modem, pkt_channel, svr_channel, crd_channel, ran
pkt.make(msg_type, msg)
s_pkt.make(self.api.addr, self.api.seq_num, PROTOCOL.SCADA_MGMT, pkt.raw_sendable())
- modem.transmit(crd_channel, pkt_channel, s_pkt.raw_sendable())
+ nic.transmit(crd_channel, pkt_channel, s_pkt)
self.api.seq_num = self.api.seq_num + 1
end
@@ -93,7 +89,7 @@ function pocket.comms(version, modem, pkt_channel, svr_channel, crd_channel, ran
-- pkt.make(msg_type, msg)
-- s_pkt.make(self.api.addr, self.api.seq_num, PROTOCOL.COORD_API, pkt.raw_sendable())
- -- modem.transmit(crd_channel, pkt_channel, s_pkt.raw_sendable())
+ -- nic.transmit(crd_channel, pkt_channel, s_pkt)
-- self.api.seq_num = self.api.seq_num + 1
-- end
@@ -124,13 +120,6 @@ function pocket.comms(version, modem, pkt_channel, svr_channel, crd_channel, ran
---@class pocket_comms
local public = {}
- -- reconnect a newly connected modem
- ---@param new_modem table
- function public.reconnect_modem(new_modem)
- modem = new_modem
- _conf_channels()
- end
-
-- close connection to the supervisor
function public.close_sv()
sv_watchdog.cancel()
@@ -189,13 +178,10 @@ function pocket.comms(version, modem, pkt_channel, svr_channel, crd_channel, ran
---@param distance integer
---@return mgmt_frame|capi_frame|nil packet
function public.parse_packet(side, sender, reply_to, message, distance)
+ local s_pkt = nic.receive(side, sender, reply_to, message, distance)
local pkt = nil
- local s_pkt = comms.scada_packet()
- -- parse packet as generic SCADA packet
- s_pkt.receive(side, sender, reply_to, message, distance)
-
- if s_pkt.is_valid() then
+ if s_pkt then
-- get as SCADA management packet
if s_pkt.protocol() == PROTOCOL.SCADA_MGMT then
local mgmt_pkt = comms.mgmt_packet()
diff --git a/pocket/startup.lua b/pocket/startup.lua
index 3352605..843686e 100644
--- a/pocket/startup.lua
+++ b/pocket/startup.lua
@@ -6,6 +6,7 @@ require("/initenv").init_env()
local crash = require("scada-common.crash")
local log = require("scada-common.log")
+local network = require("scada-common.network")
local ppm = require("scada-common.ppm")
local tcd = require("scada-common.tcd")
local util = require("scada-common.util")
@@ -17,7 +18,7 @@ local coreio = require("pocket.coreio")
local pocket = require("pocket.pocket")
local renderer = require("pocket.renderer")
-local POCKET_VERSION = "alpha-v0.4.6"
+local POCKET_VERSION = "alpha-v0.5.1"
local println = util.println
local println_ts = util.println_ts
@@ -67,6 +68,11 @@ local function main()
-- setup communications & clocks
----------------------------------------
+ -- message authentication init
+ if type(config.AUTH_KEY) == "string" then
+ network.init_mac(config.AUTH_KEY)
+ end
+
coreio.report_link_state(coreio.LINK_STATE.UNLINKED)
-- get the communications modem
@@ -88,8 +94,9 @@ local function main()
log.debug("startup> conn watchdogs created")
- -- start comms, open all channels
- local pocket_comms = pocket.comms(POCKET_VERSION, modem, config.PKT_CHANNEL, config.SVR_CHANNEL,
+ -- create network interface then setup comms
+ local nic = network.nic(modem)
+ local pocket_comms = pocket.comms(POCKET_VERSION, nic, config.PKT_CHANNEL, config.SVR_CHANNEL,
config.CRD_CHANNEL, config.TRUSTED_RANGE, conn_wd.sv, conn_wd.api)
log.debug("startup> comms init")
diff --git a/reactor-plc/config.lua b/reactor-plc/config.lua
index 3462b2c..066ccf6 100644
--- a/reactor-plc/config.lua
+++ b/reactor-plc/config.lua
@@ -17,6 +17,10 @@ config.PLC_CHANNEL = 16241
config.TRUSTED_RANGE = 0
-- time in seconds (>= 2) before assuming a remote device is no longer active
config.COMMS_TIMEOUT = 5
+-- facility authentication key (do NOT use one of your passwords)
+-- this enables verifying that messages are authentic
+-- all devices on the same network must use the same key
+-- config.AUTH_KEY = "SCADAfacility123"
-- log path
config.LOG_PATH = "/log.txt"
diff --git a/reactor-plc/plc.lua b/reactor-plc/plc.lua
index fc41f80..2bba4ee 100644
--- a/reactor-plc/plc.lua
+++ b/reactor-plc/plc.lua
@@ -445,14 +445,14 @@ end
---@nodiscard
---@param id integer reactor ID
---@param version string PLC version
----@param modem table modem device
+---@param nic nic network interface device
---@param plc_channel integer PLC comms channel
---@param svr_channel integer supervisor server channel
---@param range integer trusted device connection range
---@param reactor table reactor device
---@param rps rps RPS reference
---@param conn_watchdog watchdog watchdog reference
-function plc.comms(id, version, modem, plc_channel, svr_channel, range, reactor, rps, conn_watchdog)
+function plc.comms(id, version, nic, plc_channel, svr_channel, range, reactor, rps, conn_watchdog)
local self = {
sv_addr = comms.BROADCAST,
seq_num = 0,
@@ -470,13 +470,9 @@ function plc.comms(id, version, modem, plc_channel, svr_channel, range, reactor,
-- PRIVATE FUNCTIONS --
- -- configure modem channels
- local function _conf_channels()
- modem.closeAll()
- modem.open(plc_channel)
- end
-
- _conf_channels()
+ -- configure network channels
+ nic.closeAll()
+ nic.open(plc_channel)
-- send an RPLC packet
---@param msg_type RPLC_TYPE
@@ -488,7 +484,7 @@ function plc.comms(id, version, modem, plc_channel, svr_channel, range, reactor,
r_pkt.make(id, msg_type, msg)
s_pkt.make(self.sv_addr, self.seq_num, PROTOCOL.RPLC, r_pkt.raw_sendable())
- modem.transmit(svr_channel, plc_channel, s_pkt.raw_sendable())
+ nic.transmit(svr_channel, plc_channel, s_pkt)
self.seq_num = self.seq_num + 1
end
@@ -502,7 +498,7 @@ function plc.comms(id, version, modem, plc_channel, svr_channel, range, reactor,
m_pkt.make(msg_type, msg)
s_pkt.make(self.sv_addr, self.seq_num, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
- modem.transmit(svr_channel, plc_channel, s_pkt.raw_sendable())
+ nic.transmit(svr_channel, plc_channel, s_pkt)
self.seq_num = self.seq_num + 1
end
@@ -650,13 +646,6 @@ function plc.comms(id, version, modem, plc_channel, svr_channel, range, reactor,
---@class plc_comms
local public = {}
- -- reconnect a newly connected modem
- ---@param new_modem table
- function public.reconnect_modem(new_modem)
- modem = new_modem
- _conf_channels()
- end
-
-- reconnect a newly connected reactor
---@param new_reactor table
function public.reconnect_reactor(new_reactor)
@@ -743,13 +732,10 @@ function plc.comms(id, version, modem, plc_channel, svr_channel, range, reactor,
---@param distance integer
---@return rplc_frame|mgmt_frame|nil packet
function public.parse_packet(side, sender, reply_to, message, distance)
+ local s_pkt = nic.receive(side, sender, reply_to, message, distance)
local pkt = nil
- local s_pkt = comms.scada_packet()
- -- parse packet as generic SCADA packet
- s_pkt.receive(side, sender, reply_to, message, distance)
-
- if s_pkt.is_valid() then
+ if s_pkt then
-- get as RPLC packet
if s_pkt.protocol() == PROTOCOL.RPLC then
local rplc_pkt = comms.rplc_packet()
diff --git a/reactor-plc/startup.lua b/reactor-plc/startup.lua
index a6a47a6..132c7aa 100644
--- a/reactor-plc/startup.lua
+++ b/reactor-plc/startup.lua
@@ -8,6 +8,7 @@ local comms = require("scada-common.comms")
local crash = require("scada-common.crash")
local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue")
+local network = require("scada-common.network")
local ppm = require("scada-common.ppm")
local rsio = require("scada-common.rsio")
local util = require("scada-common.util")
@@ -18,7 +19,7 @@ local plc = require("reactor-plc.plc")
local renderer = require("reactor-plc.renderer")
local threads = require("reactor-plc.threads")
-local R_PLC_VERSION = "v1.4.7"
+local R_PLC_VERSION = "v1.5.0"
local println = util.println
local println_ts = util.println_ts
@@ -79,6 +80,11 @@ local function main()
-- mount connected devices
ppm.mount_all()
+ -- message authentication init
+ if type(config.AUTH_KEY) == "string" then
+ network.init_mac(config.AUTH_KEY)
+ end
+
-- shared memory across threads
---@class plc_shared_memory
local __shared_memory = {
@@ -88,13 +94,13 @@ local function main()
-- PLC system state flags
---@class plc_state
plc_state = {
- init_ok = true,
- fp_ok = false,
- shutdown = false,
- degraded = false,
+ init_ok = true,
+ fp_ok = false,
+ shutdown = false,
+ degraded = true,
reactor_formed = true,
- no_reactor = false,
- no_modem = false
+ no_reactor = true,
+ no_modem = true
},
-- control setpoints
@@ -113,6 +119,7 @@ local function main()
-- system objects
plc_sys = {
rps = nil, ---@type rps
+ nic = nil, ---@type nic
plc_comms = nil, ---@type plc_comms
conn_watchdog = nil ---@type watchdog
},
@@ -130,14 +137,17 @@ local function main()
local plc_state = __shared_memory.plc_state
+ -- initial state evaluation
+ plc_state.no_reactor = smem_dev.reactor == nil
+ plc_state.no_modem = smem_dev.modem == nil
+
-- we need a reactor, can at least do some things even if it isn't formed though
- if smem_dev.reactor == nil then
+ if plc_state.no_reactor then
println("init> fission reactor not found");
log.warning("init> no reactor on startup")
plc_state.init_ok = false
plc_state.degraded = true
- plc_state.no_reactor = true
elseif not smem_dev.reactor.isFormed() then
println("init> fission reactor not formed");
log.warning("init> reactor logic adapter present, but reactor is not formed")
@@ -147,7 +157,7 @@ local function main()
end
-- modem is required if networked
- if __shared_memory.networked and smem_dev.modem == nil then
+ if __shared_memory.networked and plc_state.no_modem then
println("init> wireless modem not found")
log.warning("init> no wireless modem on startup")
@@ -158,7 +168,6 @@ local function main()
plc_state.init_ok = false
plc_state.degraded = true
- plc_state.no_modem = true
end
-- print a log message to the terminal as long as the UI isn't running
@@ -196,8 +205,9 @@ local function main()
smem_sys.conn_watchdog = util.new_watchdog(config.COMMS_TIMEOUT)
log.debug("init> conn watchdog started")
- -- start comms
- smem_sys.plc_comms = plc.comms(config.REACTOR_ID, R_PLC_VERSION, smem_dev.modem, config.PLC_CHANNEL, config.SVR_CHANNEL,
+ -- create network interface then setup comms
+ smem_sys.nic = network.nic(smem_dev.modem)
+ smem_sys.plc_comms = plc.comms(config.REACTOR_ID, R_PLC_VERSION, smem_sys.nic, config.PLC_CHANNEL, config.SVR_CHANNEL,
config.TRUSTED_RANGE, smem_dev.reactor, smem_sys.rps, smem_sys.conn_watchdog)
log.debug("init> comms init")
else
diff --git a/reactor-plc/threads.lua b/reactor-plc/threads.lua
index b9c986d..cf18963 100644
--- a/reactor-plc/threads.lua
+++ b/reactor-plc/threads.lua
@@ -59,6 +59,7 @@ function threads.thread__main(smem, init)
while true do
-- get plc_sys fields (may have been set late due to degraded boot)
local rps = smem.plc_sys.rps
+ local nic = smem.plc_sys.nic
local plc_comms = smem.plc_sys.plc_comms
local conn_watchdog = smem.plc_sys.conn_watchdog
@@ -66,6 +67,7 @@ function threads.thread__main(smem, init)
-- handle event
if event == "timer" and loop_clock.is_clock(param1) then
+ -- note: loop clock is only running if init_ok = true
-- blink heartbeat indicator
databus.heartbeat()
@@ -75,7 +77,7 @@ function threads.thread__main(smem, init)
loop_clock.start()
-- send updated data
- if not plc_state.no_modem then
+ if nic.connected() then
if plc_comms.is_linked() then
smem.q.mq_comms_tx.push_command(MQ__COMM_CMD.SEND_STATUS)
else
@@ -114,7 +116,7 @@ function threads.thread__main(smem, init)
smem.q.mq_rps.push_command(MQ__RPS_CMD.SCRAM)
-- determine if we are still in a degraded state
- if not networked or not plc_state.no_modem then
+ if (not networked) or nic.connected() then
plc_state.degraded = false
end
@@ -144,7 +146,7 @@ function threads.thread__main(smem, init)
-- update indicators
databus.tx_hw_status(plc_state)
- elseif event == "modem_message" and networked and plc_state.init_ok and not plc_state.no_modem then
+ elseif event == "modem_message" and networked and plc_state.init_ok and nic.connected() then
-- got a packet
local packet = plc_comms.parse_packet(param1, param2, param3, param4, param5)
if packet ~= nil then
@@ -171,7 +173,9 @@ function threads.thread__main(smem, init)
plc_state.degraded = true
elseif networked and type == "modem" then
-- we only care if this is our wireless modem
- if device == plc_dev.modem then
+ if nic.is_modem(device) then
+ nic.disconnect()
+
println_ts("comms modem disconnected!")
log.error("comms modem disconnected")
@@ -199,12 +203,11 @@ function threads.thread__main(smem, init)
if type == "fissionReactorLogicAdapter" then
-- reconnected reactor
plc_dev.reactor = device
+ plc_state.no_reactor = false
println_ts("reactor reconnected.")
log.info("reactor reconnected")
- plc_state.no_reactor = false
-
-- we need to assume formed here as we cannot check in this main loop
-- RPS will identify if it isn't and this will get set false later
plc_state.reactor_formed = true
@@ -230,14 +233,12 @@ function threads.thread__main(smem, init)
if device.isWireless() then
-- reconnected modem
plc_dev.modem = device
+ plc_state.no_modem = false
- if plc_state.init_ok then
- plc_comms.reconnect_modem(plc_dev.modem)
- end
+ if plc_state.init_ok then nic.connect(device) end
println_ts("wireless modem reconnected.")
log.info("comms modem reconnected")
- plc_state.no_modem = false
-- determine if we are still in a degraded state
if not plc_state.no_reactor then
@@ -709,9 +710,7 @@ function threads.thread__setpoint_control(smem)
end
-- if ramping completed or was aborted, reset last burn setpoint so that if it is requested again it will be re-attempted
- if not setpoints.burn_rate_en then
- last_burn_sp = 0
- end
+ if not setpoints.burn_rate_en then last_burn_sp = 0 end
end
-- check for termination request
diff --git a/rtu/config.lua b/rtu/config.lua
index 2279759..a0d3e68 100644
--- a/rtu/config.lua
+++ b/rtu/config.lua
@@ -10,6 +10,10 @@ config.RTU_CHANNEL = 16242
config.TRUSTED_RANGE = 0
-- time in seconds (>= 2) before assuming a remote device is no longer active
config.COMMS_TIMEOUT = 5
+-- facility authentication key (do NOT use one of your passwords)
+-- this enables verifying that messages are authentic
+-- all devices on the same network must use the same key
+-- config.AUTH_KEY = "SCADAfacility123"
-- log path
config.LOG_PATH = "/log.txt"
diff --git a/rtu/rtu.lua b/rtu/rtu.lua
index 831e231..3832986 100644
--- a/rtu/rtu.lua
+++ b/rtu/rtu.lua
@@ -158,12 +158,12 @@ end
-- RTU Communications
---@nodiscard
---@param version string RTU version
----@param modem table modem device
+---@param nic nic network interface device
---@param rtu_channel integer PLC comms channel
---@param svr_channel integer supervisor server channel
---@param range integer trusted device connection range
---@param conn_watchdog watchdog watchdog reference
-function rtu.comms(version, modem, rtu_channel, svr_channel, range, conn_watchdog)
+function rtu.comms(version, nic, rtu_channel, svr_channel, range, conn_watchdog)
local self = {
sv_addr = comms.BROADCAST,
seq_num = 0,
@@ -179,12 +179,8 @@ function rtu.comms(version, modem, rtu_channel, svr_channel, range, conn_watchdo
-- PRIVATE FUNCTIONS --
-- configure modem channels
- local function _conf_channels()
- modem.closeAll()
- modem.open(rtu_channel)
- end
-
- _conf_channels()
+ nic.closeAll()
+ nic.open(rtu_channel)
-- send a scada management packet
---@param msg_type SCADA_MGMT_TYPE
@@ -196,7 +192,7 @@ function rtu.comms(version, modem, rtu_channel, svr_channel, range, conn_watchdo
m_pkt.make(msg_type, msg)
s_pkt.make(self.sv_addr, self.seq_num, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
- modem.transmit(svr_channel, rtu_channel, s_pkt.raw_sendable())
+ nic.transmit(svr_channel, rtu_channel, s_pkt)
self.seq_num = self.seq_num + 1
end
@@ -240,17 +236,10 @@ function rtu.comms(version, modem, rtu_channel, svr_channel, range, conn_watchdo
function public.send_modbus(m_pkt)
local s_pkt = comms.scada_packet()
s_pkt.make(self.sv_addr, self.seq_num, PROTOCOL.MODBUS_TCP, m_pkt.raw_sendable())
- modem.transmit(svr_channel, rtu_channel, s_pkt.raw_sendable())
+ nic.transmit(svr_channel, rtu_channel, s_pkt)
self.seq_num = self.seq_num + 1
end
- -- reconnect a newly connected modem
- ---@param new_modem table
- function public.reconnect_modem(new_modem)
- modem = new_modem
- _conf_channels()
- end
-
-- unlink from the server
---@param rtu_state rtu_state
function public.unlink(rtu_state)
@@ -295,13 +284,10 @@ function rtu.comms(version, modem, rtu_channel, svr_channel, range, conn_watchdo
---@param distance integer
---@return modbus_frame|mgmt_frame|nil packet
function public.parse_packet(side, sender, reply_to, message, distance)
+ local s_pkt = nic.receive(side, sender, reply_to, message, distance)
local pkt = nil
- local s_pkt = comms.scada_packet()
- -- parse packet as generic SCADA packet
- s_pkt.receive(side, sender, reply_to, message, distance)
-
- if s_pkt.is_valid() then
+ if s_pkt then
-- get as MODBUS TCP packet
if s_pkt.protocol() == PROTOCOL.MODBUS_TCP then
local m_pkt = comms.modbus_packet()
diff --git a/rtu/startup.lua b/rtu/startup.lua
index 85f3220..9eecace 100644
--- a/rtu/startup.lua
+++ b/rtu/startup.lua
@@ -8,6 +8,7 @@ local comms = require("scada-common.comms")
local crash = require("scada-common.crash")
local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue")
+local network = require("scada-common.network")
local ppm = require("scada-common.ppm")
local rsio = require("scada-common.rsio")
local types = require("scada-common.types")
@@ -28,7 +29,7 @@ local sna_rtu = require("rtu.dev.sna_rtu")
local sps_rtu = require("rtu.dev.sps_rtu")
local turbinev_rtu = require("rtu.dev.turbinev_rtu")
-local RTU_VERSION = "v1.3.7"
+local RTU_VERSION = "v1.4.0"
local RTU_UNIT_TYPE = types.RTU_UNIT_TYPE
local RTU_UNIT_HW_STATE = databus.RTU_UNIT_HW_STATE
@@ -81,6 +82,19 @@ local function main()
-- mount connected devices
ppm.mount_all()
+ -- message authentication init
+ if type(config.AUTH_KEY) == "string" then
+ network.init_mac(config.AUTH_KEY)
+ end
+
+ -- get modem
+ local modem = ppm.get_wireless_modem()
+ if modem == nil then
+ println("boot> wireless modem not found")
+ log.fatal("no wireless modem on startup")
+ return
+ end
+
---@class rtu_shared_memory
local __shared_memory = {
-- RTU system state flags
@@ -91,16 +105,12 @@ local function main()
shutdown = false
},
- -- core RTU devices
- rtu_dev = {
- modem = ppm.get_wireless_modem()
- },
-
-- system objects
rtu_sys = {
+ nic = network.nic(modem),
rtu_comms = nil, ---@type rtu_comms
conn_watchdog = nil, ---@type watchdog
- units = {} ---@type table
+ units = {}
},
-- message queues
@@ -109,16 +119,8 @@ local function main()
}
}
- local smem_dev = __shared_memory.rtu_dev
local smem_sys = __shared_memory.rtu_sys
- -- get modem
- if smem_dev.modem == nil then
- println("boot> wireless modem not found")
- log.fatal("no wireless modem on startup")
- return
- end
-
databus.tx_hw_modem(true)
----------------------------------------
@@ -471,7 +473,7 @@ local function main()
log.debug("startup> conn watchdog started")
-- setup comms
- smem_sys.rtu_comms = rtu.comms(RTU_VERSION, smem_dev.modem, config.RTU_CHANNEL, config.SVR_CHANNEL,
+ smem_sys.rtu_comms = rtu.comms(RTU_VERSION, smem_sys.nic, config.RTU_CHANNEL, config.SVR_CHANNEL,
config.TRUSTED_RANGE, smem_sys.conn_watchdog)
log.debug("startup> comms init")
diff --git a/rtu/threads.lua b/rtu/threads.lua
index 6d51dec..c27052d 100644
--- a/rtu/threads.lua
+++ b/rtu/threads.lua
@@ -46,7 +46,7 @@ function threads.thread__main(smem)
-- load in from shared memory
local rtu_state = smem.rtu_state
- local rtu_dev = smem.rtu_dev
+ local nic = smem.rtu_sys.nic
local rtu_comms = smem.rtu_sys.rtu_comms
local conn_watchdog = smem.rtu_sys.conn_watchdog
local units = smem.rtu_sys.units
@@ -93,7 +93,9 @@ function threads.thread__main(smem)
if type ~= nil and device ~= nil then
if type == "modem" then
-- we only care if this is our wireless modem
- if device == rtu_dev.modem then
+ if nic.is_modem(device) then
+ nic.disconnect()
+
println_ts("wireless modem disconnected!")
log.warning("comms modem disconnected!")
@@ -127,8 +129,7 @@ function threads.thread__main(smem)
if type == "modem" then
if device.isWireless() then
-- reconnected modem
- rtu_dev.modem = device
- rtu_comms.reconnect_modem(rtu_dev.modem)
+ nic.connect(device)
println_ts("wireless modem reconnected.")
log.info("comms modem reconnected")
diff --git a/scada-common/comms.lua b/scada-common/comms.lua
index c5e9fd2..88e8631 100644
--- a/scada-common/comms.lua
+++ b/scada-common/comms.lua
@@ -7,14 +7,14 @@ local log = require("scada-common.log")
local insert = table.insert
---@diagnostic disable-next-line: undefined-field
-local C_ID = os.getComputerID() ---@type integer computer ID
+local COMPUTER_ID = os.getComputerID() ---@type integer computer ID
-local max_distance = nil ---@type number|nil maximum acceptable transmission distance
+local max_distance = nil ---@type number|nil maximum acceptable transmission distance
---@class comms
local comms = {}
-comms.version = "2.0.0"
+comms.version = "2.1.0"
---@enum PROTOCOL
local PROTOCOL = {
@@ -163,8 +163,7 @@ function comms.scada_packet()
---@param payload table
function public.make(dest_addr, seq_num, protocol, payload)
self.valid = true
----@diagnostic disable-next-line: undefined-field
- self.src_addr = C_ID
+ self.src_addr = COMPUTER_ID
self.dest_addr = dest_addr
self.seq_num = seq_num
self.protocol = protocol
@@ -219,10 +218,14 @@ function comms.scada_packet()
end
-- check if this packet is destined for this device
- local is_destination = (self.dest_addr == comms.BROADCAST) or (self.dest_addr == C_ID)
+ local is_destination = (self.dest_addr == comms.BROADCAST) or (self.dest_addr == COMPUTER_ID)
- self.valid = is_destination and type(self.src_addr) == "number" and type(self.dest_addr) == "number" and
- type(self.seq_num) == "number" and type(self.protocol) == "number" and type(self.payload) == "table"
+ self.valid = is_destination and
+ type(self.src_addr) == "number" and
+ type(self.dest_addr) == "number" and
+ type(self.seq_num) == "number" and
+ type(self.protocol) == "number" and
+ type(self.payload) == "table"
end
end
@@ -260,6 +263,112 @@ function comms.scada_packet()
return public
end
+-- authenticated SCADA packet object
+---@nodiscard
+function comms.authd_packet()
+ local self = {
+ modem_msg_in = nil, ---@type modem_message|nil
+ valid = false,
+ raw = {},
+ src_addr = comms.BROADCAST,
+ dest_addr = comms.BROADCAST,
+ mac = "",
+ payload = ""
+ }
+
+ ---@class authd_packet
+ local public = {}
+
+ -- make an authenticated SCADA packet
+ ---@param s_packet scada_packet scada packet to authenticate
+ ---@param mac function message authentication function
+ function public.make(s_packet, mac)
+ self.valid = true
+ self.src_addr = s_packet.src_addr()
+ self.dest_addr = s_packet.dest_addr()
+ self.payload = textutils.serialize(s_packet.raw_sendable(), { allow_repetitions = true, compact = true })
+ self.mac = mac(self.payload)
+ self.raw = { self.src_addr, self.dest_addr, self.mac, self.payload }
+ end
+
+ -- parse in a modem message as an authenticated SCADA packet
+ ---@param side string modem side
+ ---@param sender integer sender channel
+ ---@param reply_to integer reply channel
+ ---@param message any message body
+ ---@param distance integer transmission distance
+ ---@return boolean valid valid message received
+ function public.receive(side, sender, reply_to, message, distance)
+ ---@class modem_message
+ self.modem_msg_in = {
+ iface = side,
+ s_channel = sender,
+ r_channel = reply_to,
+ msg = message,
+ dist = distance
+ }
+
+ self.valid = false
+ self.raw = self.modem_msg_in.msg
+
+ if (type(max_distance) == "number") and (distance > max_distance) then
+ -- outside of maximum allowable transmission distance
+ -- log.debug("comms.authd_packet.receive(): discarding packet with distance " .. distance .. " outside of trusted range")
+ else
+ if type(self.raw) == "table" then
+ if #self.raw == 4 then
+ self.src_addr = self.raw[1]
+ self.dest_addr = self.raw[2]
+ self.mac = self.raw[3]
+ self.payload = self.raw[4]
+ else
+ self.src_addr = nil
+ self.dest_addr = nil
+ self.mac = ""
+ self.payload = ""
+ end
+
+ -- check if this packet is destined for this device
+ local is_destination = (self.dest_addr == comms.BROADCAST) or (self.dest_addr == COMPUTER_ID)
+
+ self.valid = is_destination and
+ type(self.src_addr) == "number" and
+ type(self.dest_addr) == "number" and
+ type(self.mac) == "string" and
+ type(self.payload) == "string"
+ end
+ end
+
+ return self.valid
+ end
+
+ -- public accessors --
+
+ ---@nodiscard
+ function public.modem_event() return self.modem_msg_in end
+ ---@nodiscard
+ function public.raw_sendable() return self.raw end
+
+ ---@nodiscard
+ function public.local_channel() return self.modem_msg_in.s_channel end
+ ---@nodiscard
+ function public.remote_channel() return self.modem_msg_in.r_channel end
+
+ ---@nodiscard
+ function public.is_valid() return self.valid end
+
+ ---@nodiscard
+ function public.src_addr() return self.src_addr end
+ ---@nodiscard
+ function public.dest_addr() return self.dest_addr end
+ ---@nodiscard
+ function public.mac() return self.mac end
+ ---@nodiscard
+ function public.data() return self.payload end
+
+ return public
+end
+
-- MODBUS packet
-- modeled after MODBUS TCP packet
---@nodiscard
diff --git a/scada-common/crash.lua b/scada-common/crash.lua
index 8d02728..45a3874 100644
--- a/scada-common/crash.lua
+++ b/scada-common/crash.lua
@@ -6,6 +6,8 @@ local comms = require("scada-common.comms")
local log = require("scada-common.log")
local util = require("scada-common.util")
+local core = require("graphics.core")
+
local crash = {}
local app = "unknown"
@@ -32,6 +34,7 @@ function crash.handler(error)
log.info(util.c("APPLICATION: ", app))
log.info(util.c("FIRMWARE VERSION: ", ver))
log.info(util.c("COMMS VERSION: ", comms.version))
+ log.info(util.c("GRAPHICS VERSION: ", core.version))
log.info("----------------------------------")
log.info(debug.traceback("--- begin debug trace ---", 1))
log.info("--- end debug trace ---")
diff --git a/scada-common/crypto.lua b/scada-common/crypto.lua
deleted file mode 100644
index 4417ae3..0000000
--- a/scada-common/crypto.lua
+++ /dev/null
@@ -1,244 +0,0 @@
---
--- Cryptographic Communications Engine
---
-
-local aes128 = require("lockbox.cipher.aes128")
-local ctr_mode = require("lockbox.cipher.mode.ctr")
-local sha1 = require("lockbox.digest.sha1")
-local sha2_256 = require("lockbox.digest.sha2_256")
-local pbkdf2 = require("lockbox.kdf.pbkdf2")
-local hmac = require("lockbox.mac.hmac")
-local zero_pad = require("lockbox.padding.zero")
-local stream = require("lockbox.util.stream")
-local array = require("lockbox.util.array")
-
-local log = require("scada-common.log")
-local util = require("scada-common.util")
-
-local crypto = {}
-
-local c_eng = {
- key = nil,
- cipher = nil,
- decipher = nil,
- hmac = nil
-}
-
----@alias hex string
-
--- initialize cryptographic system
-function crypto.init(password, server_port)
- local key_deriv = pbkdf2()
-
- -- setup PBKDF2
- -- the primary goal is to just turn our password into a 16 byte key
- key_deriv.setPassword(password)
- key_deriv.setSalt("salty_salt_at_" .. server_port)
- key_deriv.setIterations(32)
- key_deriv.setBlockLen(8)
- key_deriv.setDKeyLen(16)
-
- local start = util.time()
-
- key_deriv.setPRF(hmac().setBlockSize(64).setDigest(sha2_256))
- key_deriv.finish()
-
- log.dmesg("pbkdf2: key derivation took " .. (util.time() - start) .. "ms", "CRYPTO", colors.yellow)
-
- c_eng.key = array.fromHex(key_deriv.asHex())
-
- -- initialize cipher
- c_eng.cipher = ctr_mode.Cipher()
- c_eng.cipher.setKey(c_eng.key)
- c_eng.cipher.setBlockCipher(aes128)
- c_eng.cipher.setPadding(zero_pad)
-
- -- initialize decipher
- c_eng.decipher = ctr_mode.Decipher()
- c_eng.decipher.setKey(c_eng.key)
- c_eng.decipher.setBlockCipher(aes128)
- c_eng.decipher.setPadding(zero_pad)
-
- -- initialize HMAC
- c_eng.hmac = hmac()
- c_eng.hmac.setBlockSize(64)
- c_eng.hmac.setDigest(sha1)
- c_eng.hmac.setKey(c_eng.key)
-
- log.dmesg("init: completed in " .. (util.time() - start) .. "ms", "CRYPTO", colors.yellow)
-end
-
--- encrypt plaintext
----@nodiscard
----@param plaintext string
----@return table initial_value, string ciphertext
-function crypto.encrypt(plaintext)
- local start = util.time()
-
- -- initial value
- local iv = {
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255),
- math.random(0, 255)
- }
-
- log.debug("crypto.random: iv random took " .. (util.time() - start) .. "ms")
-
- start = util.time()
-
- c_eng.cipher.init()
- c_eng.cipher.update(stream.fromArray(iv))
- c_eng.cipher.update(stream.fromString(plaintext))
- c_eng.cipher.finish()
-
- local ciphertext = c_eng.cipher.asHex() ---@type hex
-
- log.debug("crypto.encrypt: aes128-ctr-mode took " .. (util.time() - start) .. "ms")
- log.debug("ciphertext: " .. util.strval(ciphertext))
-
- return iv, ciphertext
-end
-
--- decrypt ciphertext
----@nodiscard
----@param iv string CTR initial value
----@param ciphertext string ciphertext hex
----@return string plaintext
-function crypto.decrypt(iv, ciphertext)
- local start = util.time()
-
- c_eng.decipher.init()
- c_eng.decipher.update(stream.fromArray(iv))
- c_eng.decipher.update(stream.fromHex(ciphertext))
- c_eng.decipher.finish()
-
- local plaintext_hex = c_eng.decipher.asHex() ---@type hex
-
- local plaintext = stream.toString(stream.fromHex(plaintext_hex))
-
- log.debug("crypto.decrypt: aes128-ctr-mode took " .. (util.time() - start) .. "ms")
- log.debug("plaintext: " .. util.strval(plaintext))
-
- return plaintext
-end
-
--- generate HMAC of message
----@nodiscard
----@param message_hex string initial value concatenated with ciphertext
-function crypto.hmac(message_hex)
- local start = util.time()
-
- c_eng.hmac.init()
- c_eng.hmac.update(stream.fromHex(message_hex))
- c_eng.hmac.finish()
-
- local hash = c_eng.hmac.asHex() ---@type hex
-
- log.debug("crypto.hmac: hmac-sha1 took " .. (util.time() - start) .. "ms")
- log.debug("hmac: " .. util.strval(hash))
-
- return hash
-end
-
--- wrap a modem as a secure modem to send encrypted traffic
----@param modem table modem to wrap
-function crypto.secure_modem(modem)
- ---@class secure_modem
- ---@field open function
- ---@field isOpen function
- ---@field close function
- ---@field closeAll function
- ---@field isWireless function
- ---@field getNamesRemote function
- ---@field isPresentRemote function
- ---@field getTypeRemote function
- ---@field hasTypeRemote function
- ---@field getMethodsRemote function
- ---@field callRemote function
- ---@field getNameLocal function
- local public = {}
-
- -- wrap a modem
- ---@param reconnected_modem table
----@diagnostic disable-next-line: redefined-local
- function public.wrap(reconnected_modem)
- modem = reconnected_modem
- for key, func in pairs(modem) do
- public[key] = func
- end
- end
-
- -- wrap modem functions, then we replace transmit
- public.wrap(modem)
-
- -- send a packet with encryption
- ---@param channel integer
- ---@param reply_channel integer
- ---@param payload table packet raw_sendable
- function public.transmit(channel, reply_channel, payload)
- local plaintext = textutils.serialize(payload, { allow_repetitions = true, compact = true })
-
- local iv, ciphertext = crypto.encrypt(plaintext)
----@diagnostic disable-next-line: redefined-local
- local computed_hmac = crypto.hmac(iv .. ciphertext)
-
- modem.transmit(channel, reply_channel, { computed_hmac, iv, ciphertext })
- end
-
- -- parse in a modem message as a network packet
- ---@nodiscard
- ---@param side string modem side
- ---@param sender integer sender port
- ---@param reply_to integer reply port
- ---@param message any encrypted packet sent with secure_modem.transmit
- ---@param distance integer transmission distance
- ---@return string side, integer sender, integer reply_to, any plaintext_message, integer distance
- function public.receive(side, sender, reply_to, message, distance)
- local body = ""
-
- if type(message) == "table" then
- if #message == 3 then
----@diagnostic disable-next-line: redefined-local
- local rx_hmac = message[1]
- local iv = message[2]
- local ciphertext = message[3]
-
- local computed_hmac = crypto.hmac(iv .. ciphertext)
-
- if rx_hmac == computed_hmac then
- -- message intact
- local plaintext = crypto.decrypt(iv, ciphertext)
- body = textutils.unserialize(plaintext)
-
- if body == nil then
- -- failed decryption
- log.debug("crypto.secure_modem: decryption failed")
- body = ""
- end
- else
- -- something went wrong
- log.debug("crypto.secure_modem: hmac mismatch violation")
- end
- end
- end
-
- return side, sender, reply_to, body, distance
- end
-
- return public
-end
-
-return crypto
diff --git a/scada-common/network.lua b/scada-common/network.lua
new file mode 100644
index 0000000..dbb3e75
--- /dev/null
+++ b/scada-common/network.lua
@@ -0,0 +1,233 @@
+--
+-- Network Communications
+--
+
+local md5 = require("lockbox.digest.md5")
+local sha256 = require("lockbox.digest.sha2_256")
+local pbkdf2 = require("lockbox.kdf.pbkdf2")
+local hmac = require("lockbox.mac.hmac")
+local stream = require("lockbox.util.stream")
+local array = require("lockbox.util.array")
+local comms = require("scada-common.comms")
+
+local log = require("scada-common.log")
+local util = require("scada-common.util")
+
+local network = {}
+
+local c_eng = {
+ key = nil,
+ hmac = nil
+}
+
+-- initialize message authentication system
+---@param passkey string facility passkey
+---@return integer init_time milliseconds init took
+function network.init_mac(passkey)
+ local start = util.time_ms()
+
+ local key_deriv = pbkdf2()
+
+ -- setup PBKDF2
+ key_deriv.setPassword(passkey)
+ key_deriv.setSalt("pepper")
+ key_deriv.setIterations(32)
+ key_deriv.setBlockLen(8)
+ key_deriv.setDKeyLen(16)
+ key_deriv.setPRF(hmac().setBlockSize(64).setDigest(sha256))
+ key_deriv.finish()
+
+ c_eng.key = array.fromHex(key_deriv.asHex())
+
+ -- initialize HMAC
+ c_eng.hmac = hmac()
+ c_eng.hmac.setBlockSize(64)
+ c_eng.hmac.setDigest(md5)
+ c_eng.hmac.setKey(c_eng.key)
+
+ local init_time = util.time_ms() - start
+ log.info("network.init_mac completed in " .. init_time .. "ms")
+
+ return init_time
+end
+
+-- generate HMAC of message
+---@nodiscard
+---@param message string initial value concatenated with ciphertext
+local function compute_hmac(message)
+ -- local start = util.time_ms()
+
+ c_eng.hmac.init()
+ c_eng.hmac.update(stream.fromString(message))
+ c_eng.hmac.finish()
+
+ local hash = c_eng.hmac.asHex()
+
+ -- log.debug("compute_hmac(): hmac-md5 = " .. util.strval(hash) .. " (took " .. (util.time_ms() - start) .. "ms)")
+
+ return hash
+end
+
+-- NIC: Network Interface Controller
+-- utilizes HMAC-MD5 for message authentication, if enabled
+---@param modem table modem to use
+function network.nic(modem)
+ local self = {
+ connected = true, -- used to avoid costly MAC calculations if modem isn't even present
+ channels = {}
+ }
+
+ ---@class nic
+ ---@field open function
+ ---@field isOpen function
+ ---@field close function
+ ---@field closeAll function
+ ---@field isWireless function
+ ---@field getNameLocal function
+ ---@field getNamesRemote function
+ ---@field isPresentRemote function
+ ---@field getTypeRemote function
+ ---@field hasTypeRemote function
+ ---@field getMethodsRemote function
+ ---@field callRemote function
+ local public = {}
+
+ -- check if this NIC has a connected modem
+ ---@nodiscard
+ function public.connected() return self.connected end
+
+ -- connect to a modem peripheral
+ ---@param reconnected_modem table
+ function public.connect(reconnected_modem)
+ modem = reconnected_modem
+ self.connected = true
+
+ -- open previously opened channels
+ for _, channel in ipairs(self.channels) do
+ modem.open(channel)
+ end
+
+ -- link all public functions except for transmit
+ for key, func in pairs(modem) do
+ if key ~= "transmit" and key ~= "open" and key ~= "close" and key ~= "closeAll" then public[key] = func end
+ end
+ end
+
+ -- flag this NIC as no longer having a connected modem (usually do to peripheral disconnect)
+ function public.disconnect() self.connected = false end
+
+ -- check if a peripheral is this modem
+ ---@nodiscard
+ ---@param device table
+ function public.is_modem(device) return device == modem end
+
+ -- wrap modem functions, then create custom functions
+ public.connect(modem)
+
+ -- open a channel on the modem
+ -- if disconnected *after* opening, previousy opened channels will be re-opened on reconnection
+ ---@param channel integer
+ function public.open(channel)
+ modem.open(channel)
+
+ local already_open = false
+ for i = 1, #self.channels do
+ if self.channels[i] == channel then
+ already_open = true
+ break
+ end
+ end
+
+ if not already_open then
+ table.insert(self.channels, channel)
+ end
+ end
+
+ -- close a channel on the modem
+ ---@param channel integer
+ function public.close(channel)
+ modem.close(channel)
+
+ for i = 1, #self.channels do
+ if self.channels[i] == channel then
+ table.remove(self.channels, i)
+ return
+ end
+ end
+ end
+
+ -- close all channels on the modem
+ function public.closeAll()
+ modem.closeAll()
+ self.channels = {}
+ end
+
+ -- send a packet, with message authentication if configured
+ ---@param dest_channel integer destination channel
+ ---@param local_channel integer local channel
+ ---@param packet scada_packet packet
+ function public.transmit(dest_channel, local_channel, packet)
+ if self.connected then
+ local tx_packet = packet ---@type authd_packet|scada_packet
+
+ if c_eng.hmac ~= nil then
+ -- local start = util.time_ms()
+ tx_packet = comms.authd_packet()
+
+ ---@cast tx_packet authd_packet
+ tx_packet.make(packet, compute_hmac)
+
+ -- log.debug("crypto.modem.transmit: data processing took " .. (util.time_ms() - start) .. "ms")
+ end
+
+ modem.transmit(dest_channel, local_channel, tx_packet.raw_sendable())
+ end
+ end
+
+ -- parse in a modem message as a network packet
+ ---@nodiscard
+ ---@param side string modem side
+ ---@param sender integer sender channel
+ ---@param reply_to integer reply channel
+ ---@param message any packet sent with or without message authentication
+ ---@param distance integer transmission distance
+ ---@return scada_packet|nil packet received packet if valid and passed authentication check
+ function public.receive(side, sender, reply_to, message, distance)
+ local packet = nil
+
+ if self.connected then
+ local s_packet = comms.scada_packet()
+
+ if c_eng.hmac ~= nil then
+ -- parse packet as an authenticated SCADA packet
+ local a_packet = comms.authd_packet()
+ a_packet.receive(side, sender, reply_to, message, distance)
+
+ if a_packet.is_valid() then
+ -- local start = util.time_ms()
+ local packet_hmac = a_packet.mac()
+ local msg = a_packet.data()
+ local computed_hmac = compute_hmac(msg)
+
+ if packet_hmac == computed_hmac then
+ -- log.debug("crypto.modem.receive: HMAC verified in " .. (util.time_ms() - start) .. "ms")
+ s_packet.receive(side, sender, reply_to, textutils.unserialize(msg), distance)
+ else
+ -- log.debug("crypto.modem.receive: HMAC failed verification in " .. (util.time_ms() - start) .. "ms")
+ end
+ end
+ else
+ -- parse packet as a generic SCADA packet
+ s_packet.receive(side, sender, reply_to, message, distance)
+ end
+
+ if s_packet.is_valid() then packet = s_packet end
+ end
+
+ return packet
+ end
+
+ return public
+end
+
+return network
diff --git a/supervisor/config.lua b/supervisor/config.lua
index a4a595b..2373f0d 100644
--- a/supervisor/config.lua
+++ b/supervisor/config.lua
@@ -17,6 +17,10 @@ config.PLC_TIMEOUT = 5
config.RTU_TIMEOUT = 5
config.CRD_TIMEOUT = 5
config.PKT_TIMEOUT = 5
+-- facility authentication key (do NOT use one of your passwords)
+-- this enables verifying that messages are authentic
+-- all devices on the same network must use the same key
+-- config.AUTH_KEY = "SCADAfacility123"
-- expected number of reactors
config.NUM_REACTORS = 4
diff --git a/supervisor/session/svsessions.lua b/supervisor/session/svsessions.lua
index a311ab9..075f090 100644
--- a/supervisor/session/svsessions.lua
+++ b/supervisor/session/svsessions.lua
@@ -34,7 +34,7 @@ local SESSION_TYPE = {
svsessions.SESSION_TYPE = SESSION_TYPE
local self = {
- modem = nil, ---@type table|nil
+ nic = nil, ---@type nic|nil
fp_ok = false,
num_reactors = 0,
facility = nil, ---@type facility|nil
@@ -60,7 +60,7 @@ local function _sv_handle_outq(session)
if msg ~= nil then
if msg.qtype == mqueue.TYPE.PACKET then
-- handle a packet to be sent
- self.modem.transmit(session.r_chan, config.SVR_CHANNEL, msg.message.raw_sendable())
+ self.nic.transmit(session.r_chan, config.SVR_CHANNEL, msg.message)
elseif msg.qtype == mqueue.TYPE.COMMAND then
-- handle instruction/notification
elseif msg.qtype == mqueue.TYPE.DATA then
@@ -135,7 +135,7 @@ local function _shutdown(session)
while session.out_queue.ready() do
local msg = session.out_queue.pop()
if msg ~= nil and msg.qtype == mqueue.TYPE.PACKET then
- self.modem.transmit(session.r_chan, config.SVR_CHANNEL, msg.message.raw_sendable())
+ self.nic.transmit(session.r_chan, config.SVR_CHANNEL, msg.message)
end
end
@@ -195,23 +195,17 @@ end
-- PUBLIC FUNCTIONS --
-- initialize svsessions
----@param modem table modem device
+---@param nic nic network interface device
---@param fp_ok boolean front panel active
---@param num_reactors integer number of reactors
---@param cooling_conf table cooling configuration definition
-function svsessions.init(modem, fp_ok, num_reactors, cooling_conf)
- self.modem = modem
+function svsessions.init(nic, fp_ok, num_reactors, cooling_conf)
+ self.nic = nic
self.fp_ok = fp_ok
self.num_reactors = num_reactors
self.facility = facility.new(num_reactors, cooling_conf)
end
--- re-link the modem
----@param modem table
-function svsessions.relink_modem(modem)
- self.modem = modem
-end
-
-- find an RTU session by the computer ID
---@nodiscard
---@param source_addr integer
diff --git a/supervisor/startup.lua b/supervisor/startup.lua
index d3f2d81..3dc850e 100644
--- a/supervisor/startup.lua
+++ b/supervisor/startup.lua
@@ -7,6 +7,7 @@ require("/initenv").init_env()
local crash = require("scada-common.crash")
local comms = require("scada-common.comms")
local log = require("scada-common.log")
+local network = require("scada-common.network")
local ppm = require("scada-common.ppm")
local tcd = require("scada-common.tcd")
local util = require("scada-common.util")
@@ -20,7 +21,7 @@ local supervisor = require("supervisor.supervisor")
local svsessions = require("supervisor.session.svsessions")
-local SUPERVISOR_VERSION = "v0.17.10"
+local SUPERVISOR_VERSION = "v0.18.0"
local println = util.println
local println_ts = util.println_ts
@@ -94,6 +95,12 @@ local function main()
-- mount connected devices
ppm.mount_all()
+ -- message authentication init
+ if type(config.AUTH_KEY) == "string" then
+ network.init_mac(config.AUTH_KEY)
+ end
+
+ -- get modem
local modem = ppm.get_wireless_modem()
if modem == nil then
println("startup> wireless modem not found")
@@ -115,8 +122,9 @@ local function main()
println_ts = function (_) end
end
- -- start comms
- local superv_comms = supervisor.comms(SUPERVISOR_VERSION, modem, fp_ok)
+ -- create network interface then setup comms
+ local nic = network.nic(modem)
+ local superv_comms = supervisor.comms(SUPERVISOR_VERSION, nic, fp_ok)
-- base loop clock (6.67Hz, 3 ticks)
local MAIN_CLOCK = 0.15
@@ -139,9 +147,12 @@ local function main()
if type ~= nil and device ~= nil then
if type == "modem" then
-- we only care if this is our wireless modem
- if device == modem then
+ if nic.is_modem(device) then
+ nic.disconnect()
+
println_ts("wireless modem disconnected!")
log.warning("comms modem disconnected")
+
databus.tx_hw_modem(false)
else
log.warning("non-comms modem disconnected")
@@ -153,10 +164,9 @@ local function main()
if type ~= nil and device ~= nil then
if type == "modem" then
- if device.isWireless() then
+ if device.isWireless() and not nic.connected() then
-- reconnected modem
- modem = device
- superv_comms.reconnect_modem(modem)
+ nic.connect(device)
println_ts("wireless modem reconnected.")
log.info("comms modem reconnected")
diff --git a/supervisor/supervisor.lua b/supervisor/supervisor.lua
index cfc52d8..fb33b06 100644
--- a/supervisor/supervisor.lua
+++ b/supervisor/supervisor.lua
@@ -16,10 +16,10 @@ local SCADA_MGMT_TYPE = comms.SCADA_MGMT_TYPE
-- supervisory controller communications
---@nodiscard
---@param _version string supervisor version
----@param modem table modem device
+---@param nic nic network interface device
---@param fp_ok boolean if the front panel UI is running
---@diagnostic disable-next-line: unused-local
-function supervisor.comms(_version, modem, fp_ok)
+function supervisor.comms(_version, nic, fp_ok)
-- print a log message to the terminal as long as the UI isn't running
local function println(message) if not fp_ok then util.println_ts(message) end end
@@ -43,15 +43,11 @@ function supervisor.comms(_version, modem, fp_ok)
-- PRIVATE FUNCTIONS --
-- configure modem channels
- local function _conf_channels()
- modem.closeAll()
- modem.open(svr_channel)
- end
-
- _conf_channels()
+ nic.closeAll()
+ nic.open(svr_channel)
-- pass modem, status, and config data to svsessions
- svsessions.init(modem, fp_ok, num_reactors, cooling_conf)
+ svsessions.init(nic, fp_ok, num_reactors, cooling_conf)
-- send an establish request response
---@param packet scada_packet
@@ -64,7 +60,7 @@ function supervisor.comms(_version, modem, fp_ok)
m_pkt.make(SCADA_MGMT_TYPE.ESTABLISH, { ack, data })
s_pkt.make(packet.src_addr(), packet.seq_num() + 1, PROTOCOL.SCADA_MGMT, m_pkt.raw_sendable())
- modem.transmit(packet.remote_channel(), svr_channel, s_pkt.raw_sendable())
+ nic.transmit(packet.remote_channel(), svr_channel, s_pkt)
self.last_est_acks[packet.src_addr()] = ack
end
@@ -73,14 +69,6 @@ function supervisor.comms(_version, modem, fp_ok)
---@class superv_comms
local public = {}
- -- reconnect a newly connected modem
- ---@param new_modem table
- function public.reconnect_modem(new_modem)
- modem = new_modem
- svsessions.relink_modem(new_modem)
- _conf_channels()
- end
-
-- parse a packet
---@nodiscard
---@param side string
@@ -90,13 +78,10 @@ function supervisor.comms(_version, modem, fp_ok)
---@param distance integer
---@return modbus_frame|rplc_frame|mgmt_frame|crdn_frame|nil packet
function public.parse_packet(side, sender, reply_to, message, distance)
+ local s_pkt = nic.receive(side, sender, reply_to, message, distance)
local pkt = nil
- local s_pkt = comms.scada_packet()
- -- parse packet as generic SCADA packet
- s_pkt.receive(side, sender, reply_to, message, distance)
-
- if s_pkt.is_valid() then
+ if s_pkt then
-- get as MODBUS TCP packet
if s_pkt.protocol() == PROTOCOL.MODBUS_TCP then
local m_pkt = comms.modbus_packet()
diff --git a/test/lockbox-benchmark.lua b/test/lockbox-benchmark.lua
deleted file mode 100644
index 7c6ae55..0000000
--- a/test/lockbox-benchmark.lua
+++ /dev/null
@@ -1,105 +0,0 @@
-require("/initenv").init_env()
-
-local pbkdf2 = require("lockbox.kdf.pbkdf2")
-local AES128Cipher = require("lockbox.cipher.aes128")
-local HMAC = require("lockbox.mac.hmac")
-local SHA1 = require("lockbox.digest.sha1")
--- local SHA2_224 = require("lockbox.digest.sha2_224")
-local SHA2_256 = require("lockbox.digest.sha2_256")
-local Stream = require("lockbox.util.stream")
-local Array = require("lockbox.util.array")
-
--- local CBCMode = require("lockbox.cipher.mode.cbc")
--- local CFBMode = require("lockbox.cipher.mode.cfb")
--- local OFBMode = require("lockbox.cipher.mode.ofb")
-local CTRMode = require("lockbox.cipher.mode.ctr")
-
-local ZeroPadding = require("lockbox.padding.zero")
-
-local comms = require("scada-common.comms")
-local util = require("scada-common.util")
-
-local start = util.time()
-
-local keyd = pbkdf2()
-
-keyd.setPassword("mypassword")
-keyd.setSalt("no_salt_thanks")
-keyd.setIterations(16)
-keyd.setBlockLen(4)
-keyd.setDKeyLen(16)
-keyd.setPRF(HMAC().setBlockSize(64).setDigest(SHA2_256))
-keyd.finish()
-
-util.println("pbkdf2: took " .. (util.time() - start) .. "ms")
-util.println(keyd.asHex())
-
-local pkt = comms.modbus_packet()
----@diagnostic disable-next-line: param-type-mismatch
-pkt.make(1, 2, 7, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
-local spkt = comms.scada_packet()
-spkt.make(0, 1, 1, pkt.raw_sendable())
-
-start = util.time()
-local data = textutils.serialize(spkt.raw_sendable(), { allow_repetitions = true, compact = true })
-
-util.println("packet serialize: took " .. (util.time() - start) .. "ms")
-util.println("message: " .. data)
-
-start = util.time()
-local v = {
- cipher = CTRMode.Cipher,
- decipher = CTRMode.Decipher,
- iv = Array.fromHex("000102030405060708090A0B0C0D0E0F"),
- key = Array.fromHex(keyd.asHex()),
- padding = ZeroPadding
-}
-util.println("v init: took " .. (util.time() - start) .. "ms")
-
-start = util.time()
-local cipher = v.cipher()
-.setKey(v.key)
-.setBlockCipher(AES128Cipher)
-.setPadding(v.padding);
-util.println("cipher init: took " .. (util.time() - start) .. "ms")
-
-start = util.time()
-local cipherOutput = cipher
- .init()
- .update(Stream.fromArray(v.iv))
- .update(Stream.fromString(data))
- .asHex();
-util.println("encrypt: took " .. (util.time() - start) .. "ms")
-util.println("ciphertext: " .. cipherOutput)
-
-start = util.time()
-local decipher = v.decipher()
- .setKey(v.key)
- .setBlockCipher(AES128Cipher)
- .setPadding(v.padding);
-util.println("decipher init: took " .. (util.time() - start) .. "ms")
-
-start = util.time()
-local plainOutput = decipher
- .init()
- .update(Stream.fromArray(v.iv))
- .update(Stream.fromHex(cipherOutput))
- .asHex();
-util.println("decrypt: took " .. (util.time() - start) .. "ms")
-local a = Stream.fromHex(plainOutput)
-local b = Stream.toString(a)
-util.println("plaintext: " .. b)
-
-local msg = "000102030405060708090A0B0C0D0E0F" .. cipherOutput
-
-start = util.time()
-local hash = HMAC()
- .setBlockSize(64)
- .setDigest(SHA1)
- .setKey(keyd)
- .init()
- .update(Stream.fromHex(msg))
- .finish()
- .asHex();
-util.println("hmac: took " .. (util.time() - start) .. "ms")
-util.println("hash: " .. hash)
diff --git a/test/lockbox_benchmark.lua b/test/lockbox_benchmark.lua
new file mode 100644
index 0000000..9cdfd73
--- /dev/null
+++ b/test/lockbox_benchmark.lua
@@ -0,0 +1,193 @@
+require("/initenv").init_env()
+
+local pbkdf2 = require("lockbox.kdf.pbkdf2")
+-- local AES128Cipher = require("lockbox.cipher.aes128")
+local HMAC = require("lockbox.mac.hmac")
+local MD5 = require("lockbox.digest.md5")
+local SHA1 = require("lockbox.digest.sha1")
+local SHA2_224 = require("lockbox.digest.sha2_224")
+local SHA2_256 = require("lockbox.digest.sha2_256")
+local Stream = require("lockbox.util.stream")
+-- local Array = require("lockbox.util.array")
+
+-- local CBCMode = require("lockbox.cipher.mode.cbc")
+-- local CFBMode = require("lockbox.cipher.mode.cfb")
+-- local OFBMode = require("lockbox.cipher.mode.ofb")
+-- local CTRMode = require("lockbox.cipher.mode.ctr")
+
+-- local ZeroPadding = require("lockbox.padding.zero")
+
+local comms = require("scada-common.comms")
+local util = require("scada-common.util")
+
+local start = util.time()
+
+local keyd = pbkdf2()
+
+keyd.setPassword("mypassword")
+keyd.setSalt("no_salt_thanks")
+keyd.setIterations(16)
+keyd.setBlockLen(4)
+keyd.setDKeyLen(16)
+keyd.setPRF(HMAC().setBlockSize(64).setDigest(SHA2_256))
+keyd.finish()
+
+util.println("pbkdf2: took " .. (util.time() - start) .. "ms")
+util.println(keyd.asHex())
+
+local pkt = comms.modbus_packet()
+---@diagnostic disable-next-line: param-type-mismatch
+pkt.make(1, 2, 7, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
+local spkt = comms.scada_packet()
+spkt.make(0, 1, 1, pkt.raw_sendable())
+
+start = util.time()
+local data = textutils.serialize(spkt.raw_sendable(), { allow_repetitions = true, compact = true })
+
+util.println("packet serialize: took " .. (util.time() - start) .. "ms")
+util.println("message: " .. data)
+
+--[[
+start = util.time()
+local v = {
+ cipher = CTRMode.Cipher,
+ decipher = CTRMode.Decipher,
+ iv = Array.fromHex("000102030405060708090A0B0C0D0E0F"),
+ key = Array.fromHex(keyd.asHex()),
+ padding = ZeroPadding
+}
+util.println("v init: took " .. (util.time() - start) .. "ms")
+
+start = util.time()
+local cipher = v.cipher()
+.setKey(v.key)
+.setBlockCipher(AES128Cipher)
+.setPadding(v.padding);
+util.println("cipher init: took " .. (util.time() - start) .. "ms")
+
+start = util.time()
+local cipherOutput = cipher
+ .init()
+ .update(Stream.fromArray(v.iv))
+ .update(Stream.fromString(data))
+ .asHex();
+util.println("encrypt: took " .. (util.time() - start) .. "ms")
+util.println("ciphertext: " .. cipherOutput)
+
+start = util.time()
+local decipher = v.decipher()
+ .setKey(v.key)
+ .setBlockCipher(AES128Cipher)
+ .setPadding(v.padding);
+util.println("decipher init: took " .. (util.time() - start) .. "ms")
+
+start = util.time()
+local plainOutput = decipher
+ .init()
+ .update(Stream.fromArray(v.iv))
+ .update(Stream.fromHex(cipherOutput))
+ .asHex();
+util.println("decrypt: took " .. (util.time() - start) .. "ms")
+local a = Stream.fromHex(plainOutput)
+local b = Stream.toString(a)
+util.println("plaintext: " .. b)
+
+local msg = "000102030405060708090A0B0C0D0E0F" .. cipherOutput
+]]--
+
+-- local testmsg = "{1,0,42,3,{5,{{},{boilers={},turbines={},rad_mon={},},{TurbineOnline={false,},AutoControl=false,TurbineTrip={false,},HeatingRateLow={false,},HighStartupRate=false,BoilRateMismatch=false,ManualReactorSCRAM=false,FuelInputRateLow=false,PLCHeartbeat=false,MaxWaterReturnFeed=false,RCSFault=false,PLCOnline=false,RadiationMonitor=1,TurbineOverSpeed={false,},CoolantFeedMismatch=false,BoilerOnline={false,},ReactorTempHigh=false,SteamDumpOpen={1,},RCSFlowLow=false,RadiationWarning=false,WasteLineOcclusion=false,SteamFeedMismatch=false,ReactorSCRAM=false,EmergencyCoolant=1,CoolantLevelLow=false,ReactorHighDeltaT=false,AutoReactorSCRAM=false,WaterLevelLow={},RCPTrip=false,GeneratorTrip={false,},},{1,1,1,1,1,1,1,1,1,1,1,1,},{\"REACTOR OFF-LINE\",\"awaiting connection...\",1,false,true,},},{{},{boilers={},turbines={},rad_mon={},},{TurbineOnline={false,},AutoControl=false,TurbineTrip={false,},HeatingRateLow={false,},HighStartupRate=false,BoilRateMismatch=false,ManualReactorSCRAM=false,FuelInputRateLow=false,PLCHeartbeat=false,MaxWaterReturnFeed=false,RCSFault=false,PLCOnline=false,RadiationMonitor=1,TurbineOverSpeed={false,},CoolantFeedMismatch=false,BoilerOnline={false,},ReactorTempHigh=false,SteamDumpOpen={1,},RCSFlowLow=false,RadiationWarning=false,WasteLineOcclusion=false,SteamFeedMismatch=false,ReactorSCRAM=false,EmergencyCoolant=1,CoolantLevelLow=false,ReactorHighDeltaT=false,AutoReactorSCRAM=false,WaterLevelLow={},RCPTrip=false,GeneratorTrip={false,},},{1,1,1,1,1,1,1,1,1,1,1,1,},{\"REACTOR OFF-LINE\",\"awaiting connection...\",1,false,true,},},{{},{boilers={},turbines={},rad_mon={},},{TurbineOnline={false,},AutoControl=false,TurbineTrip={false,},HeatingRateLow={false,},HighStartupRate=false,BoilRateMismatch=false,ManualReactorSCRAM=false,FuelInputRateLow=false,PLCHeartbeat=false,MaxWaterReturnFeed=false,RCSFault=false,PLCOnline=false,RadiationMonitor=1,TurbineOverSpeed={false,},CoolantFeedMismatch=false,BoilerOnline={false,},ReactorTempHigh=false,SteamDumpOpen={1,},RCSFlowLow=false,RadiationWarning=false,WasteLineOcclusion=false,SteamFeedMismatch=false,ReactorSCRAM=false,EmergencyCoolant=1,CoolantLevelLow=false,ReactorHighDeltaT=false,AutoReactorSCRAM=false,WaterLevelLow={},RCPTrip=false,GeneratorTrip={false,},},{1,1,1,1,1,1,1,1,1,1,1,1,},{\"REACTOR OFF-LINE\",\"awaiting connection...\",1,false,true,},},{{},{boilers={},turbines={},rad_mon={},},{TurbineOnline={false,},AutoControl=false,TurbineTrip={false,},HeatingRateLow={false,},HighStartupRate=false,BoilRateMismatch=false,ManualReactorSCRAM=false,FuelInputRateLow=false,PLCHeartbeat=false,MaxWaterReturnFeed=false,RCSFault=false,PLCOnline=false,RadiationMonitor=1,TurbineOverSpeed={false,},CoolantFeedMismatch=false,BoilerOnline={false,},ReactorTempHigh=false,SteamDumpOpen={1,},RCSFlowLow=false,RadiationWarning=false,WasteLineOcclusion=false,SteamFeedMismatch=false,ReactorSCRAM=false,EmergencyCoolant=1,CoolantLevelLow=false,ReactorHighDeltaT=false,AutoReactorSCRAM=false,WaterLevelLow={},RCPTrip=false,GeneratorTrip={false,},},{1,1,1,1,1,1,1,1,1,1,1,1,},{\"REACTOR OFF-LINE\",\"awaiting connection...\",1,false,true,},},},}"
+local testmsg = "{1,0,42,3,{5,{{},{boilers={},turbines={},rad_mon={},},{TurbineOnline={false,},AutoControl=false,TurbineTrip={false,},HeatingRateLow={false,},HighStartupRate=false,BoilRateMismatch=false,ManualReactorSCRAM=false,FuelInputRateLow=false}"
+local n = 1000
+
+---@diagnostic disable: undefined-field
+
+local hash
+local hmac = HMAC().setBlockSize(64).setDigest(MD5).setKey(keyd).init()
+
+os.sleep(0)
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-md5: took " .. (util.time() - start) .. "ms")
+util.println("hash: " .. hash)
+os.sleep(0)
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-md5: took " .. (util.time() - start) .. "ms")
+os.sleep(0)
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-md5: took " .. (util.time() - start) .. "ms")
+os.sleep(0)
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-md5: took " .. (util.time() - start) .. "ms")
+os.sleep(0)
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-md5: took " .. (util.time() - start) .. "ms")
+
+hmac = HMAC().setBlockSize(64).setDigest(SHA1).setKey(keyd).init()
+
+os.sleep(0)
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-sha1: took " .. (util.time() - start) .. "ms")
+util.println("hash: " .. hash)
+os.sleep(0)
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-sha1: took " .. (util.time() - start) .. "ms")
+os.sleep(0)
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-sha1: took " .. (util.time() - start) .. "ms")
+os.sleep(0)
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-sha1: took " .. (util.time() - start) .. "ms")
+os.sleep(0)
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-sha1: took " .. (util.time() - start) .. "ms")
+
+os.sleep(0)
+
+hmac = HMAC().setBlockSize(64).setDigest(SHA2_224).setKey(keyd).init()
+
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-sha224: took " .. (util.time() - start) .. "ms")
+util.println("hash: " .. hash)
+
+os.sleep(0)
+
+hmac = HMAC().setBlockSize(64).setDigest(SHA2_256).setKey(keyd).init()
+
+start = util.time()
+for _ = 1, n do
+ hash = hmac.update(Stream.fromHex(testmsg)).finish().asHex();
+end
+util.println("hmac-sha256: took " .. (util.time() - start) .. "ms")
+util.println("hash: " .. hash)