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