mirror of
https://github.com/MikaylaFischler/cc-mek-scada.git
synced 2024-08-30 18:22:34 +00:00
#51 send serialized data to properly MAC
This commit is contained in:
parent
fb3c7ded06
commit
a8071db08e
File diff suppressed because one or more lines are too long
@ -77,7 +77,7 @@ function threads.thread__main(smem, init)
|
||||
loop_clock.start()
|
||||
|
||||
-- send updated data
|
||||
if not nic.connected() then
|
||||
if nic.connected() then
|
||||
if plc_comms.is_linked() then
|
||||
smem.q.mq_comms_tx.push_command(MQ__COMM_CMD.SEND_STATUS)
|
||||
else
|
||||
|
@ -149,7 +149,6 @@ function comms.scada_packet()
|
||||
dest_addr = comms.BROADCAST,
|
||||
seq_num = -1,
|
||||
protocol = PROTOCOL.SCADA_MGMT,
|
||||
mac = "",
|
||||
length = 0,
|
||||
payload = {}
|
||||
}
|
||||
@ -170,7 +169,7 @@ function comms.scada_packet()
|
||||
self.protocol = protocol
|
||||
self.length = #payload
|
||||
self.payload = payload
|
||||
self.raw = { self.src_addr, self.dest_addr, self.seq_num, self.protocol, self.mac, self.payload }
|
||||
self.raw = { self.src_addr, self.dest_addr, self.seq_num, self.protocol, self.payload }
|
||||
end
|
||||
|
||||
-- parse in a modem message as a SCADA packet
|
||||
@ -198,24 +197,22 @@ function comms.scada_packet()
|
||||
-- log.debug("comms.scada_packet.receive(): discarding packet with distance " .. distance .. " outside of trusted range")
|
||||
else
|
||||
if type(self.raw) == "table" then
|
||||
if #self.raw == 6 then
|
||||
if #self.raw == 5 then
|
||||
self.src_addr = self.raw[1]
|
||||
self.dest_addr = self.raw[2]
|
||||
self.seq_num = self.raw[3]
|
||||
self.protocol = self.raw[4]
|
||||
self.mac = self.raw[5]
|
||||
|
||||
-- element 6 must be a table
|
||||
if type(self.raw[6]) == "table" then
|
||||
self.length = #self.raw[6]
|
||||
self.payload = self.raw[6]
|
||||
-- element 5 must be a table
|
||||
if type(self.raw[5]) == "table" then
|
||||
self.length = #self.raw[5]
|
||||
self.payload = self.raw[5]
|
||||
end
|
||||
else
|
||||
self.src_addr = nil
|
||||
self.dest_addr = nil
|
||||
self.seq_num = nil
|
||||
self.protocol = nil
|
||||
self.mac = ""
|
||||
self.length = 0
|
||||
self.payload = {}
|
||||
end
|
||||
@ -228,7 +225,6 @@ function comms.scada_packet()
|
||||
type(self.dest_addr) == "number" and
|
||||
type(self.seq_num) == "number" and
|
||||
type(self.protocol) == "number" and
|
||||
type(self.mac) == "string" and
|
||||
type(self.payload) == "table"
|
||||
end
|
||||
end
|
||||
@ -236,20 +232,12 @@ function comms.scada_packet()
|
||||
return self.valid
|
||||
end
|
||||
|
||||
-- set message authentication code
|
||||
function public.set_mac(code)
|
||||
self.mac = code
|
||||
self.raw = { self.src_addr, self.dest_addr, self.seq_num, self.protocol, self.mac, self.payload }
|
||||
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.raw_verifiable() return { self.src_addr, self.dest_addr, self.seq_num, self.protocol, "", self.payload } end
|
||||
|
||||
---@nodiscard
|
||||
function public.local_channel() return self.modem_msg_in.s_channel end
|
||||
@ -268,8 +256,6 @@ function comms.scada_packet()
|
||||
---@nodiscard
|
||||
function public.protocol() return self.protocol end
|
||||
---@nodiscard
|
||||
function public.mac() return self.mac end
|
||||
---@nodiscard
|
||||
function public.length() return self.length end
|
||||
---@nodiscard
|
||||
function public.data() return self.payload end
|
||||
@ -277,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<br>
|
||||
-- modeled after MODBUS TCP packet
|
||||
---@nodiscard
|
||||
|
@ -55,7 +55,7 @@ end
|
||||
---@nodiscard
|
||||
---@param message string initial value concatenated with ciphertext
|
||||
local function compute_hmac(message)
|
||||
local start = util.time_ms()
|
||||
-- local start = util.time_ms()
|
||||
|
||||
c_eng.hmac.init()
|
||||
c_eng.hmac.update(stream.fromString(message))
|
||||
@ -63,7 +63,7 @@ local function compute_hmac(message)
|
||||
|
||||
local hash = c_eng.hmac.asHex()
|
||||
|
||||
log.debug("compute_hmac(): hmac-md5 = " .. util.strval(hash) .. " (took " .. (util.time_ms() - start) .. "ms)")
|
||||
-- log.debug("compute_hmac(): hmac-md5 = " .. util.strval(hash) .. " (took " .. (util.time_ms() - start) .. "ms)")
|
||||
|
||||
return hash
|
||||
end
|
||||
@ -166,20 +166,22 @@ function network.nic(modem)
|
||||
-- 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 raw_sendable
|
||||
---@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()
|
||||
local message = textutils.serialize(packet.raw_verifiable(), { allow_repetitions = true, compact = true })
|
||||
local computed_hmac = compute_hmac(message)
|
||||
-- local start = util.time_ms()
|
||||
tx_packet = comms.authd_packet()
|
||||
|
||||
packet.set_mac(computed_hmac)
|
||||
---@cast tx_packet authd_packet
|
||||
tx_packet.make(packet, compute_hmac)
|
||||
|
||||
log.debug("crypto.modem.transmit: data processing took " .. (util.time_ms() - start) .. "ms")
|
||||
-- log.debug("crypto.modem.transmit: data processing took " .. (util.time_ms() - start) .. "ms")
|
||||
end
|
||||
|
||||
modem.transmit(dest_channel, local_channel, packet.raw_sendable())
|
||||
modem.transmit(dest_channel, local_channel, tx_packet.raw_sendable())
|
||||
end
|
||||
end
|
||||
|
||||
@ -197,25 +199,30 @@ function network.nic(modem)
|
||||
if self.connected then
|
||||
local s_packet = comms.scada_packet()
|
||||
|
||||
-- parse packet as generic SCADA packet
|
||||
s_packet.receive(side, sender, reply_to, message, distance)
|
||||
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 s_packet.is_valid() then
|
||||
if c_eng.hmac ~= nil then
|
||||
local start = util.time_ms()
|
||||
local packet_hmac = s_packet.mac()
|
||||
local computed_hmac = compute_hmac(textutils.serialize(s_packet.raw_verifiable(), { allow_repetitions = true, compact = true }))
|
||||
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")
|
||||
packet = s_packet
|
||||
-- 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")
|
||||
-- log.debug("crypto.modem.receive: HMAC failed verification in " .. (util.time_ms() - start) .. "ms")
|
||||
end
|
||||
else
|
||||
packet = s_packet
|
||||
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
|
||||
|
@ -78,13 +78,10 @@ function supervisor.comms(_version, nic, 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()
|
||||
|
Loading…
Reference in New Issue
Block a user