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