// // Created by cfif on 28.01.2026. // #include #include /** * CCU Secure Access Algorithm * Реализация алгоритма генерации ключа по seed для диагностического доступа * Согласно спецификации NAMI UMP vehicle, версия 1.1 */ /* Позиции битов коэффициентов в seed */ #define COEFF1_POS 20 /* Направление сдвига (0 - влево, 1 - вправо) */ #define COEFF2_POS 7 /* Старший бит количества сдвигов */ #define COEFF3_POS 11 /* */ #define COEFF4_POS 5 /* */ #define COEFF5_POS 8 /* Младший бит количества сдвигов */ #define COEFF6_POS 22 /* Старший бит операции инверсии */ #define COEFF7_POS 1 /* Младший бит операции инверсии */ #define COEFF8_POS 21 /* Старший бит побитовой операции */ #define COEFF9_POS 6 /* Младший бит побитовой операции */ /* Позиции битов для инверсии */ #define INV_A_BITS ((1U << 6) | (1U << 15) | (1U << 17)) #define INV_B_BITS ((1U << 11) | (1U << 9) | (1U << 16)) #define INV_C_BITS ((1U << 7) | (1U << 10) | (1U << 13) | (1U << 4)) /** * Извлечение бита из значения * position: 0 = младший бит (LSB), 31 = старший бит (MSB) */ static inline uint32_t extract_bit(uint32_t value, int position) { return (value >> position) & 1U; } /** * Циклический сдвиг вправо (rotation) */ static inline uint32_t rotate_right(uint32_t value, int bits) { bits = bits % 32; if (bits == 0) return value; return (value >> bits) | (value << (32 - bits)); } /** * Циклический сдвиг влево (rotation) */ static inline uint32_t rotate_left(uint32_t value, int bits) { bits = bits % 32; if (bits == 0) return value; return (value << bits) | (value >> (32 - bits)); } /** * Генерация 32-битного ключа из 32-битного seed * * Параметры: * seed - случайное значение от ECU (32 бита) * * Возвращает: * 32-битный ключ для ответа ECU */ uint32_t generate_key(uint32_t seed) { /* Извлечение коэффициентов из seed */ uint32_t coeff1 = extract_bit(seed, COEFF1_POS); /* Направление сдвига */ /* Коэффициенты 2-5: количество циклических сдвигов (coeff2 - старший бит) */ uint32_t coeff2 = extract_bit(seed, COEFF2_POS); uint32_t coeff3 = extract_bit(seed, COEFF3_POS); uint32_t coeff4 = extract_bit(seed, COEFF4_POS); uint32_t coeff5 = extract_bit(seed, COEFF5_POS); uint32_t num_shifts = (coeff2 << 3) | (coeff3 << 2) | (coeff4 << 1) | coeff5; /* Коэффициенты 6-7: выбор операции инверсии (coeff6 - старший бит) */ uint32_t coeff6 = extract_bit(seed, COEFF6_POS); uint32_t coeff7 = extract_bit(seed, COEFF7_POS); uint32_t inversion_op = (coeff6 << 1) | coeff7; /* Коэффициенты 8-9: побитовая операция (coeff8 - старший бит) */ uint32_t coeff8 = extract_bit(seed, COEFF8_POS); uint32_t coeff9 = extract_bit(seed, COEFF9_POS); uint32_t bitwise_op = (coeff8 << 1) | coeff9; /* Шаг 1: Вычисление intermediate 1 (циклический сдвиг) */ uint32_t intermediate1; if (coeff1 == 0) { intermediate1 = rotate_left(seed, num_shifts); } else { intermediate1 = rotate_right(seed, num_shifts); } /* Шаг 2: Вычисление intermediate 2 (инверсия битов) */ uint32_t intermediate2 = intermediate1; switch (inversion_op) { case 1: /* Операция A: инвертировать биты 6, 15, 17 */ intermediate2 ^= INV_A_BITS; break; case 2: /* Операция B: инвертировать биты 11, 9, 16 */ intermediate2 ^= INV_B_BITS; break; case 3: /* Операция C: инвертировать биты 7, 10, 13, 4 */ intermediate2 ^= INV_C_BITS; break; case 0: /* Нет инверсии */ default: break; } /* Шаг 3: Вычисление финального ключа (побитовая операция) */ uint32_t key; switch (bitwise_op) { case 0: /* Key = intermediate value */ key = intermediate2; break; case 1: /* Key = seed AND intermediate value */ key = seed & intermediate2; break; case 2: /* Key = seed XOR intermediate value */ key = seed ^ intermediate2; break; case 3: /* Key = seed OR intermediate value */ key = seed | intermediate2; break; default: key = intermediate2; break; } return key; }