我正在构建一个基于 Arduino 的无线电车库开门器,为了保护它免受重放攻击,我想出了这个算法:
- 发送者发起通信
- 接收方发送一个随机的 32 位数字与密钥进行异或运算
- 发送者使用相同的密钥反转 XOR 操作,解决挑战(例如:挑战 ^ 2 - 5),XORes 并将结果与命令一起发送给接收者(gate up 或 gate down)
- 接收者将响应与它自己对挑战的计算进行比较,如果它们匹配,则执行命令。
我很好奇,上述步骤是否确保攻击者无法猜测响应?
我正在构建一个基于 Arduino 的无线电车库开门器,为了保护它免受重放攻击,我想出了这个算法:
我很好奇,上述步骤是否确保攻击者无法猜测响应?
不。
让我们把它写下来:
攻击者可以看到C和R。如果攻击者然后异或这两个值:
C ⊕ R = (q 2 - 5) ⊕ K ⊕ q ⊕ K
由于我们与K进行了两次异或运算,因此我们可以删除这些操作。这为攻击者提供了以下信息:
C ⊕ R = (q 2 - 5) ⊕ q
在 32 位空间中,对于C ⊕ R的任何给定值, q只有几个值。事实上,这是一个非常简单的操作,只需要蛮力:只需尝试所有q值,直到找到所有匹配的值。
这为您提供了一些可能的q值,即随机数。由于C = q ⊕ K,只需为每个候选q计算C ⊕ q即可获得少量可能的K值。第二次重复这个过程,看看在两次运行中出现了哪个候选K值:这给了你K。
我什至写了一个 PoC!
// our key!
int k = 0xBAD1DEA;
void Main()
{
// output the key just so we can see it in the output
Console.WriteLine("Key is: 0x{0:X8}", k);
int challenge = GenerateChallenge();
int response = GenerateResponse(challenge);
Console.WriteLine();
Console.WriteLine("Cracking the challenge and response...");
// this is the attacker: they know only the challenge and respoonse!
Crack(challenge, response);
}
int GenerateChallenge()
{
Random rng = new Random();
// I'm keeping the random number small-ish to avoid the c^2 operation from overflowing
// this is just a limitation of the fact that .NET has sane integer types that don't wrap on multiplication overflows
int q = rng.Next(0, 10000000);
Console.WriteLine("I picked q={0}", q);
int challenge = k ^ q;
return challenge;
}
int GenerateResponse(int c)
{
c ^= k;
return ((c * c) - 5) ^ k;
}
void Crack(int c, int r)
{
int c_r = c ^ r;
// try all possible 'q' values.
for (int q = 1; q < int.MaxValue; q++)
{
if ((((q * q) - 5) ^ q) == c_r)
{
// got a match, output it
Console.WriteLine("q candidate: {0}", q);
Console.WriteLine("k candidate: 0x{0:X8}", q ^ c);
}
}
}
样本输出:
Key is: 0x0BAD1DEA
I picked q=2847555
Cracking the challenge and response...
q candidate: 2847555
k candidate: 0x0BAD1DEA
“破解”过程在我的系统上花费了不到一秒钟的时间。
编辑:因为这显然不清楚:你没有对真实系统进行任何暴力破解。这种方法根本不涉及您向接收者发送任何数据。您只需使用软件定义无线电 (SDR) 坐在那里,捕捉车主打开车库门时产生的信号。然后,您从这些信号中提取挑战和响应值 - 它们是C和R。给定C和R,您可以使用上述过程为该特定挑战/响应对计算一些可能的q值。在某些情况下你只会得到一个,在某些情况下你可能会得到 2 或 3。计算每个候选q的q ⊕ C获取候选K值的列表。如果你得到多个,等待他们再次打开他们的车库并捕获另一个C和R对,重新运行该过程,并查看哪些候选K值第一次匹配 - 这将为您提供真正的K值。一旦你有了它,你就拥有了模拟真正的开瓶器设备所需的一切。由于您知道K的值,因此您每次都可以正确回复。
首先,您需要一个密码函数,其输入和输出之间的关系不容易辨别。XOR 只是不会削减它。加密数据的一种缓慢但有效的方法是将 32 位值分成两半,H 和 L,并重复以下几次:
如果使用上述方法并在其核心采用一种不错的加密方法,则结果将是一个安全的 32 位到 32 位映射。通过交换 H 和 L,执行上述过程,然后将它们交换回来,可以获得逆映射。
32 位有效负载有点小,但如果挑战从不重复,则可以提供合理的安全级别。这可以通过让发送者对已发送的质询数量进行终生计数,并将其用作要加密和验证的质询数据来实现。