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