1 /*
2 * Copyright (c) 2014-2018, Andrew Romanenko <melanhit@gmail.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <unistd.h>
35 #include <errno.h>
36
37 #include <config.h>
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42
43 #include <termios.h>
44
45 #include "../akmos.h"
46 #include "../error.h"
47
48 #include "cli.h"
49 #include "pw.h"
50 #include "cipher.h"
51
52 #define BUFLEN (BUFSIZ*2)
53
prompt_over(char * s)54 static int prompt_over(char *s)
55 {
56 int ans;
57
58 printf("Overwrite %s? [Y/n] ", s);
59
60 ans = getchar();
61
62 if(ans == EOF)
63 return 0;
64
65 if(ans == 'y' || ans == 'Y' || ans == '\n')
66 return 1;
67 else
68 return 0;
69 }
70
parse_algo(cipher_opt_t * opt,char * algo_str)71 static int parse_algo(cipher_opt_t *opt, char *algo_str)
72 {
73 char *s1, *s2, *sv;
74
75 if(!algo_str) {
76 fprintf(stderr, "Missing cipher algorithm\n");
77 return EXIT_FAILURE;
78 }
79
80 s1 = strtok_r(algo_str, ":", &sv);
81 s2 = strtok_r(NULL, ":", &sv);
82
83 if(!s2) {
84 if(strcasecmp(s1, algo_str) != 0) {
85 akmos_perror(AKMOS_ERR_ALGOID);
86 return EXIT_FAILURE;
87 }
88 opt->flag = 0;
89 } else {
90 if(strcasecmp(s2, "ede") == 0)
91 opt->flag = AKMOS_ALGO_FLAG_EDE;
92 else if(strcasecmp(s2, "eee") == 0)
93 opt->flag = AKMOS_ALGO_FLAG_EEE;
94 else {
95 fprintf(stderr, "Unknown cipher flag \'%s\'\n", s2);
96 return EXIT_FAILURE;
97 }
98 }
99
100 opt->algo = akmos_cipher_id(s1);
101 if(!opt->algo)
102 return akmos_perror(AKMOS_ERR_ALGOID);
103
104 return EXIT_SUCCESS;
105 }
106
parse_arg(cipher_opt_t * opt,int argc,char ** argv)107 static int parse_arg(cipher_opt_t *opt, int argc, char **argv)
108 {
109 char *algo_str, *mode_str, *keylen_str;
110 int c, err, len;
111
112 algo_str = mode_str = keylen_str = NULL;
113
114 while((c = getopt(argc, argv, "a:m:l:pP:k:i:yVh")) != -1) {
115 switch(c) {
116 case 'a':
117 algo_str = optarg;
118 opt->set.algo = c;
119 break;
120
121 case 'm':
122 mode_str = optarg;
123 opt->set.mode = c;
124 break;
125
126 case 'l':
127 keylen_str = optarg;
128 opt->set.keylen = c;
129 break;
130
131 case 'p':
132 opt->set.passw = c;
133 break;
134
135 case 'P':
136 opt->passf = optarg;
137 opt->set.passf = c;
138 break;
139
140 case 'k':
141 opt->key = optarg;
142 opt->set.key = c;
143 break;
144
145 case 'y':
146 opt->set.over = c;
147 break;
148
149 case 'V':
150 opt->ver = c;
151 return EXIT_SUCCESS;
152
153 case 'h':
154 default:
155 printf("Usage: akmos enc|dec [-a algo] [-m mode] [-k key] [-l keylen] [-p | -P passfile] [-y] [-h] [-V] <input> <output>\n");
156 return EXIT_FAILURE;
157 }
158 }
159
160 /* check input/output */
161 len = argc - optind;
162 switch(len) {
163 case 0:
164 opt->input = NULL;
165 opt->output = NULL;
166 break;
167
168 case 2:
169 opt->input = argv[optind];
170 opt->output = argv[optind + 1];
171 break;
172
173 default:
174 fprintf(stderr, "Missing <input> or <output>\n");
175 return EXIT_FAILURE;
176 }
177
178 /* set algo */
179 if(!opt->set.algo) {
180 opt->algo = CIPHER_DEFAULT_EALGO;
181 } else {
182 err = parse_algo(opt, algo_str);
183 if(err)
184 return err;
185 }
186
187 /* set mode */
188 if(!opt->set.mode) {
189 switch(opt->algo) {
190 case AKMOS_ALGO_SALSA:
191 case AKMOS_ALGO_CHACHA:
192 opt->mode = CIPHER_DEFAULT_SMODE;
193 break;
194
195 default:
196 opt->mode = CIPHER_DEFAULT_BMODE;
197 break;
198 }
199 } else {
200 if(mode_str) {
201 opt->mode = akmos_str2mode(mode_str);
202 if(!opt->mode)
203 return akmos_perror(AKMOS_ERR_MODEID);
204 }
205 }
206
207 if(!opt->set.key && !opt->set.passw && !opt->set.passf)
208 opt->set.passw = 'p';
209
210 /* set keylen */
211 if(!opt->set.keylen) {
212 switch(opt->algo) {
213 case AKMOS_ALGO_THREEFISH_256:
214 opt->keylen = 256;
215 break;
216
217 case AKMOS_ALGO_THREEFISH_512:
218 opt->keylen = 512;
219 break;
220
221 case AKMOS_ALGO_THREEFISH_1024:
222 opt->keylen = 1024;
223 break;
224
225 case AKMOS_ALGO_CHACHA:
226 opt->keylen = 256;
227 break;
228
229 default:
230 opt->keylen = CIPHER_DEFAULT_KEYLEN;
231 break;
232 }
233 } else {
234 if(keylen_str) {
235 err = sscanf(keylen_str, "%4zu", &opt->keylen);
236 if(err == EOF || !err)
237 return akmos_perror(AKMOS_ERR_KEYLEN);
238 }
239 }
240
241 if(opt->keylen > (CIPHER_MAX_KEYLEN*8) || opt->keylen == 0 || (opt->keylen % 8) != 0) {
242 fprintf(stderr, "Invalid key length (err = %d)\n", AKMOS_ERR_KEYLEN);
243 return EXIT_FAILURE;
244 }
245 opt->keylen /= 8;
246
247 if((opt->blklen = akmos_cipher_blklen(opt->algo)) == 0) {
248 fprintf(stderr, "Invalid cipher algorithm\n");
249 return EXIT_FAILURE;
250 }
251
252 /* read password */
253 if(opt->set.passw && opt->set.passf) {
254 fprintf(stderr, "Options -p and -P are mutually exlusive\n");
255 return EXIT_FAILURE;
256 }
257
258 if(opt->set.passw) {
259 err = pw_read_passw(opt->pass);
260 if(err)
261 return err;
262 }
263
264 if(opt->set.passf) {
265 err = pw_read_passf(opt->passf, opt->pass);
266 if(err)
267 return err;
268 }
269
270 if(opt->flag)
271 opt->algo |= opt->flag;
272
273 return EXIT_SUCCESS;
274 }
275
padbuf_hook(akmos_cipher_t ctx,uint8_t * buf,size_t * rlen,size_t blklen,akmos_mode_id enc)276 static int padbuf_hook(akmos_cipher_t ctx, uint8_t *buf, size_t *rlen, size_t blklen, akmos_mode_id enc)
277 {
278 size_t len, tmplen;
279
280 len = *rlen;
281
282 if(enc == AKMOS_MODE_ENCRYPT) {
283 tmplen = (len / blklen) * blklen;
284 akmos_padadd(buf + tmplen, len - tmplen, buf + tmplen, blklen);
285
286 akmos_cipher_crypt(ctx, buf + tmplen, blklen, buf + tmplen);
287
288 *rlen = tmplen + blklen;
289 }
290
291 if(enc == AKMOS_MODE_DECRYPT) {
292 if((len % blklen) != 0 || len < blklen)
293 return EXIT_FAILURE;
294
295 tmplen = akmos_padrem(buf + (len - blklen), blklen);
296 *rlen = len + tmplen - blklen;
297 }
298
299 return EXIT_SUCCESS;
300 }
301
header_encode(cipher_header_t * hd,uint8_t * buf)302 static int header_encode(cipher_header_t *hd, uint8_t *buf)
303 {
304 akmos_digest_t ctx;
305 int err;
306
307 hd->version = CIPHER_VERSION;
308
309 memcpy(buf, hd->iv, sizeof(hd->iv)); buf += sizeof(hd->iv);
310 memcpy(buf, hd->key, sizeof(hd->key)); buf += sizeof(hd->key);
311 *buf = hd->version; buf++;
312
313 if(hd->version == CIPHER_VERSION_V02) {
314 err = akmos_digest_init(&ctx, CIPHER_HEADER_MD);
315 if(err) {
316 akmos_perror(err);
317 return err;
318 }
319
320 akmos_digest_update(ctx, hd->iv, sizeof(hd->iv));
321 akmos_digest_update(ctx, hd->key, sizeof(hd->key));
322 akmos_digest_update(ctx, &hd->version, sizeof(hd->version));
323 akmos_digest_done(ctx, hd->md);
324
325 memcpy(buf, hd->md, sizeof(hd->md));
326 buf += sizeof(hd->md);
327 }
328
329 return EXIT_SUCCESS;
330 }
331
header_decode(uint8_t * buf,cipher_header_t * hd)332 static int header_decode(uint8_t *buf, cipher_header_t *hd)
333 {
334 akmos_digest_t ctx;
335 uint8_t md[CIPHER_HEADER_MDLEN];
336 int err;
337
338 memcpy(hd->iv, buf, sizeof(hd->iv)); buf += sizeof(hd->iv);
339 memcpy(hd->key, buf, sizeof(hd->key)); buf += sizeof(hd->key);
340
341 hd->version = *buf; buf++;
342 if(hd->version > CIPHER_VERSION) {
343 fprintf(stderr, "Invalid header version\n");
344 return EXIT_FAILURE;
345 }
346
347 if(hd->version == CIPHER_VERSION_V02) {
348 memcpy(hd->md, buf, sizeof(hd->md));
349
350 err = akmos_digest_init(&ctx, CIPHER_HEADER_MD);
351 if(err) {
352 akmos_perror(err);
353 return err;
354 }
355
356 akmos_digest_update(ctx, hd->iv, sizeof(hd->iv));
357 akmos_digest_update(ctx, hd->key, sizeof(hd->key));
358 akmos_digest_update(ctx, &hd->version, sizeof(hd->version));
359 akmos_digest_done(ctx, md);
360
361 if(memcmp(md, hd->md, sizeof(md)) != 0) {
362 fprintf(stderr, "Invalid key or broken header\n");
363 return EXIT_FAILURE;
364 }
365
366 akmos_memzero(md, sizeof(md));
367
368 buf += sizeof(hd->md);
369 }
370
371 return EXIT_SUCCESS;
372 }
373
akmos_cli_cipher(int argc,char ** argv,akmos_mode_id enc)374 int akmos_cli_cipher(int argc, char **argv, akmos_mode_id enc)
375 {
376 akmos_cipher_t ctx;
377 cipher_opt_t opt;
378 cipher_header_t hd;
379
380 uint8_t *keybuf, *keypass;
381 uint8_t *buf, *tbuf, *rbuf, *wbuf;
382 size_t keylen, len, rlen, wlen, tmplen;
383 mode_t mask;
384 FILE *fd_in, *fd_out;
385 int err;
386
387 ctx = NULL;
388 keybuf = buf = NULL;
389 fd_in = fd_out = NULL;
390
391 memset(&opt, 0, sizeof(struct cipher_opt_s));
392 err = parse_arg(&opt, argc, argv);
393 if(err)
394 return err;
395
396 if(opt.ver)
397 return akmos_cli_version();
398
399 /* Setup master keys */
400 keylen = opt.keylen * 2;
401 if(opt.flag)
402 keylen *= 3;
403
404 err = amalloc(&keybuf, keylen);
405 if(err)
406 return err;
407 memset(keybuf, 0, keylen);
408
409 keylen /= 2;
410 keypass = keybuf + keylen;
411
412 if(opt.set.passw || opt.set.passf) {
413 tbuf = keypass;
414 err = akmos_kdf_pbkdf2(tbuf, keylen, NULL, 0, (const uint8_t *)opt.pass, strlen(opt.pass),
415 CLI_PBKDF2_ALGO, CLI_PBKDF2_ITER);
416 if(err) {
417 akmos_perror(err);
418 goto out;
419 }
420 }
421
422 if(opt.set.key) {
423 /* keypass is used as salt */
424 err = pw_read_key(opt.key, keybuf, keylen, keypass, keylen);
425 if(err)
426 goto out;
427 } else {
428 /* keypass is used as master key */
429 memcpy(keybuf, keypass, keylen);
430 }
431
432 /* Open source and destination */
433 if(opt.input)
434 fd_in = fopen(opt.input, "r");
435 else
436 fd_in = stdin;
437
438 if(!fd_in) {
439 err = EXIT_FAILURE;
440 fprintf(stderr, "%s: %s\n", opt.input, strerror(errno));
441 goto out;
442 }
443
444 /* check for overwrite */
445 if(!opt.set.over && opt.output) {
446 if(!access(opt.output, F_OK)) {
447 if(!prompt_over(opt.output)) {
448 err = EXIT_SUCCESS;
449 fprintf(stderr, "%s: not overwrited - exiting\n", opt.output);
450 goto out;
451 }
452 }
453 }
454
455 mask = umask(0);
456 umask(mask);
457
458 if(opt.output)
459 fd_out = fopen(opt.output, "w");
460 else
461 fd_out = stdout;
462
463 if(!fd_out) {
464 err = EXIT_FAILURE;
465 fprintf(stderr, "%s: %s\n", opt.output, strerror(errno));
466 goto out;
467 }
468
469 /* allocate work buf */
470 err = amalloc(&buf, BUFLEN + opt.blklen);
471 if(err)
472 goto out;
473 memset(buf, 0, BUFLEN + opt.blklen);
474
475 /* Create and cook header */
476 len = sizeof(struct cipher_header_s);
477 switch(enc) {
478 case AKMOS_MODE_ENCRYPT:
479 err = pw_rand_buf(&hd, len);
480 if(err)
481 goto out;
482
483 err = header_encode(&hd, buf);
484 if(err)
485 goto out;
486
487 err = akmos_cipher(opt.algo, opt.mode|enc, keybuf, opt.keylen, NULL, buf, len, buf);
488 if(err) {
489 akmos_perror(err);
490 goto out;
491 }
492
493 if(fwrite(buf, 1, len, fd_out) != len) {
494 err = EXIT_FAILURE;
495 fprintf(stderr, "%s: %s\n", opt.output, strerror(errno));
496 goto out;
497 }
498 break;
499
500 case AKMOS_MODE_DECRYPT:
501 if(fread(buf, 1, len, fd_in) != len) {
502 err = EXIT_FAILURE;
503 fprintf(stderr, "%s: %s\n", opt.input, strerror(errno));
504 goto out;
505 }
506
507 err = akmos_cipher(opt.algo, opt.mode|enc, keybuf, opt.keylen, NULL, buf, len, buf);
508 if(err) {
509 akmos_perror(err);
510 goto out;
511 }
512
513 err = header_decode(buf, &hd);
514 if(err)
515 goto out;
516
517 break;
518
519 default:
520 break;
521 }
522
523 /* Create and init cipher contexts */
524 err = akmos_cipher_init(&ctx, opt.algo, opt.mode|enc);
525 if(err) {
526 akmos_perror(err);
527 goto out;
528 }
529
530 /* Setup cipher key and IV */
531 err = akmos_cipher_setkey(ctx, hd.key, opt.keylen);
532 if(err) {
533 akmos_perror(err);
534 goto out;
535 }
536
537 if(opt.mode != AKMOS_MODE_ECB)
538 akmos_cipher_setiv(ctx, hd.iv);
539
540 if(opt.mode == AKMOS_MODE_CTR)
541 akmos_cipher_setcnt(ctx, NULL);
542
543 /* ciphering */
544 rbuf = buf;
545 wbuf = buf + BUFSIZ;
546
547 rlen = fread(rbuf, 1, BUFSIZ, fd_in);
548 while(1) {
549 wlen = fread(wbuf, 1, BUFSIZ, fd_in);
550 if(ferror(fd_in)) {
551 err = EXIT_FAILURE;
552 fprintf(stderr, "%s: %s\n", opt.input, strerror(errno));
553 goto out;
554 }
555
556 akmos_cipher_crypt(ctx, rbuf, rlen, rbuf);
557
558 if(!wlen)
559 break;
560
561 if(fwrite(rbuf, 1, rlen, fd_out) != rlen) {
562 err = EXIT_FAILURE;
563 fprintf(stderr, "%s: %s\n", opt.output, strerror(errno));
564 goto out;
565 }
566
567 tbuf = rbuf; rbuf = wbuf; wbuf = tbuf;
568 tmplen = rlen; rlen = wlen; wlen = tmplen;
569 }
570
571 /* process padding */
572 switch(opt.mode) {
573 case AKMOS_MODE_ECB:
574 case AKMOS_MODE_CBC:
575 case AKMOS_MODE_CFB:
576 err = padbuf_hook(ctx, rbuf, &rlen, opt.blklen, enc);
577 if(err)
578 goto out;
579
580 break;
581
582 default:
583 break;
584 }
585
586 if(fwrite(rbuf, 1, rlen, fd_out) != rlen) {
587 err = EXIT_FAILURE;
588 fprintf(stderr, "%s: %s\n", opt.output, strerror(errno));
589 goto out;
590 }
591
592 out:
593 if(fd_in)
594 fclose(fd_in);
595
596 if(fd_out)
597 fclose(fd_out);
598
599 if(keybuf) {
600 akmos_memzero(keybuf, keylen);
601 free(keybuf);
602 }
603
604 if(buf) {
605 akmos_memzero(buf, BUFLEN + opt.blklen);
606 free(buf);
607 }
608
609 akmos_memzero(&hd, sizeof(struct cipher_header_s));
610
611 if(ctx)
612 akmos_cipher_free(ctx);
613
614 return err;
615 }
616