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