No.
Vamos a escribirlo:
-
C es el mensaje de desafío
-
R es el mensaje de respuesta
-
K es la clave secreta
-
C = q ⊕ K donde q es un número aleatorio.
-
R = ((C ⊕ K) 2 - 5) ⊕ K , o si saltamos el paso de descifrado: R = (q 2 - 5) ⊕ K .
El atacante puede ver tanto C como R . Si el atacante entonces xors los dos valores:
C ⊕ R = (q 2 - 5) ⊕ K ⊕ q ⊕ K
Ya que estamos xoring con K dos veces, solo podemos abandonar esas operaciones. Esto le da al atacante lo siguiente:
C ⊕ R = (q 2 - 5) ⊕ q
Solo hay unos pocos valores para q para cualquier valor dado de C ⊕ R en el espacio de 32 bits. De hecho, es una operación lo suficientemente fácil como para simplemente forzar la fuerza bruta: solo intente todos los valores de q hasta que encuentre todos los valores que coincidan.
Esto le da un valor posible de q , el número aleatorio. Dado que C = q ⊕ K , simplemente calcule C ⊕ q para cada candidato q para obtener un pequeño número de K valores. Repita este proceso por segunda vez y vea qué valor candidato de K apareció en ambas ejecuciones: esto le da a usted K .
Incluso escribí un 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);
}
}
}
Salida de muestra:
Key is: 0x0BAD1DEA
I picked q=2847555
Cracking the challenge and response...
q candidate: 2847555
k candidate: 0x0BAD1DEA
El proceso de "cracking" tomó menos de un segundo en mi sistema.
EDITAR: ya que aparentemente esto no estaba claro: no estás forzando nada contra el sistema real. Este enfoque no implica que envíes ningún dato al receptor en absoluto. Simplemente, siéntese allí con una radio definida por software (SDR) y capture las señales producidas cuando el propietario abre la puerta de su garaje. Luego extrae los valores de desafío y respuesta de esas señales, que son C y R . Dados C y R puede usar el proceso anterior para calcular algunos valores posibles de q para ese par de desafío / respuesta en particular. En algunos casos solo obtendrá uno, en otros casos puede obtener 2 o 3. Compute q ⊕ C para cada candidato q para obtener una lista de candidatos K valores. Si obtiene más de uno, espere a que vuelvan a abrir su garaje y capture otro par C y R , vuelva a ejecutar el proceso y vea qué candidato Los valores de K coinciden con la primera vez; esto le dará el valor real de K . Una vez que tienes eso, tienes todo lo que necesitas para personificar el dispositivo de apertura real. Puede responder correctamente cada vez que conozca el valor de K .