librecmc : Bump to v1.5.15
[librecmc/librecmc.git] / tools / firmware-utils / src / buffalo-enc.c
1 /*
2  * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published
6  * by the Free Software Foundation.
7  *
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stdint.h>
13 #include <string.h>
14 #include <libgen.h>
15 #include <getopt.h>     /* for getopt() */
16 #include <stdarg.h>
17
18 #include "buffalo-lib.h"
19
20 #define ERR(fmt, args...) do { \
21         fflush(0); \
22         fprintf(stderr, "[%s] *** error: " fmt "\n", \
23                         progname, ## args ); \
24 } while (0)
25
26 static char *progname;
27 static char *ifname;
28 static char *ofname;
29 static char *crypt_key = "Buffalo";
30 static char *magic = "start";
31 static int longstate;
32 static unsigned char seed = 'O';
33
34 static char *product;
35 static char *version;
36 static int do_decrypt;
37 static int offset;
38 static int size;
39
40 void usage(int status)
41 {
42         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
43
44         fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
45         fprintf(stream,
46 "\n"
47 "Options:\n"
48 "  -d              decrypt instead of encrypt\n"
49 "  -i <file>       read input from the file <file>\n"
50 "  -o <file>       write output to the file <file>\n"
51 "  -l              use longstate {en,de}cryption method\n"
52 "  -k <key>        use <key> for encryption (default: Buffalo)\n"
53 "  -m <magic>      set magic to <magic>\n"
54 "  -p <product>    set product name to <product>\n"
55 "  -v <version>    set version to <version>\n"
56 "  -h              show this screen\n"
57 "  -O              Offset of encrypted data in file (decryption)\n"
58 "  -S              Size of unencrypted data in file (encryption)\n"
59         );
60
61         exit(status);
62 }
63
64 static int decrypt_file(void)
65 {
66         struct enc_param ep;
67         ssize_t src_len;
68         unsigned char *buf = NULL;
69         int err;
70         int ret = -1;
71
72         src_len = get_file_size(ifname);
73         if (src_len < 0) {
74                 ERR("unable to get size of '%s'", ifname);
75                 goto out;
76         }
77
78         buf = malloc(src_len);
79         if (buf == NULL) {
80                 ERR("no memory for the buffer");
81                 goto out;
82         }
83
84         err = read_file_to_buf(ifname, buf, src_len);
85         if (err) {
86                 ERR("unable to read from file '%s'", ifname);
87                 goto out;
88         }
89
90         memset(&ep, '\0', sizeof(ep));
91         ep.key = (unsigned char *) crypt_key;
92         ep.longstate = longstate;
93
94         err = decrypt_buf(&ep, buf + offset, src_len - offset);
95         if (err) {
96                 ERR("unable to decrypt '%s'", ifname);
97                 goto out;
98         }
99
100         printf("Magic\t\t: '%s'\n", ep.magic);
101         printf("Seed\t\t: 0x%02x\n", ep.seed);
102         printf("Product\t\t: '%s'\n", ep.product);
103         printf("Version\t\t: '%s'\n", ep.version);
104         printf("Data len\t: %u\n", ep.datalen);
105         printf("Checksum\t: 0x%08x\n", ep.csum);
106
107         err = write_buf_to_file(ofname, buf + offset, ep.datalen);
108         if (err) {
109                 ERR("unable to write to file '%s'", ofname);
110                 goto out;
111         }
112
113         ret = 0;
114
115 out:
116         free(buf);
117         return ret;
118 }
119
120 static int encrypt_file(void)
121 {
122         struct enc_param ep;
123         ssize_t src_len, tail_dst, tail_len, tail_src;
124         unsigned char *buf;
125         uint32_t hdrlen;
126         ssize_t totlen = 0;
127         int err;
128         int ret = -1;
129
130         src_len = get_file_size(ifname);
131         if (src_len < 0) {
132                 ERR("unable to get size of '%s'", ifname);
133                 goto out;
134         }
135
136         if (size) {
137                 tail_dst = enc_compute_buf_len(product, version, size);
138                 tail_len = src_len - size;
139                 totlen = tail_dst + tail_len;
140         } else
141                 totlen = enc_compute_buf_len(product, version, src_len);
142
143         buf = malloc(totlen);
144         if (buf == NULL) {
145                 ERR("no memory for the buffer");
146                 goto out;
147         }
148
149         hdrlen = enc_compute_header_len(product, version);
150
151         err = read_file_to_buf(ifname, &buf[hdrlen], src_len);
152         if (err) {
153                 ERR("unable to read from file '%s'", ofname);
154                 goto free_buf;
155         }
156
157         if (size) {
158                 tail_src = hdrlen + size;
159                 memmove(&buf[tail_dst], &buf[tail_src], tail_len);
160                 memset(&buf[tail_src], 0, tail_dst - tail_src);
161                 src_len = size;
162         }
163
164         memset(&ep, '\0', sizeof(ep));
165         ep.key = (unsigned char *) crypt_key;
166         ep.seed = seed;
167         ep.longstate = longstate;
168         ep.csum = buffalo_csum(src_len, &buf[hdrlen], src_len);
169         ep.datalen = src_len;
170         strcpy((char *) ep.magic, magic);
171         strcpy((char *) ep.product, product);
172         strcpy((char *) ep.version, version);
173
174         err = encrypt_buf(&ep, buf, &buf[hdrlen]);
175         if (err) {
176                 ERR("invalid input file");
177                 goto free_buf;
178         }
179
180         err = write_buf_to_file(ofname, buf, totlen);
181         if (err) {
182                 ERR("unable to write to file '%s'", ofname);
183                 goto free_buf;
184         }
185
186         ret = 0;
187
188 free_buf:
189         free(buf);
190 out:
191         return ret;
192 }
193
194 static int check_params(void)
195 {
196         int ret = -1;
197
198         if (ifname == NULL) {
199                 ERR("no input file specified");
200                 goto out;
201         }
202
203         if (ofname == NULL) {
204                 ERR("no output file specified");
205                 goto out;
206         }
207
208         if (crypt_key == NULL) {
209                 ERR("no key specified");
210                 goto out;
211         } else if (strlen(crypt_key) > BCRYPT_MAX_KEYLEN) {
212                 ERR("key '%s' is too long", crypt_key);
213                 goto out;
214         }
215
216         if (strlen(magic) != (ENC_MAGIC_LEN - 1)) {
217                 ERR("length of magic must be %d", ENC_MAGIC_LEN - 1);
218                 goto out;
219         }
220
221         if (!do_decrypt) {
222                 if (product == NULL) {
223                         ERR("no product specified");
224                         goto out;
225                 }
226
227                 if (version == NULL) {
228                         ERR("no version specified");
229                         goto out;
230                 }
231
232                 if (strlen(product) > (ENC_PRODUCT_LEN - 1)) {
233                         ERR("product name '%s' is too long", product);
234                         goto out;
235                 }
236
237                 if (strlen(version) > (ENC_VERSION_LEN - 1)) {
238                         ERR("version '%s' is too long", version);
239                         goto out;
240                 }
241         }
242
243         ret = 0;
244
245 out:
246         return ret;
247 }
248
249 int main(int argc, char *argv[])
250 {
251         int res = EXIT_FAILURE;
252         int err;
253
254         progname = basename(argv[0]);
255
256         while ( 1 ) {
257                 int c;
258
259                 c = getopt(argc, argv, "adi:m:o:hlp:v:k:O:r:s:S:");
260                 if (c == -1)
261                         break;
262
263                 switch (c) {
264                 case 'd':
265                         do_decrypt = 1;
266                         break;
267                 case 'i':
268                         ifname = optarg;
269                         break;
270                 case 'l':
271                         longstate = 1;
272                         break;
273                 case 'm':
274                         magic = optarg;
275                         break;
276                 case 'o':
277                         ofname = optarg;
278                         break;
279                 case 'p':
280                         product = optarg;
281                         break;
282                 case 'v':
283                         version = optarg;
284                         break;
285                 case 'k':
286                         crypt_key = optarg;
287                         break;
288                 case 's':
289                         seed = strtoul(optarg, NULL, 16);
290                         break;
291                 case 'O':
292                         offset = strtoul(optarg, NULL, 0);
293                         break;
294                 case 'S':
295                         size = strtoul(optarg, NULL, 0);
296                         break;
297                 case 'h':
298                         usage(EXIT_SUCCESS);
299                         break;
300                 default:
301                         usage(EXIT_FAILURE);
302                         break;
303                 }
304         }
305
306         err = check_params();
307         if (err)
308                 goto out;
309
310         if (do_decrypt)
311                 err = decrypt_file();
312         else
313                 err = encrypt_file();
314
315         if (err)
316                 goto out;
317
318         res = EXIT_SUCCESS;
319
320 out:
321         return res;
322 }