#include "an6000_decode.h" #if (RM_MODEL == RM_MODEL_TYPE_AN6000) #include #include #include typedef struct { volatile unsigned long size; volatile char type[4]; } BoxHeader_t; typedef struct _BoxAddress_t { fpos_t addr; unsigned long size; } BoxAddress_t; /** * @brief Convert the Byte-order(32bit) * * @param[in] val target value * * @return convert value */ unsigned long convertEndian_32(unsigned long val) { unsigned long result = 0; unsigned char *p1 = (unsigned char *)&val; unsigned char *p2 = (unsigned char *)&result; p2[0] = p1[3]; p2[1] = p1[2]; p2[2] = p1[1]; p2[3] = p1[0]; return result; } /** * @brief [DEBUG] Box data analysis * * @param[in] fp target file pointer * @param[in] level analysis depth * @param[in] parentSize parent box size */ void BoxAnalysis(FILE *fp, int level, size_t parentSize) { BoxHeader_t boxHead, childBoxHead; char typeDesc[8] = {0}; size_t readSize; int i; int isNotAscii; char *pbuf = NULL; fpos_t pos; while (1) { // read box header readSize = fread(&boxHead, 1, sizeof(BoxHeader_t), fp); if ((feof(fp) != 0) || (readSize == 0)) { break; } boxHead.size = convertEndian_32(boxHead.size); strncpy(typeDesc, (const char *)&boxHead.type[0], 4); if (boxHead.size == 0) { break; } fgetpos(fp, &pos); printf("[%08X] ", (unsigned long)(pos - sizeof(BoxHeader_t))); for (i = 0; i < level; i++) { printf(" "); } printf("%s[%d]\n", typeDesc, boxHead.size); if (parentSize != (size_t)-1) { parentSize -= boxHead.size; } // check child box exist readSize = fread(&childBoxHead, 1, sizeof(BoxHeader_t), fp); childBoxHead.size = convertEndian_32(childBoxHead.size); isNotAscii = 0; for (i = 0; i < 4; i++) { if ((childBoxHead.type[i] < 'a') || (childBoxHead.type[i] > 'z')) { ++isNotAscii; break; } } fseek(fp, -(long)sizeof(BoxHeader_t), SEEK_CUR); if ((boxHead.size > childBoxHead.size) && (isNotAscii == 0)) { // child box exist BoxAnalysis(fp, level + 1, boxHead.size - sizeof(BoxHeader_t)); } else { // child box not exist pbuf = (char *)malloc(boxHead.size - sizeof(BoxHeader_t)); fread(pbuf, 1, boxHead.size - sizeof(BoxHeader_t), fp); free(pbuf); } // check of continue the child box loop if (parentSize == 0) { break; } // terminal box if (strncmp((const char *)boxHead.type, "FWVR", 4) == 0) { break; } } if (parentSize == (size_t)-1) { fseek(fp, 0, SEEK_SET); } } /** * @brief Get the crypt target box information * * @param[in] fp target file pointer * @param[out] buf target box information * @param[in] bufSize number of \a buf buffer * @param[in] level analysis depth * @param[in] parentSize parent box size * * @return number of available target box information */ static bool gFound_stsz = false; static bool gFount_udat = false; size_t GetCryptTarget(FILE *fp, BoxAddress_t *buf, size_t bufSize, int level, size_t parentSize) { size_t buf_num = 0; BoxHeader_t boxHead = {0,}; BoxHeader_t childBoxHead = {0,}; size_t readSize = 0; int isNotAscii = 0; int i = 0; //char *pbuf = NULL; fpos_t pos = 0; if (bufSize == 0) { return 0; } while (1) { // read box header readSize = fread(&boxHead, 1, sizeof(BoxHeader_t), fp); if (readSize == 0) { break; } boxHead.size = convertEndian_32(boxHead.size); if (boxHead.size == 0) { break; } if (parentSize != (size_t)-1) { parentSize -= boxHead.size; } // check crypt target box if (((strncmp((const char *)boxHead.type, "stsz", 4) == 0) && (gFound_stsz == false) ) || (strncmp((const char *)boxHead.type, "udat", 4) == 0) && (gFount_udat == false)){ fgetpos(fp, &pos); buf[buf_num].addr = pos - sizeof(BoxHeader_t); buf[buf_num].size = boxHead.size; fseek(fp, boxHead.size - sizeof(BoxHeader_t), SEEK_CUR); if(strncmp((const char *)boxHead.type, "stsz", 4) == 0) { gFound_stsz = true; } else if(strncmp((const char *)boxHead.type, "udat", 4) == 0) { gFount_udat = true; } if (++buf_num == bufSize) { return buf_num; } } else { // Existence check of child box readSize = fread(&childBoxHead, 1, sizeof(BoxHeader_t), fp); fseek(fp, -(long)sizeof(BoxHeader_t), SEEK_CUR); childBoxHead.size = convertEndian_32(childBoxHead.size); isNotAscii = 0; for (i = 0; i < 4; i++) { if ((childBoxHead.type[i] < 'a') || (childBoxHead.type[i] > 'z')) { ++isNotAscii; break; } } if ((boxHead.size > childBoxHead.size) && (isNotAscii == 0)) { // child box is exist buf_num += GetCryptTarget(fp, &buf[buf_num], bufSize - buf_num, level + 1, boxHead.size - sizeof(BoxHeader_t)); if (buf_num == bufSize) { return buf_num; } } else { // child box is not exist fseek(fp, boxHead.size - sizeof(BoxHeader_t), SEEK_CUR); } } // check of continue the child box loop if (parentSize == 0) { break; } // terminal box if (strncmp((const char *)boxHead.type, "FWVR", 4) == 0) { break; } } return buf_num; } /** * @brief Encrypt MP4 File * * @param[in] filename target file name * * @retval 0 successful * @retval non-zero failed */ int encrypt_an6000(const wchar_t *filename) { FILE *fp = NULL; BoxAddress_t tgtInfo[8]; size_t infoSize, i, x; char *pbuf; char key = 0x19; char preData, enc; memset(tgtInfo, 0, sizeof(tgtInfo)); infoSize = sizeof(tgtInfo) / sizeof(BoxAddress_t); fp = _wfopen(filename,L"r+b"); //fp = fopen(filename, "r+b"); if (fp == NULL) { return -1; } fseek(fp, 0, SEEK_SET); // Analysis box information //BoxAnalysis(fp, 0, (size_t)-1); infoSize = GetCryptTarget(fp, tgtInfo, infoSize, 0, -1); for (i = 0; i < infoSize; i++) { pbuf = (char*)malloc(tgtInfo[i].size); // read the target data fsetpos(fp, &tgtInfo[i].addr); fread(pbuf, 1, tgtInfo[i].size, fp); // data encrypt preData = 0; for (x = 8; x < tgtInfo[i].size; x++) { enc = ((~pbuf[x]) ^ preData) ^ key; preData = pbuf[x]; pbuf[x] = enc; } // over-write the target data fsetpos(fp, &tgtInfo[i].addr); fwrite(pbuf, 1, tgtInfo[i].size, fp); free(pbuf); } fclose(fp); return 0; } /** * @brief Decrypt MP4 File * * @param[in] filename target file name * * @retval 0 successful * @retval non-zero failed */ int decrypt_an6000(const wchar_t *filename) { gFound_stsz = false; gFount_udat = false; FILE *fp = NULL; BoxAddress_t tgtInfo[8] = {0,}; size_t infoSize, i, x; char *pbuf = NULL; char key = 0x19; char preData = 0; memset(tgtInfo, 0, sizeof(_BoxAddress_t) * 8); infoSize = sizeof(tgtInfo) / sizeof(_BoxAddress_t); // filePathCH2.toStdWString().c_str() fp = _wfopen(filename,L"r+b"); //fp = fopen(filename, "r+b"); if (fp == NULL) { return -1; } fseek(fp, 0, SEEK_SET); // Analysis box information infoSize = GetCryptTarget(fp, tgtInfo, infoSize, 0, -1); for (i = 0; i < infoSize; i++) { pbuf = (char*)malloc(tgtInfo[i].size); // read the target data fsetpos(fp, &tgtInfo[i].addr); fread(pbuf, 1, tgtInfo[i].size, fp); // data decrypt preData = 0; for (x = 8; x < tgtInfo[i].size; x++) { pbuf[x] = ~((pbuf[x] ^ key) ^ preData); preData = pbuf[x]; } // over-write the target data fsetpos(fp, &tgtInfo[i].addr); fwrite(pbuf, 1, tgtInfo[i].size, fp); free(pbuf); } fclose(fp); return 0; } bool is_encrypted_an6000(const wchar_t *filename) { gFound_stsz = false; gFount_udat = false; FILE *fp = NULL; BoxAddress_t tgtInfo[8] = {0,}; size_t infoSize, i, x; memset(tgtInfo, 0, sizeof(_BoxAddress_t) * 8); infoSize = sizeof(tgtInfo) / sizeof(_BoxAddress_t); fp = _wfopen(filename,L"r+b"); if (fp == NULL) { return false; } fseek(fp, 0, SEEK_SET); infoSize = GetCryptTarget(fp, tgtInfo, infoSize, 0, -1); char buffer[16] = {0,}; for (i = 0; i < infoSize; i++) { // read the target data tgtInfo[i].addr += 4; fsetpos(fp, &tgtInfo[i].addr); fread(buffer, 1, 16, fp); if(buffer[0] == 's' && buffer[1] =='t' && buffer[2] =='s' && buffer[3] =='z') { bool enc = (buffer[4] != 0 || buffer[5] != 0 || buffer[6] != 0 || buffer[7] != 0); fclose(fp); return enc;//(buffer[4] != 0 || buffer[5] != 0 || buffer[6] != 0 || buffer[7] != 0); } //printf("%c:%c:%c:%c\n",buffer[0],buffer[1],buffer[2],buffer[3]); //printf("%02X:%02X:%02X:%02X %02X:%02X:%02X:%02X\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7]); } fclose(fp); return true; } #endif // #if (RM_MODEL == RM_MODEL_TYPE_AN6000)