4 回答
我假设,每个节点“知道”它应该从中获取命令的节点 - 在这种情况下,接收节点为它将从中获取命令的每个节点存储一个(简单)密钥,然后将三个字段添加到协议中:
- 一个盐(发件人创建的随机数)
- 序号
- 身份验证字段
发送者和接收者都为 tx->rx 关系存储最后使用的序列号,发送者在每个命令中都会增加它。
发送者和接收者都创建连接的哈希(SHA1?)SequenceNumber+Command+SequenceNumber+salt+nodekey
编辑: nodekey
是发送节点的密钥
发送方将此作为身份验证字段发送,接收方将其与身份验证字段进行检查并仅在序列号高于 LRU 序列号且身份验证字段检查正常时接受命令。
这对于重放攻击是安全的,因为它涉及序列号重用。
编辑:
评论中有关于序列号同步丢失的担忧,但建议的解决方案对此有弹性:只有发送方会增加 SN,接收方将接受高于上次使用的所有 SN。消息的丢失会使 SN 跳变,但仍会被接受为高于 LRU。
假设我使用类似 MD5 的方式加密消息,我将传输类似“767b79ebb8061054d3ad1eaef428b469”的内容,
您不使用 MD5 加密。您发送命令的哈希值。这意味着在接收端,您需要有一个反向查找表来将您发送的消息摘要映射到相应的命令。
攻击者只需要复制该字符串并重新发送即可获得相同的结果。
这是一个有效的问题,它属于Replay Attack的类别。有很多方法可以解决这个问题,但您需要付出相当多的努力来重新设计您的发射器和接收器
由于您使用的是微控制器,因此我假设您没有最先进的加密功能,而易于实现的东西通常是 imo 的最佳方式。
如果您的控制器上有可用的 MD5,我会使用 Eugen Rieck 方法,但我只想说,您只能使用每个键一次,例如 10 天或其他时间(取决于您发送的数据量)。
这使得它已经更加安全,除非他们进行一些长期聆听,否则他们将无法使用您的命令。
请记住,这是一种通过默默无闻的安全性,如果他们的攻击者知道它只有 10 天的冷却时间,它就不会起作用。
如果您的设备上确实有加密功能和当前时间,我只会在当前时间使用基本的基本加密功能。
您应该考虑使用某种依赖于密钥的加密。当然,关键可能必须以两个控制器可以保持同步的某种方式确定——也许使用一天中的时间的某种方式就足够了。类似于 PHP 的time()
函数,四舍五入到最接近的百位。每个控制器在收到信号时都可以检查当前的舍入时间戳和之前的时间戳,因此如果攻击者收到加密信号,它最多只能重复使用 200 秒。根据传输每个信号所需的时间和所需的安全级别(以及可能错过信号的逃脱频率),您可能会舍入到十到五秒。使用一些伪代码(四舍五入到十):
发送:
signal=encrypt(outgoing, round(time, 10))
sendSignal(signal)
接收:
signal=decrypt(incoming, round(time, 10))
if (invalid(signal)) {signal=decrypt(incoming, round(time, 10)-10)}
interpretSignal(signal)
如第二行所示,您需要某种方法来确定解密信号是否有效。
这就是我想出的一种应该始终相当同步的通用密钥机制。但是,基本思想是使用发送者和接收者都知道或可以确定的频繁更改的密钥对信号进行加密。