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