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