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()
|
loop_clock.start()
|
||||||
|
|
||||||
-- send updated data
|
-- send updated data
|
||||||
if not nic.connected() then
|
if nic.connected() then
|
||||||
if plc_comms.is_linked() then
|
if plc_comms.is_linked() then
|
||||||
smem.q.mq_comms_tx.push_command(MQ__COMM_CMD.SEND_STATUS)
|
smem.q.mq_comms_tx.push_command(MQ__COMM_CMD.SEND_STATUS)
|
||||||
else
|
else
|
||||||
|
@ -149,7 +149,6 @@ function comms.scada_packet()
|
|||||||
dest_addr = comms.BROADCAST,
|
dest_addr = comms.BROADCAST,
|
||||||
seq_num = -1,
|
seq_num = -1,
|
||||||
protocol = PROTOCOL.SCADA_MGMT,
|
protocol = PROTOCOL.SCADA_MGMT,
|
||||||
mac = "",
|
|
||||||
length = 0,
|
length = 0,
|
||||||
payload = {}
|
payload = {}
|
||||||
}
|
}
|
||||||
@ -170,7 +169,7 @@ function comms.scada_packet()
|
|||||||
self.protocol = protocol
|
self.protocol = protocol
|
||||||
self.length = #payload
|
self.length = #payload
|
||||||
self.payload = 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
|
end
|
||||||
|
|
||||||
-- parse in a modem message as a SCADA packet
|
-- 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")
|
-- log.debug("comms.scada_packet.receive(): discarding packet with distance " .. distance .. " outside of trusted range")
|
||||||
else
|
else
|
||||||
if type(self.raw) == "table" then
|
if type(self.raw) == "table" then
|
||||||
if #self.raw == 6 then
|
if #self.raw == 5 then
|
||||||
self.src_addr = self.raw[1]
|
self.src_addr = self.raw[1]
|
||||||
self.dest_addr = self.raw[2]
|
self.dest_addr = self.raw[2]
|
||||||
self.seq_num = self.raw[3]
|
self.seq_num = self.raw[3]
|
||||||
self.protocol = self.raw[4]
|
self.protocol = self.raw[4]
|
||||||
self.mac = self.raw[5]
|
|
||||||
|
|
||||||
-- element 6 must be a table
|
-- element 5 must be a table
|
||||||
if type(self.raw[6]) == "table" then
|
if type(self.raw[5]) == "table" then
|
||||||
self.length = #self.raw[6]
|
self.length = #self.raw[5]
|
||||||
self.payload = self.raw[6]
|
self.payload = self.raw[5]
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.src_addr = nil
|
self.src_addr = nil
|
||||||
self.dest_addr = nil
|
self.dest_addr = nil
|
||||||
self.seq_num = nil
|
self.seq_num = nil
|
||||||
self.protocol = nil
|
self.protocol = nil
|
||||||
self.mac = ""
|
|
||||||
self.length = 0
|
self.length = 0
|
||||||
self.payload = {}
|
self.payload = {}
|
||||||
end
|
end
|
||||||
@ -228,7 +225,6 @@ function comms.scada_packet()
|
|||||||
type(self.dest_addr) == "number" and
|
type(self.dest_addr) == "number" and
|
||||||
type(self.seq_num) == "number" and
|
type(self.seq_num) == "number" and
|
||||||
type(self.protocol) == "number" and
|
type(self.protocol) == "number" and
|
||||||
type(self.mac) == "string" and
|
|
||||||
type(self.payload) == "table"
|
type(self.payload) == "table"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -236,20 +232,12 @@ function comms.scada_packet()
|
|||||||
return self.valid
|
return self.valid
|
||||||
end
|
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 --
|
-- public accessors --
|
||||||
|
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
function public.modem_event() return self.modem_msg_in end
|
function public.modem_event() return self.modem_msg_in end
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
function public.raw_sendable() return self.raw end
|
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
|
---@nodiscard
|
||||||
function public.local_channel() return self.modem_msg_in.s_channel end
|
function public.local_channel() return self.modem_msg_in.s_channel end
|
||||||
@ -268,8 +256,6 @@ function comms.scada_packet()
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
function public.protocol() return self.protocol end
|
function public.protocol() return self.protocol end
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
function public.mac() return self.mac end
|
|
||||||
---@nodiscard
|
|
||||||
function public.length() return self.length end
|
function public.length() return self.length end
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
function public.data() return self.payload end
|
function public.data() return self.payload end
|
||||||
@ -277,6 +263,112 @@ function comms.scada_packet()
|
|||||||
return public
|
return public
|
||||||
end
|
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>
|
-- MODBUS packet<br>
|
||||||
-- modeled after MODBUS TCP packet
|
-- modeled after MODBUS TCP packet
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
|
@ -55,7 +55,7 @@ end
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
---@param message string initial value concatenated with ciphertext
|
---@param message string initial value concatenated with ciphertext
|
||||||
local function compute_hmac(message)
|
local function compute_hmac(message)
|
||||||
local start = util.time_ms()
|
-- local start = util.time_ms()
|
||||||
|
|
||||||
c_eng.hmac.init()
|
c_eng.hmac.init()
|
||||||
c_eng.hmac.update(stream.fromString(message))
|
c_eng.hmac.update(stream.fromString(message))
|
||||||
@ -63,7 +63,7 @@ local function compute_hmac(message)
|
|||||||
|
|
||||||
local hash = c_eng.hmac.asHex()
|
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
|
return hash
|
||||||
end
|
end
|
||||||
@ -166,20 +166,22 @@ function network.nic(modem)
|
|||||||
-- send a packet, with message authentication if configured
|
-- send a packet, with message authentication if configured
|
||||||
---@param dest_channel integer destination channel
|
---@param dest_channel integer destination channel
|
||||||
---@param local_channel integer local 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)
|
function public.transmit(dest_channel, local_channel, packet)
|
||||||
if self.connected then
|
if self.connected then
|
||||||
|
local tx_packet = packet ---@type authd_packet|scada_packet
|
||||||
|
|
||||||
if c_eng.hmac ~= nil then
|
if c_eng.hmac ~= nil then
|
||||||
local start = util.time_ms()
|
-- local start = util.time_ms()
|
||||||
local message = textutils.serialize(packet.raw_verifiable(), { allow_repetitions = true, compact = true })
|
tx_packet = comms.authd_packet()
|
||||||
local computed_hmac = compute_hmac(message)
|
|
||||||
|
|
||||||
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
|
end
|
||||||
|
|
||||||
modem.transmit(dest_channel, local_channel, packet.raw_sendable())
|
modem.transmit(dest_channel, local_channel, tx_packet.raw_sendable())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -197,25 +199,30 @@ function network.nic(modem)
|
|||||||
if self.connected then
|
if self.connected then
|
||||||
local s_packet = comms.scada_packet()
|
local s_packet = comms.scada_packet()
|
||||||
|
|
||||||
-- parse packet as generic SCADA packet
|
|
||||||
s_packet.receive(side, sender, reply_to, message, distance)
|
|
||||||
|
|
||||||
if s_packet.is_valid() then
|
|
||||||
if c_eng.hmac ~= nil then
|
if c_eng.hmac ~= nil then
|
||||||
local start = util.time_ms()
|
-- parse packet as an authenticated SCADA packet
|
||||||
local packet_hmac = s_packet.mac()
|
local a_packet = comms.authd_packet()
|
||||||
local computed_hmac = compute_hmac(textutils.serialize(s_packet.raw_verifiable(), { allow_repetitions = true, compact = true }))
|
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
|
if packet_hmac == computed_hmac then
|
||||||
log.debug("crypto.modem.receive: HMAC verified in " .. (util.time_ms() - start) .. "ms")
|
-- log.debug("crypto.modem.receive: HMAC verified in " .. (util.time_ms() - start) .. "ms")
|
||||||
packet = s_packet
|
s_packet.receive(side, sender, reply_to, textutils.unserialize(msg), distance)
|
||||||
else
|
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
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
packet = s_packet
|
-- parse packet as a generic SCADA packet
|
||||||
end
|
s_packet.receive(side, sender, reply_to, message, distance)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if s_packet.is_valid() then packet = s_packet end
|
||||||
end
|
end
|
||||||
|
|
||||||
return packet
|
return packet
|
||||||
|
@ -78,13 +78,10 @@ function supervisor.comms(_version, nic, fp_ok)
|
|||||||
---@param distance integer
|
---@param distance integer
|
||||||
---@return modbus_frame|rplc_frame|mgmt_frame|crdn_frame|nil packet
|
---@return modbus_frame|rplc_frame|mgmt_frame|crdn_frame|nil packet
|
||||||
function public.parse_packet(side, sender, reply_to, message, distance)
|
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 pkt = nil
|
||||||
local s_pkt = comms.scada_packet()
|
|
||||||
|
|
||||||
-- parse packet as generic SCADA packet
|
if s_pkt then
|
||||||
s_pkt.receive(side, sender, reply_to, message, distance)
|
|
||||||
|
|
||||||
if s_pkt.is_valid() then
|
|
||||||
-- get as MODBUS TCP packet
|
-- get as MODBUS TCP packet
|
||||||
if s_pkt.protocol() == PROTOCOL.MODBUS_TCP then
|
if s_pkt.protocol() == PROTOCOL.MODBUS_TCP then
|
||||||
local m_pkt = comms.modbus_packet()
|
local m_pkt = comms.modbus_packet()
|
||||||
|
Loading…
Reference in New Issue
Block a user