Если речь идет о сигнализации Starline A91, то у меня сейчас на реверсинге прошивка от китайского клона трансивера (антенного блока) для A91.
Клон не без греха. Через некоторое время перестает работать. Причина, как я подозреваю - неверная реализация алгоритма прыгающей частоты при приеме отгадки от брелка. Эту часть придется разобрать самому. Но мне уже известно о алгоритмах шифрования и некоторых пакетах.
Например, я знаю, что система использует три ключа. Один четырехбайтный, для протокола радиообмена и два восьмибайтных для общения между самим трансивером, главным блоком и брелком. То есть, ими шифруется полезная нагрузка. Все ключи при прописывании генерирует центральный блок, запоминает у себя и отдает их трансиверу. Трансивер в свою очередь их тоже запоминает и передает брелку. Вообще, если знать ID брелка, то короткий ключ подбирается легко. Но для угонщика сложность состоит в том, что он не знает ID брелка и даже при таком простом шифровании, подобрать ключ просто нереально, потому что он не знает, что он должен получить в результате того же брутфорса.
В протоколе радиообмена всегда используются две базовые частоты, которые выбираются при прописывании брелка и зависят от двух последних байт короткого (четырехбайтного) ключа. Принцип примерно такой:
Радиопакет состоит из следующих трех частей:
1. Преамбула 32 бита, значение всегда одно: 0x55555555. Нужна она для того, чтобы модем радиочипа настроился на прием данных.
2. Синхрослово (4 байта). Значение тоже всегда одно: 0x2B, 0xC6, 0x76, 0x55. Оно принимается радиочипом для контроля корректной настройки модема при приеме преамбулы и служит так же своеобразным идентификатором, отсеивающим любой другой мусор из эфира.
3. Полезные данные - 10 байт. Последний является контрольной суммой и считается простым суммированием остальных 9 байт данных.
Такой формат радиопакета полностью совместим с чипами, вроде Si4432 или Si4463 при соответствующей их настройке.
Первые две части обрабатываются радиочипом аппаратно, последняя часть отдается микроконтроллеру.
Сам обмен выглядит так:
1. При нажатии на любую кнопку брелка, брелок отправляет запрос на обмен.
В этом пакете он шифрует свой ID (три байта) двумя байтами ключа и счетчиком (тоже три байта), значения которого он помещает в тот же пакет.
2. Приемник, приняв пакет, дешифрует ID, сверяет со списком сохраненных ID у себя (при прописывании брелка, брелок отдает свой ID трансиверу)
и если таковой имеется, формирует загадку и отправляет ее брелку на второй базовой частоте.
3. Брелок разгадывает ее и отправляет отгадку вместе с командой (команда нажатой кнопки или комбинации кнопок) на трех разных частотах, которые вычисляются по пока неизвестному мне алгоритму.
4. Трансивер приняв все три пакета, проверяет отгадку (китайцы проверку тупо проигнорировали) и если она верная, пересылает команду центральному блоку.
5. Центральный блок дешифрует команду, выполняет ее и присылает трансиверу свое состояние.
6. Трансивер пересылает ответ от центрального блока брелку на второй базовой частоте.
Расшифровка ID брелка в первом пакете выглядит так:
function CalculateCRC8(data)
local crc = 0;
for i = 1, (#data - 1), 1 do
crc = data[i] + crc & 0xFF;
end
return crc;
end
function DecryptID(data, idKey)
local idResult = {};
idResult[1] = data[1] ~ data[5] ~ idKey[1] & 0xFF;
idResult[2] = data[2] ~ data[6] ~ idKey[2] & 0xFF;
idResult[3] = data[3] ~ data[7] ~ idKey[1] ~ idKey[2] & 0xFF;
return idResult;
end
--------------------------------------------------
-- DATA
local dataPack_1 = {0x62, 0xe5, 0x9b, 0x30, 0xea, 0xb3, 0x89, 0x13, 0x0f, 0x5a};
local dataPack_2 = {0x0f, 0xc9, 0x1e, 0x48, 0x87, 0x9f, 0x0c, 0x13, 0x0d, 0x90};
local dataPack_3 = {0x14, 0xe2, 0x28, 0x75, 0x9c, 0xb4, 0x3a, 0x13, 0x09, 0x39};
local crIdKey = {0x2B, 0x9B, 0x25, 0xCB};
local rcID = {0xA3, 0xCD, 0xA2};
-- Packet selection
local dataPack = dataPack_1;
-- Check CRC8
local cCrc = CalculateCRC8(dataPack);
if(dataPack[#dataPack] == cCrc) then
print("CRC is valid. CRC value = 0x"..string.format("%02X", cCrc));
else
print(string.format("CRC ERROR, received value = 0x%02X, calculated value = 0x%02X", dataPack[#dataPack], cCrc));
end
-- Decrypt ID
local decryptedId = DecryptID(dataPack, crIdKey);
if(decryptedId[1] == rcID[1] and decryptedId[2] == rcID[2] and decryptedId[3] == rcID[3]) then
print(string.format("ID is valid. Decrypted ID = %02X %02X %02X", decryptedId[1], decryptedId[2], decryptedId[3]));
else
print(string.format("ID is no valid! Decrypted ID = %02X %02X %02X", decryptedId[1], decryptedId[2], decryptedId[3]));
end
В примере (написан на языке Lua) три варианта первых пакетов от брелка и все они содержат один и тот же ID.
Первые три байта данных ксорятся с 5, 6 и 7 байтом соответственно и еще с байтами ключа. Причем следует обратить внимание, что первая пара байт ксорится с первым байтом ключа, вторая со вторым и третья с первым и вторым байтом ключа.
Ответ от трансивера с загадкой выглядит по другому.
Первый байт я пока не разобрал, откуда берется.
Второй, 3 и 4 - это зашифрованный ID брелка (ксор ID с первым байтом ключа)
5 и 6 - это загадка. Берется случайное число, прибавляется к нему 0x55 и это будет 5 байт.
К этому же случайному числу прибавляется 0xAB и это будет 6 байт. Не знаю, на сколько верно она формируется (ибо это китайский реверс), но брелок реагирует на этот пакет и шлет отгадку на других частотах.
7, 8 и 9 байт пустые.
10 байт - контрольная сумма.
Пакеты отгадок я еще не поймал. Вижу их на спектре SDR# но еще не разобрался, как в GNU radio организовать АПЧ во всей прослушиваемой полосе. Китайцы тупо выбирают коэффициенты перестройки из массива констант без какой-либо синхронизации, что совсем неверно. Частоты считаются явно по другому и как то должны быть синхронизированы, так как и брелок и трансивер должны перестраиваться на одни и те же частоты. В этом и косяк китайской реплики оригинального трансивера. Клон работал но до поры до времени. Возможно, в вычислении частот участвуют байты загадки, но это еще предстоит выяснить.