我不确定您的设计和要求,所以其中一些可能不符合要求;希望其中一些也有用。
首先,我在理解攻击方面有点困难;我可能只是错过了一些东西。Alice 向 Bob 发送一条消息,其中包括一个计数器、一个有效负载和一个 (counter||payload) 的 HMAC。Eve 截取并重播消息。鲍勃看到了那个,所以他把它扔掉了。Eve 尝试使用 counter+1 计算新消息,但她无法计算此消息的 HMAC(因为计数器不同),因此 Bob 将其丢弃。只要有可用的秘密,Eve 就永远无法伪造消息,并且重播消息无济于事。
那么什么是“已知密钥”?攻击者是否知道此密钥?(如果是,那么他可以轻松伪造消息,因此 HMAC 没有帮助。)既然您注意到您有 DH,您是否使用它来协商密钥?
假设我错过了攻击,思考你的问题的其余部分:如果你有一个共享的秘密,为什么不使用它来加密消息,或者至少是时间+计数器?通过将时间和计数器加密在一起,彩虹表应该是不切实际的。
如果有一些共享密钥,但您没有可用于加密的处理器,您仍然可以执行 MD5(secret+counter) 之类的操作来防止攻击者提前猜测(您的 HMAC-MD5 必须已经有可用的 MD5) .
我之前在没有共享秘密和 DH 的情况下攻击过这个问题。在这种情况下,嵌入式设备需要每个设备的公钥/私钥对(理想情况下是在制造过程中安装,但可以在第一次开机时计算并存储在非易失性存储器中;随机性很难,一种选择是让服务器提供随机数服务;如果您在芯片上有任何唯一的非公开信息,例如序列号,也可用于为您的密钥播种。最坏的情况是,您可以使用您的 MAC 加上时间加上尽可能多的时间熵,因为你可以从网络中搜刮。)
使用公钥/私钥,而不是使用 HMAC,设备只需对其消息进行签名,并在其第一条消息中将其公钥发送到服务器。公钥成为设备的标识符。这种方法的好处是没有协商阶段。设备可以开始通话,如果服务器从未听说过这个公钥,它会创建一个新记录。
这里有一个小的拒绝服务问题,因为攻击者可能会用垃圾填充您的数据库。最好的解决方案是在制造过程中生成密钥,然后立即将公钥插入到您的数据库中。这对一些合同制造商来说是不切实际的。因此,您可以诉诸于包含一个共享密钥,设备可以使用该密钥在第一次向服务器验证自己的身份。这很弱,但对于绝大多数情况来说可能已经足够了。