私はArduinoベースのラジオガレージのドア開閉装置を構築しています。それをリプレイ攻撃から保護するために、次のアルゴリズムを考え出しました。
興味があります。上記の手順により、攻撃者が応答を推測できないようになっていますか?
番号。
それを書きましょう:
攻撃者は[〜#〜] c [〜#〜]と[〜#〜] r [〜#〜]の両方を見ることができます。攻撃者が2つの値をxorsした場合:
C⊕R =(q2 -5)⊕K⊕q⊕K
[〜#〜] k [〜#〜]で2回xorしているので、これらの操作を削除できます。これにより、攻撃者は次のようになります。
C⊕R =(q2 -5)⊕q
32ビット空間のC⊕Rの特定の値について、qの値はほんのわずかです。実際、これはブルートフォースするだけの簡単な操作です。一致するすべての値が見つかるまで、すべてのq値を試してください。
これにより、乱数であるqの考えられる値が得られます。 C = q⊕Kなので、候補ごとにC⊕qを計算する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
私のシステムでは、「クラッキング」プロセスに1秒もかかりませんでした。
編集:これは明らかに明確ではなかったため、実際のシステムに対して何も総当たりではありません。このアプローチでは、レシーバーにデータを送信する必要はまったくありません。あなたは単にソフトウェア無線(SDR)をそこに座って、所有者がガレージのドアを開けたときに生成される信号をキャプチャします。次に、それらの信号からチャレンジとレスポンスの値を抽出します。これらは[〜#〜] c [〜#〜]および[〜#〜] r [〜#〜]です。 =。与えられた[〜#〜] c [〜#〜]および[〜#〜] r [〜#〜]上記のプロセスを使用して、いくつかの可能なものを計算できます- q特定のチャレンジ/レスポンスのペアの値。 1つしか得られない場合もあれば、2つまたは3つが得られる場合もあります。計算q⊕C候補ごとにq候補のリストを取得- [〜#〜] k [〜#〜]値。あなたが複数を取得した場合、彼らが彼らのガレージを再び開いて、別の[〜#〜] c [〜#〜]と[〜#〜] r [〜# 〜]ペアにして、プロセスを再実行し、どの候補を確認します[〜#〜] k [〜#〜]値が最初に一致する-これは本当のことをします- [〜#〜] k [〜#〜]値。それができたら、実際のオープナーデバイスを偽装するために必要なものがすべて揃います。 [〜#〜] k [〜#〜]の値がわかっているので、毎回正しく返信できます。
まず、入力と出力の関係を簡単に識別できない暗号関数が必要です。 XORはそれを切り捨てません。データを暗号化する遅いが効果的な方法は、32ビット値を2つの半分HとLに分割し、以下を数回繰り返すことです。
適切な暗号化方式をコアに使用して上記のアプローチを使用すると、結果は安全な32ビットから32ビットへのマッピングになります。逆マッピングは、HとLを交換し、上記の手順を実行して、それらを元に戻すことで取得できます。
32ビットのペイロードは少し小さいですが、チャレンジが繰り返されない場合は、妥当なレベルのセキュリティを提供できます。これは、送信者に送信されたチャレンジのライフタイムカウントを保持させ、それを暗号化および検証するチャレンジデータとして使用することで実現できます。