root/tools/packfi2/fi2enc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _strlwr
  2. read32_be
  3. store32_be
  4. align128
  5. get_hexstring
  6. fi2rec_size
  7. fi2enc
  8. main

   1 // fi2encdec v1.0

   2 
   3 #include <stdio.h>
   4 #include <stdint.h>
   5 #include <stdlib.h>
   6 #include <memory.h>
   7 #include <string.h>
   8 #include <ctype.h>
   9 #include "zlib.h"
  10 
  11 #include "aes128.h"
  12 
  13 static const char *g_str_err_malloc = "memory allocation error (requested %d bytes)\n";
  14 static const char *g_str_shorthelp = "Usage: fi2encdec [-p PID] [-key KEY -iv IV] [-x FLAGS] in.file out.file\n"
  15                                      "    FLAGS: one or more of the following letters\n"
  16                                      "           W: checksum is word based (on new models)\n"
  17                                      "\n";
  18 
  19 char *_strlwr(char *moep) {
  20      char *tmp = moep;
  21      while((*tmp = tolower(*tmp)))  tmp++;
  22      return moep;
  23 } 
  24 
  25 // FI2 block record

  26 struct fi2_rec_s {
  27         uint32_t        offset;         // Offset in data block

  28         uint32_t        upklen;         // Real (unpacked) size of data block

  29         uint32_t        len;            // Length of compressed and padded data block

  30         uint32_t        addr;           // target address for data block

  31         uint32_t        uf1;            // unknown flag 1

  32         uint32_t        fmain;          // Main FW block flag

  33         uint32_t        fboot;          // Bootloader block flag

  34         uint32_t        uf2;            // unknown flag 2

  35         uint32_t        uf3;            // unknown flag 3 (new in DryOS 50)

  36     uint32_t    uf4;        // unknown flag 4 (seen in a DryOS r55 file)

  37 } fi2_rec_s;
  38 
  39 // FI2 header (with size field)

  40 typedef struct fi2_header_s {
  41         uint32_t        hlen_be;        // Header length in big endian

  42         uint32_t        hwid;           // Hardware ID

  43         uint32_t        unk1;           // unk1 field (0x02230000)

  44         uint32_t        id;                     // ID field   (0x01000000)

  45         uint32_t        ch;                     // Ch field   (0x00000000)

  46         uint32_t        unk2;           // unk2 field (0x00000001)

  47         uint32_t        nblk;           // number of blocks & records

  48         uint32_t        datacs;         // checksum of encrypted data block

  49 } fi2_hdr_t, *pfi2_hdr_t; 
  50 
  51 static uint32_t read32_be( const void *src_buffer )
  52 {
  53         unsigned char *b = (unsigned char *)src_buffer;
  54         return (b[0]<<24) | (b[1] << 16) | (b[2] << 8) | b[3];
  55 }
  56 
  57 static void store32_be( void *dst_buffer, uint32_t value )
  58 {
  59         unsigned char *b = (unsigned char *)dst_buffer;
  60         b[0] = ( value >> 24 ) & 0xFF;
  61         b[1] = ( value >> 16 ) & 0xFF;
  62         b[2] = ( value >>  8 ) & 0xFF;
  63         b[3] = ( value >>  0 ) & 0xFF;
  64 }
  65 
  66 static uint32_t align128( uint32_t value )
  67 {
  68         return ( (value + 16 - 1) & 0xFFFFFFF0ul );
  69 }
  70 
  71 static int get_hexstring( void *dst, const char *str, int len )
  72 {
  73         int i;
  74         unsigned char c;
  75         unsigned char *p = (unsigned char *)dst;
  76 
  77         if( !str ){
  78                 printf( "No hex string supplied!\n" );
  79                 return -1;
  80         }
  81         if( !p ) return -1;
  82         if( strlen( str ) != len*2 ){
  83                 printf( "Hex length mismatch in \"%s\"!\n", str );
  84                 return -1;
  85         }
  86         for( i = 0; i < len*2; i++ ){
  87                 c = str[i];
  88                 if( c < ('9'+1) && c >= '0' ) c-= 0x30;
  89                 else if( c < 'G' && c >= 'A' ) c -= ('A' - 0x0A);
  90                 else if( c < 'g' && c >= 'a' ) c -= ('a' - 0x0A);
  91                 else {
  92                         printf("Non-hex character \'%c\' at %d in string %s\n", c, i+1, str );
  93                         return -1;
  94                 }
  95                 p[i/2] = i & 1 ? p[i/2] | c : c << 4;
  96         }
  97         return 0;
  98 }
  99 
 100 static int fi2rec_size(uint32_t dryos_ver)
 101 {
 102     // return the correct size to use for the block record

 103     if (dryos_ver >= 55)
 104     {
 105         return sizeof (fi2_rec_s);
 106     }
 107     else if (dryos_ver >= 50)
 108     {
 109         return sizeof (fi2_rec_s) - 4; // exclude the new R50 extra value

 110     }
 111     else
 112     {
 113         return sizeof (fi2_rec_s) - 8; // exclude the new R55 extra value too

 114     }
 115 }
 116 
 117 static int fi2enc( char *infname, char *outfname, uint32_t *key, uint32_t *iv , uint32_t pid, uint32_t dryos_ver,
 118                    int32_t cs_words)
 119 {
 120         unsigned long i;
 121         size_t flen;
 122         uint32_t cs;
 123         FILE *fi, *fo;
 124         fi2_hdr_t hdr;
 125         struct fi2_rec_s  fi2rec;
 126         unsigned char *buf = NULL;
 127         unsigned char *upkbuf = NULL;
 128         unsigned char exkey[176];
 129         unsigned char *pblk;
 130 
 131         if( !infname ){
 132                 printf("Please supply input file name.\n");
 133                 return -1;
 134         }
 135         if( !outfname ){
 136                 printf("Please supply target file name.\n");
 137                 return -1;
 138         }
 139         aes128_expandkey( exkey, key );
 140         cs = 0;
 141         memset(&hdr, 0, sizeof (hdr));
 142         memset(&fi2rec, 0, sizeof (fi2rec));
 143         hdr.hwid=pid;
 144         hdr.unk1=0x02230000;
 145         hdr.id=0x01010000;
 146         hdr.ch=0;
 147         hdr.unk2=1;
 148         fi2rec.addr=0;
 149         fi2rec.fboot = 1;
 150         if ( !(fi = fopen(infname, "rb")) ){
 151                 printf( "Can't open data file %s\n", infname );
 152                 return -1;
 153         }
 154         fseek( fi, 0, SEEK_END );
 155         flen = ftell( fi );
 156         fseek( fi, 0, SEEK_SET );
 157 
 158         if( flen <= 0 || flen > (256  << 20) ){                         // file size sanity check (256MB max)

 159                 printf( "Data file %s have unacceptable file size (%ld)\n", infname, (unsigned long) flen );
 160                 return -1;
 161         }
 162         upkbuf = (unsigned char*)malloc( flen );                        // allocate buffer for data file

 163         if( !upkbuf ){
 164                 printf( g_str_err_malloc, flen );
 165                 return -1;
 166         }
 167         if( flen > fread( upkbuf, 1, flen, fi ) ){
 168                 printf( "Error reading data file\n" );
 169                 return -1;
 170         }
 171         fclose( fi );
 172         i = align128( 4 + compressBound( flen ) );                      // determine upper bound for compressed block buffer

 173         buf = (unsigned char*)malloc( i );                                      // allocate buffer for compressed block + blocksize

 174         if( !buf ){
 175                 printf( g_str_err_malloc, i );
 176                 return -1;
 177         }
 178         memset( buf, 0xFF, i );
 179         i -= 4;
 180         if( Z_OK !=    compress( buf + 4, (uLongf*)&i, upkbuf, flen ) ){ 
 181                 printf( "Data compression error\n" );
 182                 return -1;
 183         }
 184         store32_be( buf, i );                                                           // store real compressed block size

 185         fi2rec.upklen = flen;
 186         fi2rec.offset = 0;                                              // save data block offset

 187         fi2rec.len = align128( i + 4 );
 188         // encrypt data block

 189         aes128_cbc_encrypt( buf, exkey, iv, fi2rec.len );
 190         pblk = buf;                                                                     
 191     if (cs_words) {
 192         uint32_t *wbuf = (uint32_t*)buf;
 193         for( i = 0; i < (int)fi2rec.len/4; i++) cs += wbuf[i];  // update block checksum

 194     }
 195     else {
 196         for( i = 0; i < (int)fi2rec.len; i++) cs += buf[i];     // update block checksum

 197     }
 198 
 199         free( upkbuf ); upkbuf = NULL;
 200         // process next block

 201         // finalize header

 202         i = 32 + fi2rec_size(dryos_ver);
 203     i = align128(i); // header needs to be aligned

 204         store32_be( &hdr.hlen_be, i - 4 );
 205         hdr.nblk = 1;
 206         hdr.datacs = cs;
 207         buf = (unsigned char*)malloc( i );                                                      // allocate buffer for encrypted header

 208         if( !buf ){
 209                 printf( g_str_err_malloc, i );
 210                 return -1;
 211         }
 212     memset( buf, 0, i );
 213         memcpy( buf, &hdr, 32 );
 214         memcpy( buf+32, &fi2rec, fi2rec_size(dryos_ver));
 215         aes128_cbc_encrypt( buf, exkey, iv, i );
 216 
 217         // ---------------------------- save results ------------------------------

 218         // open target file

 219         printf( "Saving %s\n", outfname );
 220         fo = fopen(outfname,"wb");
 221         if(!fo){
 222                 printf("Can't open file %s for writing\n", outfname);
 223                 return(-1);
 224         }
 225         // save header

 226         if ( i != fwrite(buf, 1, i, fo ) ){
 227                 printf("\nError writing header to %s (%ld bytes)\n", outfname, i);
 228                 return(-1);
 229         }
 230         free( buf );
 231         // save data blocks

 232                 if (fi2rec.len != fwrite( pblk, 1, fi2rec.len, fo ) ){
 233                         printf("\nError writing data block to %s (%d bytes)\n", outfname, fi2rec.len);
 234                         return(-1);
 235                 }
 236                 free( pblk );
 237         fclose( fo );
 238         return 0;
 239 }
 240 
 241 int main( int argc, char **argv )
 242 {
 243         int i;
 244         uint32_t key_buf[4];
 245         uint32_t iv_buf[4];
 246         uint32_t *key = NULL;
 247         uint32_t *iv = NULL;
 248         char *fni = NULL, *fno = NULL;
 249         uint32_t pid=0;
 250     uint32_t dryos_ver=0;
 251     char *flags = NULL;
 252     int32_t cs_words = 0;
 253 
 254         // parse command line

 255         for( i = 1; i < argc; i++){
 256                 if( argv[i][0] == '/' || argv[i][0] == '-' ){   // ---- arg is option

 257                         
 258                         if( !strcmp( "key", _strlwr(argv[i]+1) ) ){                                             // opt: key

 259                                 if ( get_hexstring( key_buf, argv[++i], sizeof key_buf ) ) return -1;
 260                                 else key = key_buf;
 261                         }
 262                         else if( !strcmp( "iv", _strlwr(argv[i]+1) ) ){                                                 // opt: iv

 263                                 if ( get_hexstring( iv_buf, argv[++i], sizeof iv_buf ) ) return -1;
 264                                 else iv = iv_buf;
 265                         }
 266                         else if( !strcmp( "p", _strlwr(argv[i]+1) ) ){                                          // opt: pid

 267                                 char *err=NULL;
 268                                 pid = strtoul(argv[++i], &err, 0);
 269                                 if (*err) return -1;
 270                         }
 271                         else if( !strcmp( "pv", _strlwr(argv[i]+1) ) ){                                         // opt: dryos_ver

 272                                 char *err=NULL;
 273                                 dryos_ver = strtoul(argv[++i], &err, 0);
 274                                 if (*err) return -1;
 275                         }
 276                         else if( !strcmp( "x", _strlwr(argv[i]+1) ) ){ // extra flags, single string without spaces

 277                                 flags = argv[++i];
 278                         }
 279                         else {
 280                                 printf("Unexpected option: %s\n", argv[i]);
 281                                 return -1;
 282                         }
 283                 } else {        // ---- arg is not an option

 284                         if( !fni ) fni = argv[i];               // 1st non-option is input file name

 285                         else if( !fno ) fno = argv[i];  // 2nd non-option is output file name

 286                         else {
 287                                 printf("Unexpected parameter: %s\n", argv[i]);
 288                                 return -1;
 289                         }
 290                 }
 291         }
 292         if( !key || !iv || !pid){
 293                 fputs( g_str_shorthelp, stdout );
 294                 return -1;
 295         }
 296     if (flags) {
 297         if ( strstr(flags, "W") ) {
 298             cs_words = 1;
 299         }
 300     }
 301         for( i = 0; i < 4; i ++ )  key[i] = read32_be( key+i );
 302         i = fi2enc( fni, fno, key, iv , pid, dryos_ver, cs_words);
 303         if ( !i ) printf( "Done\n" );   else printf( "Failed!\n" );
 304         return i;
 305 }

/* [<][>][^][v][top][bottom][index][help] */