xref: /dragonfly/usr.bin/bdes/bdes.c (revision 799ba435edf825f35aa8f08bc8353a878dca2116)
1 /*-
2  * Copyright (c) 1991, 1993
3  *        The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Matt Bishop of Dartmouth College.
7  *
8  * The United States Government has rights in this work pursuant
9  * to contract no. NAG 2-680 between the National Aeronautics and
10  * Space Administration and Dartmouth College.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *        This product includes software developed by the University of
23  *        California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  * @(#) Copyright (c) 1991, 1993 The Regents of the University of California.  All rights reserved.
41  * @(#)bdes.c       8.1 (Berkeley) 6/6/93
42  * $FreeBSD: src/secure/usr.bin/bdes/bdes.c,v 1.11 2009/11/03 18:40:42 jhb Exp $
43  */
44 
45 /*
46  * BDES -- DES encryption package for Berkeley Software Distribution 4.4
47  * options:
48  *        -a        key is in ASCII
49  *        -b        use ECB (electronic code book) mode
50  *        -d        invert (decrypt) input
51  *        -f b      use b-bit CFB (cipher feedback) mode
52  *        -F b      use b-bit CFB (cipher feedback) alternative mode
53  *        -k key    use key as the cryptographic key
54  *        -m b      generate a MAC of length b
55  *        -o b      use b-bit OFB (output feedback) mode
56  *        -p        don't reset the parity bit
57  *        -v v      use v as the initialization vector (ignored for ECB)
58  * note: the last character of the last block is the integer indicating
59  * how many characters of that block are to be output
60  *
61  * Author: Matt Bishop
62  *           Department of Mathematics and Computer Science
63  *           Dartmouth College
64  *           Hanover, NH  03755
65  * Email:  Matt.Bishop@dartmouth.edu
66  *           ...!decvax!dartvax!Matt.Bishop
67  *
68  * See Technical Report PCS-TR91-158, Department of Mathematics and Computer
69  * Science, Dartmouth College, for a detailed description of the implemen-
70  * tation and differences between it and Sun's.  The DES is described in
71  * FIPS PUB 46, and the modes in FIPS PUB 81 (see either the manual page
72  * or the technical report for a complete reference).
73  */
74 
75 #include <sys/types.h>
76 
77 #include <ctype.h>
78 #include <err.h>
79 #include <errno.h>
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include <string.h>
83 #include <unistd.h>
84 
85 #include <openssl/des.h>
86 
87 /*
88  * BSD and System V systems offer special library calls that do
89  * block moves and fills, so if possible we take advantage of them
90  */
91 #define   MEMCPY(dest,src,len)          bcopy((src),(dest),(len))
92 #define   MEMZERO(dest,len)   bzero((dest),(len))
93 
94 #define   DES_XFORM(buf)                                                                  \
95                     DES_ecb_encrypt(buf, buf, &schedule,                        \
96                         mode == MODE_ENCRYPT ? DES_ENCRYPT : DES_DECRYPT);
97 
98 /*
99  * this does an error-checking write
100  */
101 #define   READ(buf, n)        fread(buf, sizeof(char), n, stdin)
102 #define WRITE(buf,n)                                                            \
103                     if (fwrite(buf, sizeof(char), n, stdout) != n)    \
104                               warnx("fwrite error at %d", n);
105 
106 /*
107  * global variables and related macros
108  */
109 #define KEY_DEFAULT           0         /* interpret radix of key from key */
110 #define KEY_ASCII             1         /* key is in ASCII characters */
111 int keybase = KEY_DEFAULT;              /* how to interpret the key */
112 
113 enum {                                            /* encrypt, decrypt, authenticate */
114           MODE_ENCRYPT, MODE_DECRYPT, MODE_AUTHENTICATE
115 } mode = MODE_ENCRYPT;
116 
117 enum {                                            /* ecb, cbc, cfb, cfba, ofb? */
118           ALG_ECB, ALG_CBC, ALG_CFB, ALG_OFB, ALG_CFBA
119 } alg = ALG_CBC;
120 
121 DES_cblock ivec;                                  /* initialization vector */
122 
123 char bits[] = {                                   /* used to extract bits from a char */
124           '\200', '\100', '\040', '\020', '\010', '\004', '\002', '\001'
125 };
126 
127 int inverse;                                      /* 0 to encrypt, 1 to decrypt */
128 int macbits = -1;                       /* number of bits in authentication */
129 int fbbits = -1;                        /* number of feedback bits */
130 int pflag;                                        /* 1 to preserve parity bits */
131 
132 DES_key_schedule schedule;              /* expanded DES key */
133 
134 static void ecbenc(void);
135 static void ecbdec(void);
136 static void cbcenc(void);
137 static void cbcdec(void);
138 static void cfbenc(void);
139 static void cfbdec(void);
140 static void cfbaenc(void);
141 static void cfbadec(void);
142 static void ofbenc(void);
143 static void ofbdec(void);
144 
145 static void cbcauth(void);
146 static void cfbauth(void);
147 
148 static void cvtkey(DES_cblock, char *);
149 static int setbits(char *, int);
150 static void makekey(DES_cblock *);
151 static int tobinhex(char, int);
152 
153 static void usage(void);
154 
155 int
main(int argc,char * argv[])156 main(int argc, char *argv[])
157 {
158           extern char *optarg;                    /* argument to option if any */
159           int i;                                  /* counter in a for loop */
160           char *p;                      /* used to obtain the key */
161           DES_cblock msgbuf;            /* I/O buffer */
162           int kflag;                              /* command-line encryption key */
163 
164           setproctitle("-");            /* Hide command-line arguments */
165 
166           /* initialize the initialization vector */
167           MEMZERO(ivec, 8);
168 
169           /* process the argument list */
170           kflag = 0;
171           while ((i = getopt(argc, argv, "abdF:f:k:m:o:pv:")) != -1)
172                     switch(i) {
173                     case 'a':           /* key is ASCII */
174                               keybase = KEY_ASCII;
175                               break;
176                     case 'b':           /* use ECB mode */
177                               alg = ALG_ECB;
178                               break;
179                     case 'd':           /* decrypt */
180                               mode = MODE_DECRYPT;
181                               break;
182                     case 'F':           /* use alternative CFB mode */
183                               alg = ALG_CFBA;
184                               if ((fbbits = setbits(optarg, 7)) > 56 || fbbits == 0)
185                                         errx(1, "-F: number must be 1-56 inclusive");
186                               else if (fbbits == -1)
187                                         errx(1, "-F: number must be a multiple of 7");
188                               break;
189                     case 'f':           /* use CFB mode */
190                               alg = ALG_CFB;
191                               if ((fbbits = setbits(optarg, 8)) > 64 || fbbits == 0)
192                                         errx(1, "-f: number must be 1-64 inclusive");
193                               else if (fbbits == -1)
194                                         errx(1, "-f: number must be a multiple of 8");
195                               break;
196                     case 'k':           /* encryption key */
197                               kflag = 1;
198                               cvtkey(msgbuf, optarg);
199                               break;
200                     case 'm':           /* number of bits for MACing */
201                               mode = MODE_AUTHENTICATE;
202                               if ((macbits = setbits(optarg, 1)) > 64)
203                                         errx(1, "-m: number must be 0-64 inclusive");
204                               break;
205                     case 'o':           /* use OFB mode */
206                               alg = ALG_OFB;
207                               if ((fbbits = setbits(optarg, 8)) > 64 || fbbits == 0)
208                                         errx(1, "-o: number must be 1-64 inclusive");
209                               else if (fbbits == -1)
210                                         errx(1, "-o: number must be a multiple of 8");
211                               break;
212                     case 'p':           /* preserve parity bits */
213                               pflag = 1;
214                               break;
215                     case 'v':           /* set initialization vector */
216                               cvtkey(ivec, optarg);
217                               break;
218                     default:            /* error */
219                               usage();
220                     }
221 
222           if (!kflag) {
223                     /*
224                      * if the key's not ASCII, assume it is
225                      */
226                     keybase = KEY_ASCII;
227                     /*
228                      * get the key
229                      */
230                     p = getpass("Enter key: ");
231                     /*
232                      * copy it, nul-padded, into the key area
233                      */
234                     cvtkey(msgbuf, p);
235           }
236 
237           makekey(&msgbuf);
238           inverse = (alg == ALG_CBC || alg == ALG_ECB) && mode == MODE_DECRYPT;
239 
240           switch(alg) {
241           case ALG_CBC:
242                     switch(mode) {
243                     case MODE_AUTHENTICATE:       /* authenticate using CBC mode */
244                               cbcauth();
245                               break;
246                     case MODE_DECRYPT:  /* decrypt using CBC mode */
247                               cbcdec();
248                               break;
249                     case MODE_ENCRYPT:  /* encrypt using CBC mode */
250                               cbcenc();
251                               break;
252                     }
253                     break;
254           case ALG_CFB:
255                     switch(mode) {
256                     case MODE_AUTHENTICATE:       /* authenticate using CFB mode */
257                               cfbauth();
258                               break;
259                     case MODE_DECRYPT:  /* decrypt using CFB mode */
260                               cfbdec();
261                               break;
262                     case MODE_ENCRYPT:  /* encrypt using CFB mode */
263                               cfbenc();
264                               break;
265                     }
266                     break;
267           case ALG_CFBA:
268                     switch(mode) {
269                     case MODE_AUTHENTICATE:       /* authenticate using CFBA mode */
270                               errx(1, "can't authenticate with CFBA mode");
271                               break;
272                     case MODE_DECRYPT:  /* decrypt using CFBA mode */
273                               cfbadec();
274                               break;
275                     case MODE_ENCRYPT:  /* encrypt using CFBA mode */
276                               cfbaenc();
277                               break;
278                     }
279                     break;
280           case ALG_ECB:
281                     switch(mode) {
282                     case MODE_AUTHENTICATE:       /* authenticate using ECB mode */
283                               errx(1, "can't authenticate with ECB mode");
284                               break;
285                     case MODE_DECRYPT:  /* decrypt using ECB mode */
286                               ecbdec();
287                               break;
288                     case MODE_ENCRYPT:  /* encrypt using ECB mode */
289                               ecbenc();
290                               break;
291                     }
292                     break;
293           case ALG_OFB:
294                     switch(mode) {
295                     case MODE_AUTHENTICATE:       /* authenticate using OFB mode */
296                               errx(1, "can't authenticate with OFB mode");
297                               break;
298                     case MODE_DECRYPT:  /* decrypt using OFB mode */
299                               ofbdec();
300                               break;
301                     case MODE_ENCRYPT:  /* encrypt using OFB mode */
302                               ofbenc();
303                               break;
304                     }
305                     break;
306           }
307           return (0);
308 }
309 
310 /*
311  * map a hex character to an integer
312  */
313 static int
tobinhex(char c,int radix)314 tobinhex(char c, int radix)
315 {
316           switch(c) {
317           case '0':           return(0x0);
318           case '1':           return(0x1);
319           case '2':           return(radix > 2 ? 0x2 : -1);
320           case '3':           return(radix > 3 ? 0x3 : -1);
321           case '4':           return(radix > 4 ? 0x4 : -1);
322           case '5':           return(radix > 5 ? 0x5 : -1);
323           case '6':           return(radix > 6 ? 0x6 : -1);
324           case '7':           return(radix > 7 ? 0x7 : -1);
325           case '8':           return(radix > 8 ? 0x8 : -1);
326           case '9':           return(radix > 9 ? 0x9 : -1);
327           case 'A': case 'a': return(radix > 10 ? 0xa : -1);
328           case 'B': case 'b': return(radix > 11 ? 0xb : -1);
329           case 'C': case 'c': return(radix > 12 ? 0xc : -1);
330           case 'D': case 'd': return(radix > 13 ? 0xd : -1);
331           case 'E': case 'e': return(radix > 14 ? 0xe : -1);
332           case 'F': case 'f': return(radix > 15 ? 0xf : -1);
333           }
334           /*
335            * invalid character
336            */
337           return(-1);
338 }
339 
340 /*
341  * convert the key to a bit pattern
342  */
343 static void
cvtkey(DES_cblock obuf,char * ibuf)344 cvtkey(DES_cblock obuf, char *ibuf)
345 {
346           int i, j;                     /* counter in a for loop */
347           int nbuf[64];                           /* used for hex/key translation */
348 
349           /*
350            * just switch on the key base
351            */
352           switch(keybase) {
353           case KEY_ASCII:                         /* ascii to integer */
354                     (void)strncpy(obuf, ibuf, 8);
355                     return;
356           case KEY_DEFAULT:             /* tell from context */
357                     /*
358                      * leading '0x' or '0X' == hex key
359                      */
360                     if (ibuf[0] == '0' && (ibuf[1] == 'x' || ibuf[1] == 'X')) {
361                               ibuf = &ibuf[2];
362                               /*
363                                * now translate it, bombing on any illegal hex digit
364                                */
365                               for (i = 0; i < 16 && ibuf[i]; i++)
366                                         if ((nbuf[i] = tobinhex(ibuf[i], 16)) == -1)
367                                                   warnx("bad hex digit in key");
368                               while (i < 16)
369                                         nbuf[i++] = 0;
370                               for (i = 0; i < 8; i++)
371                                         obuf[i] =
372                                             ((nbuf[2*i]&0xf)<<4) | (nbuf[2*i+1]&0xf);
373                               /* preserve parity bits */
374                               pflag = 1;
375                               return;
376                     }
377                     /*
378                      * leading '0b' or '0B' == binary key
379                      */
380                     if (ibuf[0] == '0' && (ibuf[1] == 'b' || ibuf[1] == 'B')) {
381                               ibuf = &ibuf[2];
382                               /*
383                                * now translate it, bombing on any illegal binary digit
384                                */
385                               for (i = 0; i < 16 && ibuf[i]; i++)
386                                         if ((nbuf[i] = tobinhex(ibuf[i], 2)) == -1)
387                                                   warnx("bad binary digit in key");
388                               while (i < 64)
389                                         nbuf[i++] = 0;
390                               for (i = 0; i < 8; i++)
391                                         for (j = 0; j < 8; j++)
392                                                   obuf[i] = (obuf[i]<<1)|nbuf[8*i+j];
393                               /* preserve parity bits */
394                               pflag = 1;
395                               return;
396                     }
397                     /*
398                      * no special leader -- ASCII
399                      */
400                     (void)strncpy(obuf, ibuf, 8);
401           }
402 }
403 
404 /*
405  * convert an ASCII string into a decimal number:
406  * 1. must be between 0 and 64 inclusive
407  * 2. must be a valid decimal number
408  * 3. must be a multiple of mult
409  */
410 static int
setbits(char * s,int mult)411 setbits(char *s, int mult)
412 {
413           char *p;                      /* pointer in a for loop */
414           int n = 0;                              /* the integer collected */
415 
416           /*
417            * skip white space
418            */
419           while (isspace(*s))
420                     s++;
421           /*
422            * get the integer
423            */
424           for (p = s; *p; p++) {
425                     if (isdigit(*p))
426                               n = n * 10 + *p - '0';
427                     else {
428                               warnx("bad decimal digit in MAC length");
429                     }
430           }
431           /*
432            * be sure it's a multiple of mult
433            */
434           return((n % mult != 0) ? -1 : n);
435 }
436 
437 /*****************
438  * DES FUNCTIONS *
439  *****************/
440 /*
441  * This sets the DES key and (if you're using the deszip version)
442  * the direction of the transformation.  This uses the Sun
443  * to map the 64-bit key onto the 56 bits that the key schedule
444  * generation routines use: the old way, which just uses the user-
445  * supplied 64 bits as is, and the new way, which resets the parity
446  * bit to be the same as the low-order bit in each character.  The
447  * new way generates a greater variety of key schedules, since many
448  * systems set the parity (high) bit of each character to 0, and the
449  * DES ignores the low order bit of each character.
450  */
451 static void
makekey(DES_cblock * buf)452 makekey(DES_cblock *buf)
453 {
454           int i, j;                               /* counter in a for loop */
455           int par;                                /* parity counter */
456 
457           /*
458            * if the parity is not preserved, flip it
459            */
460           if (!pflag) {
461                     for (i = 0; i < 8; i++) {
462                               par = 0;
463                               for (j = 1; j < 8; j++)
464                                         if ((bits[j] & (*buf)[i]) != 0)
465                                                   par++;
466                               if ((par & 0x01) == 0x01)
467                                         (*buf)[i] &= 0x7f;
468                               else
469                                         (*buf)[i] = ((*buf)[i] & 0x7f) | 0x80;
470                     }
471           }
472 
473           DES_set_odd_parity(buf);
474           DES_set_key(buf, &schedule);
475 }
476 
477 /*
478  * This encrypts using the Electronic Code Book mode of DES
479  */
480 static void
ecbenc(void)481 ecbenc(void)
482 {
483           int n;                                  /* number of bytes actually read */
484           int bn;                                 /* block number */
485           DES_cblock msgbuf;            /* I/O buffer */
486 
487           for (bn = 0; (n = READ(msgbuf,  8)) == 8; bn++) {
488                     /*
489                      * do the transformation
490                      */
491                     DES_XFORM(&msgbuf);
492                     WRITE(&msgbuf, 8);
493           }
494           /*
495            * at EOF or last block -- in either case, the last byte contains
496            * the character representation of the number of bytes in it
497            */
498           bn++;
499           MEMZERO(&msgbuf[n], 8 - n);
500           msgbuf[7] = n;
501           DES_XFORM(&msgbuf);
502           WRITE(&msgbuf, 8);
503 
504 }
505 
506 /*
507  * This decrypts using the Electronic Code Book mode of DES
508  */
509 static void
ecbdec(void)510 ecbdec(void)
511 {
512           int n;                        /* number of bytes actually read */
513           int c;                        /* used to test for EOF */
514           int bn;                       /* block number */
515           DES_cblock msgbuf;            /* I/O buffer */
516 
517           for (bn = 1; (n = READ(msgbuf, 8)) == 8; bn++) {
518                     /*
519                      * do the transformation
520                      */
521                     DES_XFORM(&msgbuf);
522                     /*
523                      * if the last one, handle it specially
524                      */
525                     if ((c = getchar()) == EOF) {
526                               n = msgbuf[7];
527                               if (n < 0 || n > 7)
528                                         warnx("decryption failed (block corrupt) at %d",
529                                             bn);
530                     }
531                     else
532                               (void)ungetc(c, stdin);
533                     WRITE(msgbuf, n);
534           }
535           if (n > 0)
536                     warnx("decryption failed (incomplete block) at %d", bn);
537 }
538 
539 /*
540  * This encrypts using the Cipher Block Chaining mode of DES
541  */
542 static void
cbcenc(void)543 cbcenc(void)
544 {
545           int n;                        /* number of bytes actually read */
546           int bn;                       /* block number */
547           DES_cblock msgbuf;  /* I/O buffer */
548 
549           /*
550            * do the transformation
551            */
552           for (bn = 1; (n = READ(msgbuf, 8)) == 8; bn++) {
553                     for (n = 0; n < 8; n++)
554                               msgbuf[n] ^= ivec[n];
555                     DES_XFORM(&msgbuf);
556                     MEMCPY(ivec, msgbuf, 8);
557                     WRITE(msgbuf, 8);
558           }
559           /*
560            * at EOF or last block -- in either case, the last byte contains
561            * the character representation of the number of bytes in it
562            */
563           bn++;
564           MEMZERO(&msgbuf[n], 8 - n);
565           msgbuf[7] = n;
566           for (n = 0; n < 8; n++)
567                     msgbuf[n] ^= ivec[n];
568           DES_XFORM(&msgbuf);
569           WRITE(msgbuf, 8);
570 
571 }
572 
573 /*
574  * This decrypts using the Cipher Block Chaining mode of DES
575  */
576 static void
cbcdec(void)577 cbcdec(void)
578 {
579           int n;                        /* number of bytes actually read */
580           DES_cblock msgbuf;  /* I/O buffer */
581           DES_cblock ibuf;    /* temp buffer for initialization vector */
582           int c;                        /* used to test for EOF */
583           int bn;                       /* block number */
584 
585           for (bn = 0; (n = READ(msgbuf, 8)) == 8; bn++) {
586                     /*
587                      * do the transformation
588                      */
589                     MEMCPY(ibuf, msgbuf, 8);
590                     DES_XFORM(&msgbuf);
591                     for (c = 0; c < 8; c++)
592                               msgbuf[c] ^= ivec[c];
593                     MEMCPY(ivec, ibuf, 8);
594                     /*
595                      * if the last one, handle it specially
596                      */
597                     if ((c = getchar()) == EOF) {
598                               n = msgbuf[7];
599                               if (n < 0 || n > 7)
600                                         warnx("decryption failed (block corrupt) at %d",
601                                             bn);
602                     }
603                     else
604                               (void)ungetc(c, stdin);
605                     WRITE(msgbuf, n);
606           }
607           if (n > 0)
608                     warnx("decryption failed (incomplete block) at %d", bn);
609 }
610 
611 /*
612  * This authenticates using the Cipher Block Chaining mode of DES
613  */
614 static void
cbcauth(void)615 cbcauth(void)
616 {
617           int n, j;           /* number of bytes actually read */
618           DES_cblock msgbuf;            /* I/O buffer */
619           DES_cblock encbuf;            /* encryption buffer */
620 
621           /*
622            * do the transformation
623            * note we DISCARD the encrypted block;
624            * we only care about the last one
625            */
626           while ((n = READ(msgbuf, 8)) == 8) {
627                     for (n = 0; n < 8; n++)
628                               encbuf[n] = msgbuf[n] ^ ivec[n];
629                     DES_XFORM(&encbuf);
630                     MEMCPY(ivec, encbuf, 8);
631           }
632           /*
633            * now compute the last one, right padding with '\0' if need be
634            */
635           if (n > 0) {
636                     MEMZERO(&msgbuf[n], 8 - n);
637                     for (n = 0; n < 8; n++)
638                               encbuf[n] = msgbuf[n] ^ ivec[n];
639                     DES_XFORM(&encbuf);
640           }
641           /*
642            * drop the bits
643            * we write chars until fewer than 7 bits,
644            * and then pad the last one with 0 bits
645            */
646           for (n = 0; macbits > 7; n++, macbits -= 8)
647                     (void)putchar(encbuf[n]);
648           if (macbits > 0) {
649                     msgbuf[0] = 0x00;
650                     for (j = 0; j < macbits; j++)
651                               msgbuf[0] |= encbuf[n] & bits[j];
652                     (void)putchar(msgbuf[0]);
653           }
654 }
655 
656 /*
657  * This encrypts using the Cipher FeedBack mode of DES
658  */
659 static void
cfbenc(void)660 cfbenc(void)
661 {
662           int n;                        /* number of bytes actually read */
663           int nbytes;                   /* number of bytes to read */
664           int bn;                       /* block number */
665           char ibuf[8];                 /* input buffer */
666           DES_cblock msgbuf;            /* encryption buffer */
667 
668           /*
669            * do things in bytes, not bits
670            */
671           nbytes = fbbits / 8;
672           /*
673            * do the transformation
674            */
675           for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) {
676                     MEMCPY(msgbuf, ivec, 8);
677                     DES_XFORM(&msgbuf);
678                     for (n = 0; n < 8 - nbytes; n++)
679                               ivec[n] = ivec[n+nbytes];
680                     for (n = 0; n < nbytes; n++)
681                               ivec[8 - nbytes + n] = ibuf[n] ^ msgbuf[n];
682                     WRITE(&ivec[8 - nbytes], nbytes);
683           }
684           /*
685            * at EOF or last block -- in either case, the last byte contains
686            * the character representation of the number of bytes in it
687            */
688           bn++;
689           MEMZERO(&ibuf[n], nbytes - n);
690           ibuf[nbytes - 1] = n;
691           MEMCPY(msgbuf, ivec, 8);
692           DES_XFORM(&msgbuf);
693           for (n = 0; n < nbytes; n++)
694                     ibuf[n] ^= msgbuf[n];
695           WRITE(ibuf, nbytes);
696 }
697 
698 /*
699  * This decrypts using the Cipher Block Chaining mode of DES
700  */
701 static void
cfbdec(void)702 cfbdec(void)
703 {
704           int n;                        /* number of bytes actually read */
705           int c;                        /* used to test for EOF */
706           int nbytes;                   /* number of bytes to read */
707           int bn;                       /* block number */
708           char ibuf[8];                 /* input buffer */
709           char obuf[8];                 /* output buffer */
710           DES_cblock msgbuf;            /* encryption buffer */
711 
712           /*
713            * do things in bytes, not bits
714            */
715           nbytes = fbbits / 8;
716           /*
717            * do the transformation
718            */
719           for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) {
720                     MEMCPY(msgbuf, ivec, 8);
721                     DES_XFORM(&msgbuf);
722                     for (c = 0; c < 8 - nbytes; c++)
723                               ivec[c] = ivec[c + nbytes];
724                     for (c = 0; c < nbytes; c++) {
725                               ivec[8 - nbytes + c] = ibuf[c];
726                               obuf[c] = ibuf[c] ^ msgbuf[c];
727                     }
728                     /*
729                      * if the last one, handle it specially
730                      */
731                     if ((c = getchar()) == EOF) {
732                               n = obuf[nbytes-1];
733                               if (n < 0 || n > nbytes-1)
734                                         warnx("decryption failed (block corrupt) at %d",
735                                             bn);
736                     }
737                     else
738                               (void)ungetc(c, stdin);
739                     WRITE(obuf, n);
740           }
741           if (n > 0)
742                     warnx("decryption failed (incomplete block) at %d", bn);
743 }
744 
745 /*
746  * This encrypts using the alternative Cipher FeedBack mode of DES
747  */
748 static void
cfbaenc(void)749 cfbaenc(void)
750 {
751           int n;                        /* number of bytes actually read */
752           int nbytes;                   /* number of bytes to read */
753           int bn;                       /* block number */
754           char ibuf[8];                 /* input buffer */
755           char obuf[8];                 /* output buffer */
756           DES_cblock msgbuf;            /* encryption buffer */
757 
758           /*
759            * do things in bytes, not bits
760            */
761           nbytes = fbbits / 7;
762           /*
763            * do the transformation
764            */
765           for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) {
766                     MEMCPY(msgbuf, ivec, 8);
767                     DES_XFORM(&msgbuf);
768                     for (n = 0; n < 8 - nbytes; n++)
769                               ivec[n] = ivec[n + nbytes];
770                     for (n = 0; n < nbytes; n++)
771                               ivec[8 - nbytes + n] = (ibuf[n] ^ msgbuf[n]) | 0x80;
772                     for (n = 0; n < nbytes; n++)
773                               obuf[n] = ivec[8 - nbytes + n] & 0x7f;
774                     WRITE(obuf, nbytes);
775           }
776           /*
777            * at EOF or last block -- in either case, the last byte contains
778            * the character representation of the number of bytes in it
779            */
780           bn++;
781           MEMZERO(&ibuf[n], nbytes - n);
782           ibuf[nbytes - 1] = ('0' + n)|0200;
783           MEMCPY(msgbuf, ivec, 8);
784           DES_XFORM(&msgbuf);
785           for (n = 0; n < nbytes; n++)
786                     ibuf[n] ^= msgbuf[n];
787           WRITE(ibuf, nbytes);
788 }
789 
790 /*
791  * This decrypts using the alternative Cipher Block Chaining mode of DES
792  */
793 static void
cfbadec(void)794 cfbadec(void)
795 {
796           int n;                        /* number of bytes actually read */
797           int c;                        /* used to test for EOF */
798           int nbytes;                   /* number of bytes to read */
799           int bn;                       /* block number */
800           char ibuf[8];                 /* input buffer */
801           char obuf[8];                 /* output buffer */
802           DES_cblock msgbuf;            /* encryption buffer */
803 
804           /*
805            * do things in bytes, not bits
806            */
807           nbytes = fbbits / 7;
808           /*
809            * do the transformation
810            */
811           for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) {
812                     MEMCPY(msgbuf, ivec, 8);
813                     DES_XFORM(&msgbuf);
814                     for (c = 0; c < 8 - nbytes; c++)
815                               ivec[c] = ivec[c + nbytes];
816                     for (c = 0; c < nbytes; c++) {
817                               ivec[8 - nbytes + c] = ibuf[c] | 0x80;
818                               obuf[c] = (ibuf[c] ^ msgbuf[c]) & 0x7f;
819                     }
820                     /*
821                      * if the last one, handle it specially
822                      */
823                     if ((c = getchar()) == EOF) {
824                               if ((n = (obuf[nbytes-1] - '0')) < 0
825                                                             || n > nbytes-1)
826                                         warnx("decryption failed (block corrupt) at %d",
827                                             bn);
828                     }
829                     else
830                               (void)ungetc(c, stdin);
831                     WRITE(obuf, n);
832           }
833           if (n > 0)
834                     warnx("decryption failed (incomplete block) at %d", bn);
835 }
836 
837 
838 /*
839  * This encrypts using the Output FeedBack mode of DES
840  */
841 static void
ofbenc(void)842 ofbenc(void)
843 {
844           int n;                        /* number of bytes actually read */
845           int c;                        /* used to test for EOF */
846           int nbytes;                   /* number of bytes to read */
847           int bn;                       /* block number */
848           char ibuf[8];                 /* input buffer */
849           char obuf[8];                 /* output buffer */
850           DES_cblock msgbuf;            /* encryption buffer */
851 
852           /*
853            * do things in bytes, not bits
854            */
855           nbytes = fbbits / 8;
856           /*
857            * do the transformation
858            */
859           for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) {
860                     MEMCPY(msgbuf, ivec, 8);
861                     DES_XFORM(&msgbuf);
862                     for (n = 0; n < 8 - nbytes; n++)
863                               ivec[n] = ivec[n + nbytes];
864                     for (n = 0; n < nbytes; n++) {
865                               ivec[8 - nbytes + n] = msgbuf[n];
866                               obuf[n] = ibuf[n] ^ msgbuf[n];
867                     }
868                     WRITE(obuf, nbytes);
869           }
870           /*
871            * at EOF or last block -- in either case, the last byte contains
872            * the character representation of the number of bytes in it
873            */
874           bn++;
875           MEMZERO(&ibuf[n], nbytes - n);
876           ibuf[nbytes - 1] = n;
877           MEMCPY(msgbuf, ivec, 8);
878           DES_XFORM(&msgbuf);
879           for (c = 0; c < nbytes; c++)
880                     ibuf[c] ^= msgbuf[c];
881           WRITE(ibuf, nbytes);
882 }
883 
884 /*
885  * This decrypts using the Output Block Chaining mode of DES
886  */
887 static void
ofbdec(void)888 ofbdec(void)
889 {
890           int n;                        /* number of bytes actually read */
891           int c;                        /* used to test for EOF */
892           int nbytes;                   /* number of bytes to read */
893           int bn;                       /* block number */
894           char ibuf[8];                 /* input buffer */
895           char obuf[8];                 /* output buffer */
896           DES_cblock msgbuf;            /* encryption buffer */
897 
898           /*
899            * do things in bytes, not bits
900            */
901           nbytes = fbbits / 8;
902           /*
903            * do the transformation
904            */
905           for (bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++) {
906                     MEMCPY(msgbuf, ivec, 8);
907                     DES_XFORM(&msgbuf);
908                     for (c = 0; c < 8 - nbytes; c++)
909                               ivec[c] = ivec[c + nbytes];
910                     for (c = 0; c < nbytes; c++) {
911                               ivec[8 - nbytes + c] = msgbuf[c];
912                               obuf[c] = ibuf[c] ^ msgbuf[c];
913                     }
914                     /*
915                      * if the last one, handle it specially
916                      */
917                     if ((c = getchar()) == EOF) {
918                               n = obuf[nbytes-1];
919                               if (n < 0 || n > nbytes-1)
920                                         warnx("decryption failed (block corrupt) at %d",
921                                             bn);
922                     }
923                     else
924                               (void)ungetc(c, stdin);
925                     /*
926                      * dump it
927                      */
928                     WRITE(obuf, n);
929           }
930           if (n > 0)
931                     warnx("decryption failed (incomplete block) at %d", bn);
932 }
933 
934 /*
935  * This authenticates using the Cipher FeedBack mode of DES
936  */
937 static void
cfbauth(void)938 cfbauth(void)
939 {
940           int n, j;           /* number of bytes actually read */
941           int nbytes;                   /* number of bytes to read */
942           char ibuf[8];                 /* input buffer */
943           DES_cblock msgbuf;  /* encryption buffer */
944 
945           /*
946            * do things in bytes, not bits
947            */
948           nbytes = fbbits / 8;
949           /*
950            * do the transformation
951            */
952           while ((n = READ(ibuf, nbytes)) == nbytes) {
953                     MEMCPY(msgbuf, ivec, 8);
954                     DES_XFORM(&msgbuf);
955                     for (n = 0; n < 8 - nbytes; n++)
956                               ivec[n] = ivec[n + nbytes];
957                     for (n = 0; n < nbytes; n++)
958                               ivec[8 - nbytes + n] = ibuf[n] ^ msgbuf[n];
959           }
960           /*
961            * at EOF or last block -- in either case, the last byte contains
962            * the character representation of the number of bytes in it
963            */
964           MEMZERO(&ibuf[n], nbytes - n);
965           ibuf[nbytes - 1] = '0' + n;
966           MEMCPY(msgbuf, ivec, 8);
967           DES_XFORM(&msgbuf);
968           for (n = 0; n < nbytes; n++)
969                     ibuf[n] ^= msgbuf[n];
970           /*
971            * drop the bits
972            * we write chars until fewer than 7 bits,
973            * and then pad the last one with 0 bits
974            */
975           for (n = 0; macbits > 7; n++, macbits -= 8)
976                     (void)putchar(msgbuf[n]);
977           if (macbits > 0) {
978                     msgbuf[0] = 0x00;
979                     for (j = 0; j < macbits; j++)
980                               msgbuf[0] |= msgbuf[n] & bits[j];
981                     (void)putchar(msgbuf[0]);
982           }
983 }
984 
985 /*
986  * message about usage
987  */
988 static void
usage(void)989 usage(void)
990 {
991           (void)fprintf(stderr, "%s\n",
992 "usage: bdes [-abdp] [-F N] [-f N] [-k key] [-m N] [-o N] [-v vector]");
993           exit(1);
994 }
995