73 lines
1.9 KiB
C
73 lines
1.9 KiB
C
#define MODULE_LOG_PREFIX "emu"
|
|
|
|
#include "globals.h"
|
|
|
|
#ifdef WITH_EMU
|
|
|
|
#include "module-emulator-osemu.h"
|
|
#include "module-emulator-omnicrypt.h"
|
|
#include "oscam-aes.h"
|
|
#include "oscam-string.h"
|
|
|
|
|
|
static inline int8_t get_ecm_key(uint16_t provider, uint8_t parity, uint8_t *key)
|
|
{
|
|
return emu_find_key('O', provider, 0, parity == 0 ? "00" : "01", key, 16, 1, 0, 0, NULL);
|
|
}
|
|
|
|
int8_t omnicrypt_ecm(uint8_t *ecm, uint8_t *dw)
|
|
{
|
|
uint8_t section_syntax_indicator, session_key[16], session_key_parity, position;
|
|
uint16_t private_section_length, session_key_id, payload_length;
|
|
struct aes_keys aes;
|
|
|
|
section_syntax_indicator = ecm[1] >> 7;
|
|
if (section_syntax_indicator != 0) // The private_data_bytes immediately follow the private_section_length field
|
|
{
|
|
cs_log("ECM section syntax indicator %d not supported", section_syntax_indicator);
|
|
return EMU_NOT_SUPPORTED;
|
|
}
|
|
|
|
private_section_length = b2i(2, ecm + 1) & 0x0FFF;
|
|
if (private_section_length != 0x2D)
|
|
{
|
|
cs_log("ECM has an unsupported private section length of %d", private_section_length);
|
|
return EMU_NOT_SUPPORTED;
|
|
}
|
|
|
|
session_key_parity = ecm[3] & 0x01;
|
|
session_key_id = b2i(2, ecm + 4);
|
|
|
|
if (!get_ecm_key(session_key_id, session_key_parity, session_key))
|
|
{
|
|
return EMU_KEY_NOT_FOUND;
|
|
}
|
|
aes_set_key(&aes, (char *)session_key);
|
|
|
|
payload_length = b2i(2, ecm + 6) & 0x0FFF;
|
|
if (payload_length != 0x28)
|
|
{
|
|
cs_log("ECM has an unsupported payload length of %d", payload_length);
|
|
return EMU_NOT_SUPPORTED;
|
|
}
|
|
|
|
for (position = 8; position + 1 < payload_length; position += 4 + 16) // Run twice for odd, even CW
|
|
{
|
|
uint8_t parity = ecm[position + 1] & 0x01;
|
|
uint8_t length = ecm[position + 3];
|
|
|
|
if (length != 16)
|
|
{
|
|
cs_log("CW %d has an unsupported length of %d", parity, length);
|
|
return EMU_NOT_SUPPORTED;
|
|
}
|
|
|
|
aes_decrypt(&aes, ecm + position + 4, 16);
|
|
memcpy(dw + parity * 8, ecm + position + 4, 8); // Copy the first 8 bytes (rest are zeros)
|
|
}
|
|
|
|
return EMU_OK;
|
|
}
|
|
|
|
#endif // WITH_EMU
|