Created
April 2, 2025 07:32
-
-
Save Linblow/68de00bc117c38c40c7edc25a7b31d95 to your computer and use it in GitHub Desktop.
Decrypt/encrypt TiltFX id.txt file contents
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Compile this with PolarSSL */ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <polarssl/aes.h> // PolarSSL 0.13 is used in TiltFX | |
void idStrToBin(const char *idStr, uint8_t *id) | |
{ | |
int i; | |
char sbuf[128]; | |
uint32_t ibuf[4]; | |
strncpy(sbuf, idStr, sizeof(sbuf)); | |
for (i = 0; i < 4; ++i) { | |
sbuf[8 + 9*i] = 0; | |
ibuf[i] = strtoull(&sbuf[9*i], NULL, 16); | |
} | |
memcpy(id, ibuf, 16); | |
} | |
char * idToStr(const uint8_t *id, char *idStr) | |
{ | |
const uint32_t *pId = (const uint32_t *)id; | |
sprintf(idStr, "%08X-%08X-%08X-%08X", pId[0], pId[1], pId[2], pId[3]); | |
return idStr; | |
} | |
void printId(const void *id) | |
{ | |
char str[64]; | |
idToStr(id, str); | |
printf(str); | |
} | |
static void crypt(int mode, void *input, void *output) | |
{ | |
aes_context ctx; | |
static const char key[16] = {0x8e,0x5d,0x0b,0x1c,0x3f,0xbb,0x9c,0x6b,0x88,0xd9,0xbf,0x90,0x1c,0x91,0xaf,0x2f}; | |
switch (mode) | |
{ | |
case AES_ENCRYPT: | |
aes_setkey_enc(&ctx, key, 128); | |
aes_crypt_ecb(&ctx, AES_ENCRYPT, (unsigned char *)input, (unsigned char *)output); | |
break; | |
case AES_DECRYPT: | |
aes_setkey_dec(&ctx, key, 128); | |
aes_crypt_ecb(&ctx, AES_DECRYPT, (unsigned char *)input, (unsigned char *)output); | |
break; | |
} | |
} | |
/** | |
* Generate the Datel ID from the PSP hardware fuse ID, and encrypt it. | |
* @param fuse90 Low part of the FuseID | |
* @param fuse94 High part of the FuseID | |
* @param id 16-bytes buffer to receive the generated ID bytes | |
* @param idStr Buffer to receive the ID as a formatted string (at least 36 bytes) | |
*/ | |
void generateId(uint32_t fuse90, uint32_t fuse94, uint8_t id[16], char *idStr) | |
{ | |
uint32_t plain[4]; | |
/* Prepare data: <fuse_id>DATEL10001 (actually AD1LET1000 because of endianness). */ | |
plain[0] = ((fuse94 << 16) & 0xffff0000u) | ((fuse90 >> 16) & 0xffffu); | |
plain[1] = ((fuse90 << 16) & 0xffff0000u) | 0x4441; // DA | |
plain[2] = 0x54454c31; // TEL1 | |
plain[3] = 0x30303031; // 0001 | |
memset(id, 0, 16); | |
crypt(AES_ENCRYPT, plain, id); | |
idToStr(id, idStr); | |
} | |
/** | |
* Decrypt an encrypted Datel ID. | |
* @param encId Encrypted ID (16 bytes) | |
* @param plainId 16-bytes buffer to receive the decrypted ID | |
* @param pFuse90 Optional pointer to receive the low part of the FuseID | |
* @param pFuse94 Optional pointer to receive the high part of the FuseID | |
*/ | |
void decryptId(uint8_t *encId, uint8_t *plainId, uint32_t *pFuse90, uint32_t *pFuse94) | |
{ | |
uint32_t *pId = (uint32_t *)plainId; | |
memset(plainId, 0, 16); | |
crypt(AES_DECRYPT, encId, plainId); | |
if (pFuse90) { | |
*pFuse90 = ((pId[0] << 16) & 0xffff0000u) | ((pId[1] >> 16) & 0xffffu); | |
} | |
if (pFuse94) { | |
*pFuse94 = (pId[0] >> 16) & 0xffffu; | |
} | |
} | |
int main(int argc, char *argv[]) | |
{ | |
char idStr[] = "BBDC9248-821212D3-F348C2CE-1F65D56A"; | |
uint8_t id[16] = {0}; | |
uint8_t plainId[16] = {0}; | |
uint32_t fuse90 = 0; | |
uint32_t fuse94 = 0; | |
idStrToBin(idStr, id); | |
printf("Encrypted ID:\n "); | |
printId(id); | |
decryptId(id, plainId, &fuse90, &fuse94); | |
printf("\nDecrypted ID:\n "); | |
printId(plainId); | |
printf("\n"); | |
printf(" fuse90 = 0x%8.8X\n", fuse90); | |
printf(" fuse94 = 0x%8.8X\n", fuse94); | |
printf(" FuseID = %X%8.8X\n", fuse94, fuse90); | |
uint8_t newId[16] = {0}; | |
char newIdStr[64] = {0}; | |
generateId(fuse90, fuse94, newId, newIdStr); | |
printf("Re-encrypted ID (using above fuse):\n %s\n", newIdStr); | |
printf("Comparison of encrypted ID and re-encrypted ID:\n %s\n", (memcmp(newId, id, 16) == 0 ? "MATCH" : "NO MATCH")); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment