oscam-2.26.01-11942-802-wit.../module-emulator-viaccess.c
2026-02-17 09:41:05 +00:00

1184 lines
20 KiB
C
Executable File

#define MODULE_LOG_PREFIX "emu"
#include "globals.h"
#ifdef WITH_EMU
#include "cscrypt/des.h"
#include "module-emulator-osemu.h"
#include "module-newcamd-des.h"
#include "oscam-aes.h"
#include "oscam-string.h"
// from reader-viaccess.c:
void hdSurEncPhase1_D2_0F_11(uint8_t *CWs);
void hdSurEncPhase2_D2_0F_11(uint8_t *CWs);
void hdSurEncPhase1_D2_13_15(uint8_t *cws);
void hdSurEncPhase2_D2_13_15(uint8_t *cws);
// Viaccess EMU
static int8_t get_key(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex,
uint32_t keyLength, uint8_t isCriticalKey)
{
char keyStr[EMU_MAX_CHAR_KEYNAME];
snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex);
if (emu_find_key('V', ident, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL))
{
return 1;
}
if (ident == 0xD00040 && emu_find_key('V', 0x030B00, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL))
{
return 1;
}
return 0;
}
static void via1_mod(const uint8_t *key2, uint8_t *data)
{
int32_t kb, db;
for (db = 7; db >= 0; db--)
{
for (kb = 7; kb > 3; kb--)
{
int32_t a0 = kb ^ db;
int32_t pos = 7;
if (a0 & 4)
{
a0 ^= 7;
pos ^= 7;
}
a0 = (a0 ^ (kb & 3)) + (kb & 3);
if (!(a0 & 4))
{
data[db] ^= (key2[kb] ^ ((data[kb ^ pos] * key2[kb ^ 4]) & 0xFF));
}
}
}
for (db = 0; db < 8; db++)
{
for (kb = 0; kb < 4; kb++)
{
int32_t a0 = kb ^ db;
int32_t pos = 7;
if (a0 & 4)
{
a0 ^= 7;
pos ^= 7;
}
a0 = (a0 ^ (kb & 3)) + (kb & 3);
if (!(a0 & 4))
{
data[db] ^= (key2[kb] ^ ((data[kb ^ pos] * key2[kb ^ 4]) & 0xFF));
}
}
}
}
static void via1_decode(uint8_t *data, uint8_t *key)
{
via1_mod(key + 8, data);
nc_des(key, DES_ECM_CRYPT, data);
via1_mod(key + 8, data);
}
static void via1_hash(uint8_t *data, uint8_t *key)
{
via1_mod(key + 8, data);
nc_des(key, DES_ECM_HASH, data);
via1_mod(key + 8, data);
}
static inline void via1_do_hash(uint8_t *hashbuffer, uint8_t *pH, uint8_t data, uint8_t *hashkey)
{
hashbuffer[*pH] ^= data;
(*pH)++;
if (*pH == 8)
{
via1_hash(hashbuffer, hashkey);
*pH = 0;
}
}
static int8_t via1_decrypt(uint8_t *ecm, uint8_t *dw, uint32_t ident, uint8_t desKeyIndex)
{
int32_t msg_pos, encStart = 0, hash_start, i;
uint8_t tmp, k, pH, foundData = 0;
uint8_t work_key[16], signature[8], hashbuffer[8], prepared_key[16], hashkey[16];
uint8_t *data, *des_data1, *des_data2;
uint16_t ecmLen = SCT_LEN(ecm);
if (ident == 0)
{
return EMU_CORRUPT_DATA;
}
memset(work_key, 0, 16);
if (!get_key(work_key, ident, '0', desKeyIndex, 8, 1))
{
return EMU_KEY_NOT_FOUND;
}
if (ecmLen < 11)
{
return EMU_NOT_SUPPORTED;
}
data = ecm + 9;
des_data1 = dw;
des_data2 = dw + 8;
msg_pos = 0;
pH = 0;
memset(hashbuffer, 0, sizeof(hashbuffer));
memcpy(hashkey, work_key, sizeof(hashkey));
memset(signature, 0, 8);
while (9 + msg_pos + 2 < ecmLen)
{
switch (data[msg_pos])
{
case 0xEA:
if (9 + msg_pos + 2 + 15 < ecmLen)
{
encStart = msg_pos + 2;
memcpy(des_data1, &data[msg_pos + 2], 8);
memcpy(des_data2, &data[msg_pos + 2 + 8], 8);
foundData |= 1;
}
break;
case 0xF0:
if (9 + msg_pos + 2 + 7 < ecmLen)
{
memcpy(signature, &data[msg_pos + 2], 8);
foundData |= 2;
}
break;
}
msg_pos += data[msg_pos + 1] + 2;
}
if (foundData != 3)
{
return EMU_NOT_SUPPORTED;
}
pH = i = 0;
if (data[0] == 0x9F && 10 + data[1] <= ecmLen)
{
via1_do_hash(hashbuffer, &pH, data[i++], hashkey);
via1_do_hash(hashbuffer, &pH, data[i++], hashkey);
for (hash_start = 0; hash_start < data[1]; hash_start++)
{
via1_do_hash(hashbuffer, &pH, data[i++], hashkey);
}
while (pH != 0)
{
via1_do_hash(hashbuffer, &pH, 0, hashkey);
}
}
if (work_key[7] == 0)
{
for (; i < encStart + 16; i++)
{
via1_do_hash(hashbuffer, &pH, data[i], hashkey);
}
memcpy(prepared_key, work_key, 8);
}
else
{
prepared_key[0] = work_key[2];
prepared_key[1] = work_key[3];
prepared_key[2] = work_key[4];
prepared_key[3] = work_key[5];
prepared_key[4] = work_key[6];
prepared_key[5] = work_key[0];
prepared_key[6] = work_key[1];
prepared_key[7] = work_key[7];
memcpy(prepared_key + 8, work_key + 8, 8);
if (work_key[7] & 1)
{
for (; i < encStart; i++)
{
via1_do_hash(hashbuffer, &pH, data[i], hashkey);
}
k = ((work_key[7] & 0xF0) == 0) ? 0x5A : 0xA5;
for (i = 0; i < 8; i++)
{
tmp = des_data1[i];
des_data1[i] = (k & hashbuffer[pH] ) ^ tmp;
via1_do_hash(hashbuffer, &pH, tmp, hashkey);
}
for (i = 0; i < 8; i++)
{
tmp = des_data2[i];
des_data2[i] = (k & hashbuffer[pH] ) ^ tmp;
via1_do_hash(hashbuffer, &pH, tmp, hashkey);
}
}
else
{
for ( ; i < encStart + 16; i++)
{
via1_do_hash(hashbuffer, &pH, data[i], hashkey);
}
}
}
via1_decode(des_data1, prepared_key);
via1_decode(des_data2, prepared_key);
via1_hash(hashbuffer, hashkey);
if (memcmp(signature, hashbuffer, 8))
{
return EMU_CHECKSUM_ERROR;
}
return EMU_OK;
}
static int8_t via26_process_dw(uint8_t *indata, uint32_t ident, uint8_t desKeyIndex)
{
uint8_t pv1,pv2, i;
uint8_t Tmp[8], T1Key[300], P1Key[8], KeyDes1[16], KeyDes2[16], XorKey[8];
uint32_t ks1[32], ks2[32];
if (!get_key(T1Key, ident, 'T', 1, 300, 1))
{
return 2;
}
if (!get_key(P1Key, ident, 'P', 1, 8, 1))
{
return 2;
}
if (!get_key(KeyDes1, ident, 'D', 1, 16, 1))
{
return 2;
}
if (!get_key(KeyDes2, ident, '0', desKeyIndex, 16, 1))
{
return 2;
}
if (!get_key(XorKey, ident, 'X', 1, 8, 1))
{
return 2;
}
for (i = 0; i < 8; i++)
{
pv1 = indata[i];
Tmp[i] = T1Key[pv1];
}
for (i = 0; i < 8; i++)
{
pv1 = P1Key[i];
pv2 = Tmp[pv1];
indata[i] = pv2;
}
des_set_key(KeyDes1, ks1);
des(indata, ks1, 1);
for (i = 0; i < 8; i++)
{
indata[i] ^= XorKey[i];
}
des_set_key(KeyDes2, ks1);
des_set_key(KeyDes2 + 8, ks2);
des(indata, ks1, 0);
des(indata, ks2, 1);
des(indata, ks1, 0);
for (i = 0; i < 8; i++)
{
indata[i] ^= XorKey[i];
}
des_set_key(KeyDes1, ks1);
des(indata, ks1, 0);
for (i = 0; i < 8; i++)
{
pv1 = indata[i];
pv2 = P1Key[i];
Tmp[pv2] = pv1;
}
for (i = 0; i < 8; i++)
{
pv1 = Tmp[i];
pv2 = T1Key[pv1];
indata[i] = pv2;
}
return 0;
}
static int8_t via26_decrypt(uint8_t *source, uint8_t *dw, uint32_t ident, uint8_t desKeyIndex)
{
uint8_t tmpData[8], C1[8];
uint8_t *pXorVector;
int32_t i, j;
if (ident == 0)
{
return EMU_CORRUPT_DATA;
}
if (!get_key(C1, ident, 'C', 1, 8, 1))
{
return EMU_KEY_NOT_FOUND;
}
for (i = 0; i < 2; i++)
{
memcpy(tmpData, source + i * 8, 8);
via26_process_dw(tmpData, ident, desKeyIndex);
if (i != 0)
{
pXorVector = source;
}
else
{
pXorVector = &C1[0];
}
for (j = 0; j < 8; j++)
{
dw[i * 8 + j] = tmpData[j] ^ pXorVector[j];
}
// Fix CW checksum bytes
for (j = 3; j < 8; j += 4)
{
dw[i * 8 + j] = (dw[i * 8 + j - 3] + dw[i * 8 + j - 2] + dw[i * 8 + j - 1]) & 0xFF;
}
}
return EMU_OK;
}
static void via3_core(uint8_t *data, uint8_t Off, uint32_t ident, uint8_t *XorKey, uint8_t *T1Key)
{
uint8_t i;
uint32_t lR2, lR3, lR4, lR6, lR7;
switch (ident)
{
case 0x032820:
{
for (i = 0; i < 4; i++)
{
data[i] ^= XorKey[(Off + i) & 0x07];
}
lR2 = (data[0] ^ 0xBD) + data[0];
lR3 = (data[3] ^ 0xEB) + data[3];
lR2 = (lR2 - lR3) ^ data[2];
lR3 = ((0x39 * data[1]) << 2);
data[4] = (lR2 | lR3) + data[2];
lR3 = ((((data[0] + 6) ^ data[0]) | (data[2] << 1)) ^ 0x65) + data[0];
lR2 = (data[1] ^ 0xED) + data[1];
lR7 = ((data[3] + 0x29) ^ data[3]) * lR2;
data[5] = lR7 + lR3;
lR2 = ((data[2] ^ 0x33) + data[2]) & 0x0A;
lR3 = (data[0] + 0xAD) ^ data[0];
lR3 = lR3 + lR2;
lR2 = data[3] * data[3];
lR7 = (lR2 | 1) + data[1];
data[6] = (lR3 | lR7) + data[1];
lR3 = data[1] & 0x07;
lR2 = (lR3 - data[2]) & (data[0] | lR2 | 0x01);
data[7] = lR2 + data[3];
for (i = 0; i < 4; i++)
{
data[i + 4] = T1Key[data[i + 4]];
}
}
break;
case 0x030B00:
{
for (i = 0; i < 4; i++)
{
data[i] ^= XorKey[(Off + i) & 0x07];
}
lR6 = (data[3] + 0x6E) ^ data[3];
lR6 = (lR6 * (data[2] << 1)) + 0x17;
lR3 = (data[1] + 0x77) ^ data[1];
lR4 = (data[0] + 0xD7) ^ data[0];
data[4] = ((lR4 & lR3) | lR6) + data[0];
lR4 = ((data[3] + 0x71) ^ data[3]) ^ 0x90;
lR6 = (data[1] + 0x1B) ^ data[1];
lR4 = (lR4 * lR6) ^ data[0];
data[5] = (lR4 ^ (data[2] << 1)) + data[1];
lR3 = (data[3] * data[3]) | 0x01;
lR4 = (((data[2] ^ 0x35) + data[2]) | lR3) + data[2];
lR6 = data[1] ^ (data[0] + 0x4A);
data[6] = lR6 + lR4;
lR3 = (data[0] * (data[2] << 1)) | data[1];
lR4 = 0xFE - data[3];
lR3 = lR4 ^ lR3;
data[7] = lR3 + data[3];
for (i = 0; i < 4; i++)
{
data[4 + i] = T1Key[data[4 + i]];
}
}
break;
default:
break;
}
}
static void via3_fct1(uint8_t *data, uint32_t ident, uint8_t *XorKey, uint8_t *T1Key)
{
uint8_t t;
via3_core(data, 0, ident, XorKey, T1Key);
switch (ident)
{
case 0x032820:
{
t = data[4];
data[4] = data[7];
data[7] = t;
}
break;
case 0x030B00:
{
t = data[5];
data[5] = data[7];
data[7] = t;
}
break;
default:
break;
}
}
static void via3_fct2(uint8_t *data, uint32_t ident, uint8_t *XorKey, uint8_t *T1Key)
{
uint8_t t;
via3_core(data, 4, ident, XorKey, T1Key);
switch (ident)
{
case 0x032820:
{
t = data[4];
data[4] = data[7];
data[7] = data[5];
data[5] = data[6];
data[6] = t;
}
break;
case 0x030B00:
{
t = data[6];
data[6] = data[7];
data[7] = t;
}
break;
default:
break;
}
}
static int8_t via3_process_dw(uint8_t *data, uint32_t ident, uint8_t desKeyIndex)
{
uint8_t i;
uint8_t tmp[8], T1Key[300], P1Key[8], KeyDes[16], XorKey[8];
uint32_t ks1[32], ks2[32];
if (!get_key(T1Key, ident, 'T', 1, 300, 1))
{
return 2;
}
if (!get_key(P1Key, ident, 'P', 1, 8, 1))
{
return 2;
}
if (!get_key(KeyDes, ident, '0', desKeyIndex, 16, 1))
{
return 2;
}
if (!get_key(XorKey, ident, 'X', 1, 8, 1))
{
return 2;
}
for (i = 0; i < 4; i++)
{
tmp[i] = data[i + 4];
}
via3_fct1(tmp, ident, XorKey, T1Key);
for (i = 0; i < 4; i++)
{
tmp[i] = data[i] ^ tmp[i + 4];
}
via3_fct2(tmp, ident, XorKey, T1Key);
for (i = 0; i < 4; i++)
{
tmp[i] ^= XorKey[i + 4];
}
for (i = 0; i < 4; i++)
{
data[i] = data[i + 4] ^ tmp[i + 4];
data[i + 4] = tmp[i];
}
des_set_key(KeyDes, ks1);
des_set_key(KeyDes + 8, ks2);
des(data, ks1, 0);
des(data, ks2, 1);
des(data, ks1, 0);
for (i = 0; i < 4; i++)
{
tmp[i] = data[i + 4];
}
via3_fct2(tmp, ident, XorKey, T1Key);
for (i = 0; i < 4; i++)
{
tmp[i] = data[i] ^ tmp[i + 4];
}
via3_fct1(tmp, ident, XorKey, T1Key);
for (i = 0; i < 4; i++)
{
tmp[i] ^= XorKey[i];
}
for (i = 0; i < 4; i++)
{
data[i] = data[i + 4] ^ tmp[i + 4];
data[i + 4] = tmp[i];
}
return 0;
}
static void via3_final_mix(uint8_t *dw)
{
uint8_t tmp[4];
memcpy(tmp, dw, 4);
memcpy(dw, dw + 4, 4);
memcpy(dw + 4, tmp, 4);
memcpy(tmp, dw + 8, 4);
memcpy(dw + 8, dw + 12, 4);
memcpy(dw + 12, tmp, 4);
}
static int8_t via3_decrypt(uint8_t *source, uint8_t *dw, uint32_t ident, uint8_t desKeyIndex,
uint8_t aesKeyIndex, uint8_t aesMode, int8_t doFinalMix)
{
int8_t aesAfterCore = 0, needsAES = (aesKeyIndex != 0xFF);
int32_t i, j;
uint8_t tmpData[8], C1[8];
uint8_t *pXorVector;
char aesKey[16];
if (ident == 0)
{
return EMU_CORRUPT_DATA;
}
if (!get_key(C1, ident, 'C', 1, 8, 1))
{
return EMU_KEY_NOT_FOUND;
}
if (needsAES && !get_key((uint8_t *)aesKey, ident, 'E', aesKeyIndex, 16, 1))
{
return EMU_KEY_NOT_FOUND;
}
if (aesMode == 0x0D || aesMode == 0x11 || aesMode == 0x15)
{
aesAfterCore = 1;
}
if (needsAES && !aesAfterCore)
{
if (aesMode == 0x0F)
{
hdSurEncPhase1_D2_0F_11(source);
hdSurEncPhase2_D2_0F_11(source);
}
else if (aesMode == 0x13)
{
hdSurEncPhase1_D2_13_15(source);
}
struct aes_keys aes;
aes_set_key(&aes, aesKey);
aes_decrypt(&aes, source, 16);
if (aesMode == 0x0F)
{
hdSurEncPhase1_D2_0F_11(source);
}
else if (aesMode == 0x13)
{
hdSurEncPhase2_D2_13_15(source);
}
}
for (i = 0; i < 2; i++)
{
memcpy(tmpData, source + i * 8, 8);
via3_process_dw(tmpData, ident, desKeyIndex);
if (i != 0)
{
pXorVector = source;
}
else
{
pXorVector = &C1[0];
}
for (j = 0; j < 8; j++)
{
dw[i * 8 + j] = tmpData[j] ^ pXorVector[j];
}
}
if (needsAES && aesAfterCore)
{
if (aesMode == 0x11)
{
hdSurEncPhase1_D2_0F_11(dw);
hdSurEncPhase2_D2_0F_11(dw);
}
else if (aesMode == 0x15)
{
hdSurEncPhase1_D2_13_15(dw);
}
struct aes_keys aes;
aes_set_key(&aes, aesKey);
aes_decrypt(&aes, dw, 16);
if (aesMode == 0x11)
{
hdSurEncPhase1_D2_0F_11(dw);
}
if (aesMode == 0x15)
{
hdSurEncPhase2_D2_13_15(dw);
}
}
if (ident == 0x030B00)
{
if (doFinalMix)
{
via3_final_mix(dw);
}
if (!is_valid_dcw(dw) || !is_valid_dcw(dw + 8))
{
return EMU_CHECKSUM_ERROR;
}
}
return EMU_OK;
}
int8_t viaccess_ecm(uint8_t *ecm, uint8_t *dw)
{
int8_t doFinalMix = 0;
uint8_t nanoCmd = 0, nanoLen = 0, version = 0, providerKeyLen = 0;
uint8_t desKeyIndex = 0, aesMode = 0, aesKeyIndex = 0xFF;
uint16_t i = 0, keySelectPos = 0, ecmLen = SCT_LEN(ecm);
uint32_t currentIdent = 0;
for (i = 4; i + 2 < ecmLen; )
{
nanoCmd = ecm[i++];
nanoLen = ecm[i++];
if (i + nanoLen > ecmLen)
{
return EMU_NOT_SUPPORTED;
}
switch (nanoCmd)
{
case 0x40:
if (nanoLen < 0x03)
{
break;
}
version = ecm[i];
if (nanoLen == 3)
{
currentIdent = ((ecm[i] << 16) | (ecm[i + 1] << 8)) | (ecm[i + 2] & 0xF0);
desKeyIndex = ecm[i + 2] & 0x0F;
keySelectPos = i + 3;
}
else
{
currentIdent = (ecm[i] << 16) | (ecm[i + 1] << 8) | ((ecm[i + 2] >> 4) & 0x0F);
desKeyIndex = ecm[i + 3];
keySelectPos = i + 4;
}
providerKeyLen = nanoLen;
break;
case 0x90:
if (nanoLen < 0x03)
{
break;
}
version = ecm[i];
currentIdent = ((ecm[i] << 16) | (ecm[i + 1] << 8)) | (ecm[i + 2] & 0xF0);
desKeyIndex = ecm[i + 2] & 0x0F;
keySelectPos = i + 4;
if ((version == 3) && (nanoLen > 3))
{
desKeyIndex = ecm[i + (nanoLen - 4)] & 0x0F;
}
providerKeyLen = nanoLen;
break;
case 0x80:
nanoLen = 0;
break;
case 0xD2:
if (nanoLen < 0x02)
{
break;
}
aesMode = ecm[i];
aesKeyIndex = ecm[i + 1];
break;
case 0xDD:
nanoLen = 0;
break;
case 0xEA:
if (nanoLen < 0x10)
{
break;
}
if (version < 2)
{
return via1_decrypt(ecm, dw, currentIdent, desKeyIndex);
}
else if (version == 2)
{
return via26_decrypt(ecm + i, dw, currentIdent, desKeyIndex);
}
else if (version == 3)
{
doFinalMix = 0;
if (currentIdent == 0x030B00 && providerKeyLen > 3)
{
if (keySelectPos + 2 >= ecmLen)
{
break;
}
if (ecm[keySelectPos] == 0x05 && ecm[keySelectPos + 1] == 0x67 &&
(ecm[keySelectPos + 2] == 0x00 || ecm[keySelectPos + 2] == 0x01))
{
if (ecm[keySelectPos + 2] == 0x01)
{
doFinalMix = 1;
}
}
else
{
break;
}
}
return via3_decrypt(ecm + i, dw, currentIdent, desKeyIndex, aesKeyIndex, aesMode, doFinalMix);
}
break;
default:
break;
}
i += nanoLen;
}
return EMU_NOT_SUPPORTED;
}
// Viaccess EMM EMU
int8_t viaccess_emm(uint8_t *emm, uint32_t *keysAdded)
{
uint8_t nanoCmd = 0, subNanoCmd = 0, *tmp;
uint8_t ecmKeyCount = 0, emmKeyIndex = 0, aesMode = 0x0D;
uint8_t nanoLen = 0, subNanoLen = 0, haveEmmXorKey = 0, haveNewD0 = 0;
uint8_t ecmKeys[6][16], keyD0[2], emmKey[16], emmXorKey[16], provName[17];
uint16_t i = 0, j = 0, k = 0, emmLen = SCT_LEN(emm);
uint32_t ui1, ui2, ui3, ecmKeyIndex[6], provider = 0, ecmProvider = 0;
char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36];
struct aes_keys aes;
memset(keyD0, 0, 2);
memset(ecmKeyIndex, 0, sizeof(uint32_t) * 6);
for (i = 3; i + 2 < emmLen; )
{
nanoCmd = emm[i++];
nanoLen = emm[i++];
if (i + nanoLen > emmLen)
{
return EMU_NOT_SUPPORTED;
}
switch (nanoCmd)
{
case 0x90:
{
if (nanoLen < 3)
{
break;
}
ui1 = emm[i + 2];
ui2 = emm[i + 1];
ui3 = emm[i];
provider = (ui1 | (ui2 << 8) | (ui3 << 16));
if (provider == 0x00D00040)
{
ecmProvider = 0x030B00;
}
else
{
return EMU_NOT_SUPPORTED;
}
break;
}
case 0xD2:
{
if (nanoLen < 2)
{
break;
}
emmKeyIndex = emm[i + 1];
break;
}
case 0x41:
{
if (nanoLen < 1)
{
break;
}
if (!get_key(emmKey, provider, 'M', emmKeyIndex, 16, 1))
{
return EMU_KEY_NOT_FOUND;
}
memset(provName, 0, 17);
memset(emmXorKey, 0, 16);
k = nanoLen < 16 ? nanoLen : 16;
memcpy(provName, &emm[i], k);
aes_set_key(&aes, (char *)emmKey);
aes_decrypt(&aes, emmXorKey, 16);
for (j = 0; j < 16; j++)
{
provName[j] ^= emmXorKey[j];
}
provName[k] = 0;
if (strcmp((char *)provName, "TNTSAT") != 0 &&
strcmp((char *)provName, "TNTSATPRO") != 0 &&
strcmp((char *)provName, "CSAT V") != 0)
{
return EMU_NOT_SUPPORTED;
}
break;
}
case 0xBA:
{
if (nanoLen < 2)
{
break;
}
get_key(keyD0, ecmProvider, 'D', 0, 2, 0);
ui1 = (emm[i] << 8) | emm[i + 1];
if( (uint32_t)((keyD0[0] << 8) | keyD0[1]) < ui1 || (keyD0[0] == 0x00 && keyD0[1] == 0x00))
{
keyD0[0] = emm[i];
keyD0[1] = emm[i + 1];
haveNewD0 = 1;
break;
}
return EMU_OK;
}
case 0xBC:
{
break;
}
case 0x43:
{
if (nanoLen < 16)
{
break;
}
memcpy(emmXorKey, &emm[i], 16);
haveEmmXorKey = 1;
break;
}
case 0x44:
{
if (nanoLen < 3)
{
break;
}
if (!haveEmmXorKey)
{
memset(emmXorKey, 0, 16);
}
tmp = (uint8_t *)malloc(((nanoLen / 16) + 1) * 16 * sizeof(uint8_t));
if (tmp == NULL)
{
return EMU_OUT_OF_MEMORY;
}
memcpy(tmp, &emm[i], nanoLen);
aes_set_key(&aes, (char *)emmKey);
for (j = 0; j < nanoLen; j += 16)
{
aes_decrypt(&aes, emmXorKey, 16);
for (k = 0; k < 16; k++)
{
tmp[j + k] ^= emmXorKey[k];
}
}
memcpy(&emm[i - 2], tmp, nanoLen);
free(tmp);
nanoLen = 0;
i -= 2;
break;
}
case 0x68:
{
if (ecmKeyCount > 5)
{
break;
}
for (j = i; j + 2 < i + nanoLen; )
{
subNanoCmd = emm[j++];
subNanoLen = emm[j++];
if (j + subNanoLen > i + nanoLen)
{
break;
}
switch (subNanoCmd)
{
case 0xD2:
{
if (nanoLen < 2)
{
break;
}
aesMode = emm[j];
emmKeyIndex = emm[j + 1];
break;
}
case 0x01:
{
if(nanoLen < 17)
{
break;
}
ecmKeyIndex[ecmKeyCount] = emm[j];
memcpy(&ecmKeys[ecmKeyCount], &emm[j + 1], 16);
if (!get_key(emmKey, provider, 'M', emmKeyIndex, 16, 1))
{
break;
}
if (aesMode == 0x0F || aesMode == 0x11)
{
hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]);
hdSurEncPhase2_D2_0F_11(ecmKeys[ecmKeyCount]);
}
else if (aesMode == 0x13 || aesMode == 0x15)
{
hdSurEncPhase1_D2_13_15(ecmKeys[ecmKeyCount]);
}
aes_set_key(&aes, (char *)emmKey);
aes_decrypt(&aes, ecmKeys[ecmKeyCount], 16);
if (aesMode == 0x0F || aesMode == 0x11)
{
hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]);
}
else if (aesMode == 0x13 || aesMode == 0x15)
{
hdSurEncPhase2_D2_13_15(ecmKeys[ecmKeyCount]);
}
ecmKeyCount++;
break;
}
default:
break;
}
j += subNanoLen;
}
break;
}
case 0xF0:
{
if (nanoLen != 4)
{
break;
}
ui1 = ((emm[i + 2] << 8) | (emm[i + 1] << 16) | (emm[i] << 24) | emm[i + 3]);
if (ccitt32_crc(emm + 3, emmLen - 11) != ui1)
{
return EMU_CHECKSUM_ERROR;
}
if (haveNewD0)
{
SAFE_MUTEX_LOCK(&emu_key_data_mutex);
emu_set_key('V', ecmProvider, "D0", keyD0, 2, 1, NULL, NULL);
for (j = 0; j < ecmKeyCount; j++)
{
snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "E%X", ecmKeyIndex[j]);
emu_set_key('V', ecmProvider, keyName, ecmKeys[j], 16, 1, NULL, NULL);
(*keysAdded)++;
cs_hexdump(0, ecmKeys[j], 16, keyValue, sizeof(keyValue));
cs_log("Key found in EMM: V %06X %s %s", ecmProvider, keyName, keyValue);
}
SAFE_MUTEX_UNLOCK(&emu_key_data_mutex);
}
break;
}
default:
break;
}
i += nanoLen;
}
return EMU_OK;
}
#endif // WITH_EMU