Skip to content

Instantly share code, notes, and snippets.

@Linblow
Created April 2, 2025 07:32
Show Gist options
  • Save Linblow/68de00bc117c38c40c7edc25a7b31d95 to your computer and use it in GitHub Desktop.
Save Linblow/68de00bc117c38c40c7edc25a7b31d95 to your computer and use it in GitHub Desktop.
Decrypt/encrypt TiltFX id.txt file contents
/* 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