image_formats:tplink

TP-Link Switch Image Format

This page is WiP and details the TP-Link image format header as found in various Realtek-based switches.

  • The whole file is DES CBC encrypted - IV and Key are known
  • There is a 512 Byte header, the structure is known
  • The header MD5 sum matches if the last 128 bytes of the decrypted image are omitted or zeroed
  • There are about 8000 bytes of data at the end of the image that are not part of any partition; that's a lot of zeros, the product ID, 200 bytes of base64 data (maybe an RSA signature?)

IV and Key can be extracted from the U-Boot source at common/DesDecode.c. There are the two variables:

unsigned char des_key[] = 
{
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
};
unsigned char des_iv[] = 
{
  0xf5,0x10,0x10,0x73,0x6e,0xfb,0xab,0xb2
};

With this knowledge, we can use openssl to decode the image:

openssl enc -d -des-cbc -in encrypted.bin -out decrypted.bin -nosalt -nopad -p -iv f51010736efbabb2 -K 0001020304050607

Note: this may require legacy providers to be enabled for recent version of openssl

The image itself contains a 512 byte header. The structure can also be found in the U-Boot source code at include/tplink/flashAppFsImage.h:

#define MD5_CHECKSUM_OFFSET	0
#define MD5_DIGEST_LEN		16
#define FLASH_PRODUCT_LENGTH 	16
#define TP_IMAGE_NAME_SIZE	200
#define TP_IMAGE_HEADER_SIZE	512
#define FL_SIZE_LEN             16  /* "0x100000" */
#define FL_VER_LEN              16   /* "0x10000" */

typedef struct
{
    char            md5[MD5_DIGEST_LEN];
    unsigned char   productId[FLASH_PRODUCT_LENGTH];
    char	    imagename[TP_IMAGE_NAME_SIZE];
    UINT32          usrImageSize;
    UINT32          uImageSize;
    UINT32          bootromSize;
    UINT32          compressMethod;
    char            flBootSize[FL_SIZE_LEN];
    char            flKernelOffset[FL_SIZE_LEN];
    char            flKernelSize[FL_SIZE_LEN];
    char            flUsrImg1Offset[FL_SIZE_LEN];
    char            flUsrImg1Size[FL_SIZE_LEN];
    char            flUsrImg2Offset[FL_SIZE_LEN];
    char            flUsrImg2Size[FL_SIZE_LEN];
    char            flUsrAppOffset[FL_SIZE_LEN];
    char            flUsrAppSize[FL_SIZE_LEN];
    char            flVer[FL_VER_LEN];
}_TP_IMAGE_HEADER;

In the T2500G-10TS GPL archive, the common/flashAppFsImage.c has a (commented out) section on MD5 and checksum calculation.

The header MD5 sum matches, given the following:

  • The header MD5 sum needs to be zeroed (=salt)
  • The last 128 bytes of the image, an RSA signature, need to be truncated.

The RSA signature contained in the last 128, signs the 16 MD5 checksum bytes. The public key of the certificate is contained in the aforementioned source file as a BASE64 string.

There is an embedded RSA public key towards the end of the image. Upon decoding, the string "RSA1" pops up, it is most likely an RSA Public Key Blob. Its purpose is yet unknown, but:

  • All firmware version for the T1600G-52PS have the same key
  • The latest firmware versions for the T1500G-10MPS and the T2500G-10TS have the same key (others not checked)
  • image_formats/tplink.txt
  • Last modified: 2022/08/13 07:56
  • by svanheule