• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/mkhilinkfw.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2013 Jeff Kent <jeff@jkent.net>
  4  *
  5  * This tool encrypts and decrypts uImage formatted firmware for Hilink
  6  * HLK-RM04 wireless modules.  It will also truncate a dump of mtd6 and make
  7  * it an image suitable for flashing via the stock firmware upgrade page.
  8  *
  9  * Build instructions: 
 10  *   gcc -lcrypto hlkcrypt.c -o hlkcrypt
 11  */
 12  
 13 #include <arpa/inet.h>
 14 #include <errno.h>
 15 #include <fcntl.h>
 16 #include <getopt.h>
 17 #include <openssl/des.h>
 18 #include <stdint.h>
 19 #include <stdio.h>
 20 #include <stdlib.h>
 21 #include <string.h>
 22 #include <sys/mman.h>
 23 #include <sys/types.h>
 24 #include <sys/stat.h>
 25 #include <unistd.h>
 26  
 27 #define DES_KEY "H@L9K*(3"
 28  
 29 #ifndef min
 30 #define min(a,b) \
 31    ({ __typeof__ (a) _a = (a); \
 32        __typeof__ (b) _b = (b); \
 33      _a < _b ? _a : _b; })
 34 #endif
 35  
 36 #define IH_MAGIC    0x27051956
 37 #define IH_NMLEN    32
 38 typedef struct image_header {
 39     uint32_t    ih_magic;   /* Image Header Magic Number    */
 40     uint32_t    ih_hcrc;    /* Image Header CRC Checksum    */
 41     uint32_t    ih_time;    /* Image Creation Timestamp */
 42     uint32_t    ih_size;    /* Image Data Size      */
 43     uint32_t    ih_load;    /* Data  Load  Address      */
 44     uint32_t    ih_ep;      /* Entry Point Address      */
 45     uint32_t    ih_dcrc;    /* Image Data CRC Checksum  */
 46     uint8_t     ih_os;      /* Operating System     */
 47     uint8_t     ih_arch;    /* CPU architecture     */
 48     uint8_t     ih_type;    /* Image Type           */
 49     uint8_t     ih_comp;    /* Compression Type     */
 50     uint8_t     ih_name[IH_NMLEN];  /* Image Name       */
 51 } image_header_t;
 52  
 53 static int temp_fd = -1;
 54 static DES_key_schedule schedule;
 55  
 56 static void show_usage(const char *arg0);
 57 static void exit_cleanup(void);
 58 static void copy_file(int src, int dst);
 59 static void do_encrypt(void *p, off_t len);
 60 static void do_decrypt(void *p, off_t len);
 61  
 62  
 63 int main(int argc, char **argv)
 64 {
 65         int encrypt_opt = 0;
 66         int decrypt_opt = 0;
 67         int input_opt = 0;
 68         int output_opt = 0;
 69         char *input_filename = NULL;
 70         char *output_filename = NULL;
 71  
 72         int input_fd;
 73         int output_fd;
 74         off_t file_len;
 75         char *p;
 76         char buf[sizeof(image_header_t) + 3];
 77         image_header_t *header;
 78  
 79         while (1) {
 80                 static struct option long_options[] = {
 81                         {"encrypt", no_argument,       0, 'e'},
 82                         {"decrypt", no_argument,       0, 'd'},
 83                         {"input",   required_argument, 0, 'i'},
 84                         {"output",  required_argument, 0, 'o'},
 85                         {0,         0,                 0, 0  }
 86                 };
 87                 int option_index = 0;
 88                 int c = getopt_long(argc, argv, "dei:o:",
 89                                 long_options, &option_index);
 90                 if (c == -1)
 91                         break;
 92  
 93                 switch (c) {
 94                 case 'd':
 95                         decrypt_opt++;
 96                         if (decrypt_opt > 1) {
 97                                 fprintf(stderr, "%s: decrypt may only be specified once\n",
 98                                         argv[0]);
 99                                 show_usage(argv[0]);
100                         }
101                         break;
102  
103                 case 'e':
104                         encrypt_opt++;
105                         if (encrypt_opt > 1) {
106                                 fprintf(stderr, "%s: encrypt may only be specified once\n",
107                                         argv[0]);
108                                 show_usage(argv[0]);
109                         }
110                         break;
111  
112                 case 'i':
113                         input_opt++;
114                         if (input_opt > 1) {
115                                 fprintf(stderr, "%s: only one input file may be specified\n",
116                                         argv[0]);
117                                 show_usage(argv[0]);
118                         }
119                         if (strcmp("-", optarg) != 0) {
120                                 input_filename = optarg;
121                         }
122                         break;
123  
124                 case 'o':
125                         output_opt++;
126                         if (output_opt > 1) {
127                                 fprintf(stderr, "%s: only one output file may be specified\n",
128                                         argv[0]);
129                                 show_usage(argv[0]);
130                         }
131                         if (strcmp("-", optarg) != 0) {
132                                 output_filename = optarg;
133                         }
134                         break;
135  
136                 case '?':
137                         exit(-1);
138  
139                 default:
140                         abort();
141                 }
142         }
143  
144         if (decrypt_opt && encrypt_opt) {
145                 fprintf(stderr, "%s: decrypt and encrypt may not be used together\n",
146                         argv[0]);
147                 show_usage(argv[0]);
148         }
149  
150         if (!decrypt_opt && !encrypt_opt) {
151                 fprintf(stderr, "%s: neither decrypt or encrypt were specified\n",
152                         argv[0]);
153                 show_usage(argv[0]);
154         }
155  
156         temp_fd = fileno(tmpfile());
157         if (temp_fd < 0) {
158                 fprintf(stderr, "Can't create temporary file\n");
159                 exit(EXIT_FAILURE);
160         }
161  
162         atexit(exit_cleanup);
163         DES_set_key_unchecked((const_DES_cblock *)DES_KEY, &schedule);
164  
165         if (input_filename) {
166                 input_fd = open(input_filename, O_RDONLY);
167                 if (input_fd < 0) {
168                         fprintf(stderr, "Can't open %s for reading: %s\n", input_filename,
169                                 strerror(errno));
170                         exit(EXIT_FAILURE);
171                 }
172                 copy_file(input_fd, temp_fd);
173                 close(input_fd);
174         }
175         else {
176                 copy_file(STDIN_FILENO, temp_fd);
177         }
178  
179         file_len = lseek(temp_fd, 0, SEEK_CUR);
180         if (file_len < 64) {
181                 fprintf(stderr, "Not enough data\n");
182                 exit(EXIT_FAILURE);
183         }
184  
185         p = mmap(0, file_len, PROT_READ|PROT_WRITE, MAP_SHARED, temp_fd, 0);
186         if (p == MAP_FAILED) {
187                 fprintf(stderr, "mmap failed: %s\n", strerror(errno));
188                 exit(EXIT_FAILURE);
189         }       
190  
191         if (encrypt_opt) {
192                 header = (image_header_t *)p;
193                 off_t len = min(file_len,
194                                 ntohl(header->ih_size) + sizeof(image_header_t));
195                 if (ntohl(header->ih_magic) != IH_MAGIC) {
196                         fprintf(stderr, "Header magic incorrect: "
197                                 "expected 0x%08X, got 0x%08X\n",
198                                 IH_MAGIC, ntohl(header->ih_magic));
199                         munmap(p, file_len);
200                         exit(EXIT_FAILURE);
201                 }
202                 do_encrypt(p, len);
203                 munmap(p, file_len);
204                 if (len != file_len) {
205                         if (ftruncate(temp_fd, len) < 0) {
206                                 fprintf(stderr, "ftruncate failed: %s\n", strerror(errno));
207                                 exit(EXIT_FAILURE);
208                         }
209                 }               
210         }
211  
212         if (decrypt_opt) {
213                 off_t header_len = min(file_len, sizeof(image_header_t) + 3);
214                 memcpy(buf, p, header_len);
215                 do_decrypt(buf, header_len);
216                 header = (image_header_t *)buf;
217                 if (ntohl(header->ih_magic) != IH_MAGIC) {
218                         fprintf(stderr, "Header magic incorrect: "
219                                 "expected 0x%08X, got 0x%08X\n",
220                                 IH_MAGIC, ntohl(header->ih_magic));
221                         exit(EXIT_FAILURE);
222                 }
223                 do_decrypt(p, file_len);
224                 munmap(p, file_len);
225         }
226  
227         lseek(temp_fd, 0, SEEK_SET);
228         if (output_filename) {
229                 output_fd = creat(output_filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
230                 if (output_fd < 0) {
231                         fprintf(stderr, "Can't open %s for writing: %s\n",
232                                 output_filename, strerror(errno));
233                         exit(EXIT_FAILURE);
234                 }
235                 copy_file(temp_fd, output_fd);
236                 close(output_fd);
237         }
238         else {
239                 copy_file(temp_fd, STDOUT_FILENO);
240         }
241  
242         exit(EXIT_SUCCESS);
243         return 0;
244 }
245  
246 static void show_usage(const char *arg0)
247 {
248         fprintf(stderr, "usage: %s -d|-e [-i FILE] [-o FILE]\n\n", arg0);
249         fprintf(stderr, "%-15s %s\n", "-d, --decrypt", "decrypt data");
250         fprintf(stderr, "%-15s %s\n", "-e, --encrypt", "encrypt data");
251         fprintf(stderr, "%-15s %s\n", "-i, --input", "intput file (defaults to stdin)");
252         fprintf(stderr, "%-15s %s\n", "-o, --output", "output file (defaults to stdout)");
253         exit(-1);
254 }
255  
256 static void exit_cleanup(void)
257 {
258         if (temp_fd >= 0) {
259                 close(temp_fd);
260         }
261 }
262  
263 static void copy_file(int src, int dst)
264 {
265         char buf[4096];
266         ssize_t size;
267  
268         while ((size = read(src, buf, 4096)) > 0) {
269         write(dst, buf, size);
270     }
271 }
272  
273 static void do_encrypt(void *p, off_t len)
274 {
275         DES_cblock *pblock;
276         int num_blocks;
277  
278         num_blocks = len / 8;
279         pblock = (DES_cblock *) p;
280         while (num_blocks--) {
281                 DES_ecb_encrypt(pblock, pblock, &schedule, DES_ENCRYPT);
282                 pblock++;
283         }
284  
285         num_blocks = (len - 3) / 8;
286         pblock = (DES_cblock *) (p + 3);
287         while (num_blocks--) {
288                 DES_ecb_encrypt(pblock, pblock, &schedule, DES_ENCRYPT);
289                 pblock++;
290         }
291 }
292  
293 static void do_decrypt(void *p, off_t len)
294 {
295         DES_cblock *pblock;
296         int num_blocks;
297  
298         num_blocks = (len - 3) / 8;
299         pblock = (DES_cblock *) (p + 3);
300         while (num_blocks--) {
301                 DES_ecb_encrypt(pblock, pblock, &schedule, DES_DECRYPT);
302                 pblock++;
303         }
304  
305         num_blocks = len / 8;
306         pblock = (DES_cblock *) p;
307         while (num_blocks--) {
308                 DES_ecb_encrypt(pblock, pblock, &schedule, DES_DECRYPT);
309                 pblock++;
310         }
311 }
312 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt