cbc.c revision 16
116Salm/* cbc.c: This file contains the encryption routines for the ed line editor */
216Salm/*-
316Salm * Copyright (c) 1991 The Regents of the University of California.
416Salm * All rights reserved.
516Salm *
616Salm * This code is derived from software contributed to Berkeley by
716Salm * Matt Bishop of Dartmouth College.
816Salm *
916Salm * The United States Government has rights in this work pursuant
1016Salm * to contract no. NAG 2-680 between the National Aeronautics and
1116Salm * Space Administration and Dartmouth College.
1216Salm *
1316Salm * Redistribution and use in source and binary forms, with or without
1416Salm * modification, are permitted provided that the following conditions
1516Salm * are met:
1616Salm * 1. Redistributions of source code must retain the above copyright
1716Salm *    notice, this list of conditions and the following disclaimer.
1816Salm * 2. Redistributions in binary form must reproduce the above copyright
1916Salm *    notice, this list of conditions and the following disclaimer in the
2016Salm *    documentation and/or other materials provided with the distribution.
2116Salm * 3. All advertising materials mentioning features or use of this software
2216Salm *    must display the following acknowledgement:
2316Salm *	This product includes software developed by the University of
2416Salm *	California, Berkeley and its contributors.
2516Salm * 4. Neither the name of the University nor the names of its contributors
2616Salm *    may be used to endorse or promote products derived from this software
2716Salm *    without specific prior written permission.
2816Salm *
2916Salm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3016Salm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3116Salm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3216Salm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3316Salm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3416Salm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3516Salm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3616Salm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3716Salm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3816Salm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3916Salm * SUCH DAMAGE.
4016Salm */
4116Salm
4216Salm#ifndef lint
4316Salmstatic char sccsid[] = "@(#)cbc.c	5.5 (Berkeley) 6/27/91";
4416Salm#endif /* not lint */
4516Salm
4616Salm/* Author: Matt Bishop
4716Salm *	   Department of Mathematics and Computer Science
4816Salm *	   Dartmouth College
4916Salm *	   Hanover, NH  03755
5016Salm * Email:  Matt.Bishop@dartmouth.edu
5116Salm *	   ...!decvax!dartvax!Matt.Bishop
5216Salm *
5316Salm * See Technical Report PCS-TR91-158, Department of Mathematics and Computer
5416Salm * Science, Dartmouth College, for a detailed description of the implemen-
5516Salm * tation and differences between it and Sun's.  The DES is described in
5616Salm * FIPS PUB 46, and the modes in FIPS PUB 81 (see either the manual page
5716Salm * or the technical report for a complete reference).
5816Salm */
5916Salm
6016Salm#include <errno.h>
6116Salm#include <pwd.h>
6216Salm#include <unistd.h>
6316Salm#include <stdio.h>
6416Salm#include <ctype.h>
6516Salm#include <stdlib.h>
6616Salm#include <string.h>
6716Salm#include <sys/types.h>
6816Salm
6916Salm#include "ed.h"
7016Salm
7116Salm/*
7216Salm * Define a divisor for rand() that yields a uniform distribution in the
7316Salm * range 0-255.
7416Salm */
7516Salm#define	RAND_DIV (((unsigned) RAND_MAX + 1) >> 8)
7616Salm
7716Salm/*
7816Salm * BSD and System V systems offer special library calls that do
7916Salm * block moves and fills, so if possible we take advantage of them
8016Salm */
8116Salm#define	MEMCPY(dest,src,len)	memcpy((dest),(src),(len))
8216Salm#define	MEMZERO(dest,len)	memset((dest), 0, (len))
8316Salm
8416Salm/* Hide the calls to the primitive encryption routines. */
8516Salm#define	DES_KEY(buf) \
8616Salm	if (des_setkey(buf)) \
8716Salm		err("des_setkey");
8816Salm#define	DES_XFORM(buf) \
8916Salm	if (des_cipher(buf, buf, 0L, (inverse ? -1 : 1))) \
9016Salm		err("des_cipher");
9116Salm
9216Salm/*
9316Salm * read/write - no error checking
9416Salm */
9516Salm#define	READ(buf, n, fp)	fread(buf, sizeof(char), n, fp)
9616Salm#define WRITE(buf, n, fp)	fwrite(buf, sizeof(char), n, fp)
9716Salm
9816Salm/*
9916Salm * some things to make references easier
10016Salm */
10116Salmtypedef char Desbuf[8];
10216Salm#define	CHAR(x,i)	(x[i])
10316Salm#define	UCHAR(x,i)	(x[i])
10416Salm#define	BUFFER(x)	(x)
10516Salm#define	UBUFFER(x)	(x)
10616Salm
10716Salm/*
10816Salm * global variables and related macros
10916Salm */
11016Salm
11116Salmenum { 					/* encrypt, decrypt, authenticate */
11216Salm	MODE_ENCRYPT, MODE_DECRYPT, MODE_AUTHENTICATE
11316Salm} mode = MODE_ENCRYPT;
11416Salm
11516SalmDesbuf ivec;				/* initialization vector */
11616SalmDesbuf pvec;				/* padding vector */
11716Salmchar bits[] = {				/* used to extract bits from a char */
11816Salm	'\200', '\100', '\040', '\020', '\010', '\004', '\002', '\001'
11916Salm};
12016Salmint pflag;				/* 1 to preserve parity bits */
12116Salm
12216Salmchar des_buf[8];		/* shared buffer for desgetc/desputc */
12316Salmint des_ct = 0;			/* count for desgetc/desputc */
12416Salmint des_n = 0;			/* index for desputc/desgetc */
12516Salm
12616Salm
12716Salm/* desinit: initialize DES */
12816Salmvoid
12916Salmdesinit()
13016Salm{
13116Salm#ifdef DES
13216Salm	int i;
13316Salm
13416Salm	des_ct = des_n = 0;
13516Salm
13616Salm	/* initialize the initialization vctor */
13716Salm	MEMZERO(ivec, 8);
13816Salm
13916Salm	/* intialize the padding vector */
14016Salm	srand((unsigned) time((time_t *) 0));
14116Salm	for (i = 0; i < 8; i++)
14216Salm		CHAR(pvec, i) = (char) (rand()/RAND_DIV);
14316Salm#endif
14416Salm}
14516Salm
14616Salm
14716Salm/* desgetc: return next char in an encrypted file */
14816Salmdesgetc(fp)
14916Salm	FILE *fp;
15016Salm{
15116Salm#ifdef DES
15216Salm	if (des_n >= des_ct) {
15316Salm		des_n = 0;
15416Salm		des_ct = cbcdec(des_buf, fp);
15516Salm	}
15616Salm	return (des_ct > 0) ? des_buf[des_n++] : EOF;
15716Salm#endif
15816Salm}
15916Salm
16016Salm
16116Salm/* desputc: write a char to an encrypted file; return char written */
16216Salmdesputc(c, fp)
16316Salm	int c;
16416Salm	FILE *fp;
16516Salm{
16616Salm#ifdef DES
16716Salm	if (des_n == sizeof des_buf) {
16816Salm		des_ct = cbcenc(des_buf, des_n, fp);
16916Salm		des_n = 0;
17016Salm	}
17116Salm	return (des_ct >= 0) ? (des_buf[des_n++] = c) : EOF;
17216Salm#endif
17316Salm}
17416Salm
17516Salm
17616Salm/* desflush: flush an encrypted file's output; return status */
17716Salmdesflush(fp)
17816Salm	FILE *fp;
17916Salm{
18016Salm#ifdef DES
18116Salm	if (des_n == sizeof des_buf) {
18216Salm		des_ct = cbcenc(des_buf, des_n, fp);
18316Salm		des_n = 0;
18416Salm	}
18516Salm	return (des_ct >= 0 && cbcenc(des_buf, des_n, fp) >= 0) ? 0 : EOF;
18616Salm#endif
18716Salm}
18816Salm
18916Salm#ifdef DES
19016Salm/*
19116Salm * get keyword from tty or stdin
19216Salm */
19316Salmgetkey()
19416Salm{
19516Salm	register char *p;		/* used to obtain the key */
19616Salm	Desbuf msgbuf;			/* I/O buffer */
19716Salm
19816Salm	/*
19916Salm	 * get the key
20016Salm	 */
20116Salm	if (*(p = getpass("Enter key: "))) {
20216Salm
20316Salm		/*
20416Salm		 * copy it, nul-padded, into the key area
20516Salm		 */
20616Salm		cvtkey(BUFFER(msgbuf), p);
20716Salm		MEMZERO(p, _PASSWORD_LEN);
20816Salm		makekey(msgbuf);
20916Salm		MEMZERO(msgbuf, sizeof msgbuf);
21016Salm		return 1;
21116Salm	}
21216Salm	return 0;
21316Salm}
21416Salm
21516Salm
21616Salmextern char errmsg[];
21716Salm
21816Salm/*
21916Salm * print a warning message and, possibly, terminate
22016Salm */
22116Salmvoid
22216Salmerr(s)
22316Salm	char *s;		/* the message */
22416Salm{
22516Salm	(void)sprintf(errmsg, "%s", s ? s : strerror(errno));
22616Salm}
22716Salm
22816Salm/*
22916Salm * map a hex character to an integer
23016Salm */
23116Salmtobinhex(c, radix)
23216Salm	int c;			/* char to be converted */
23316Salm	int radix;		/* base (2 to 16) */
23416Salm{
23516Salm	switch(c) {
23616Salm	case '0':		return(0x0);
23716Salm	case '1':		return(0x1);
23816Salm	case '2':		return(radix > 2 ? 0x2 : -1);
23916Salm	case '3':		return(radix > 3 ? 0x3 : -1);
24016Salm	case '4':		return(radix > 4 ? 0x4 : -1);
24116Salm	case '5':		return(radix > 5 ? 0x5 : -1);
24216Salm	case '6':		return(radix > 6 ? 0x6 : -1);
24316Salm	case '7':		return(radix > 7 ? 0x7 : -1);
24416Salm	case '8':		return(radix > 8 ? 0x8 : -1);
24516Salm	case '9':		return(radix > 9 ? 0x9 : -1);
24616Salm	case 'A': case 'a':	return(radix > 10 ? 0xa : -1);
24716Salm	case 'B': case 'b':	return(radix > 11 ? 0xb : -1);
24816Salm	case 'C': case 'c':	return(radix > 12 ? 0xc : -1);
24916Salm	case 'D': case 'd':	return(radix > 13 ? 0xd : -1);
25016Salm	case 'E': case 'e':	return(radix > 14 ? 0xe : -1);
25116Salm	case 'F': case 'f':	return(radix > 15 ? 0xf : -1);
25216Salm	}
25316Salm	/*
25416Salm	 * invalid character
25516Salm	 */
25616Salm	return(-1);
25716Salm}
25816Salm
25916Salm/*
26016Salm * convert the key to a bit pattern
26116Salm */
26216Salmvoid
26316Salmcvtkey(obuf, ibuf)
26416Salm	char *obuf;			/* bit pattern */
26516Salm	char *ibuf;			/* the key itself */
26616Salm{
26716Salm	register int i, j;		/* counter in a for loop */
26816Salm	int nbuf[64];			/* used for hex/key translation */
26916Salm
27016Salm	/*
27116Salm	 * leading '0x' or '0X' == hex key
27216Salm	 */
27316Salm	if (ibuf[0] == '0' && (ibuf[1] == 'x' || ibuf[1] == 'X')) {
27416Salm		ibuf = &ibuf[2];
27516Salm		/*
27616Salm		 * now translate it, bombing on any illegal hex digit
27716Salm		 */
27816Salm		for (i = 0; ibuf[i] && i < 16; i++)
27916Salm			if ((nbuf[i] = tobinhex((int) ibuf[i], 16)) == -1)
28016Salm				err("bad hex digit in key");
28116Salm		while (i < 16)
28216Salm			nbuf[i++] = 0;
28316Salm		for (i = 0; i < 8; i++)
28416Salm			obuf[i] =
28516Salm			    ((nbuf[2*i]&0xf)<<4) | (nbuf[2*i+1]&0xf);
28616Salm		/* preserve parity bits */
28716Salm		pflag = 1;
28816Salm		return;
28916Salm	}
29016Salm	/*
29116Salm	 * leading '0b' or '0B' == binary key
29216Salm	 */
29316Salm	if (ibuf[0] == '0' && (ibuf[1] == 'b' || ibuf[1] == 'B')) {
29416Salm		ibuf = &ibuf[2];
29516Salm		/*
29616Salm		 * now translate it, bombing on any illegal binary digit
29716Salm		 */
29816Salm		for (i = 0; ibuf[i] && i < 16; i++)
29916Salm			if ((nbuf[i] = tobinhex((int) ibuf[i], 2)) == -1)
30016Salm				err("bad binary digit in key");
30116Salm		while (i < 64)
30216Salm			nbuf[i++] = 0;
30316Salm		for (i = 0; i < 8; i++)
30416Salm			for (j = 0; j < 8; j++)
30516Salm				obuf[i] = (obuf[i]<<1)|nbuf[8*i+j];
30616Salm		/* preserve parity bits */
30716Salm		pflag = 1;
30816Salm		return;
30916Salm	}
31016Salm	/*
31116Salm	 * no special leader -- ASCII
31216Salm	 */
31316Salm	(void)strncpy(obuf, ibuf, 8);
31416Salm}
31516Salm
31616Salm/*****************
31716Salm * DES FUNCTIONS *
31816Salm *****************/
31916Salm/*
32016Salm * This sets the DES key and (if you're using the deszip version)
32116Salm * the direction of the transformation.  This uses the Sun
32216Salm * to map the 64-bit key onto the 56 bits that the key schedule
32316Salm * generation routines use: the old way, which just uses the user-
32416Salm * supplied 64 bits as is, and the new way, which resets the parity
32516Salm * bit to be the same as the low-order bit in each character.  The
32616Salm * new way generates a greater variety of key schedules, since many
32716Salm * systems set the parity (high) bit of each character to 0, and the
32816Salm * DES ignores the low order bit of each character.
32916Salm */
33016Salmvoid
33116Salmmakekey(buf)
33216Salm	Desbuf buf;				/* key block */
33316Salm{
33416Salm	register int i, j;			/* counter in a for loop */
33516Salm	register int par;			/* parity counter */
33616Salm
33716Salm	/*
33816Salm	 * if the parity is not preserved, flip it
33916Salm	 */
34016Salm	if (!pflag) {
34116Salm		for (i = 0; i < 8; i++) {
34216Salm			par = 0;
34316Salm			for (j = 1; j < 8; j++)
34416Salm				if ((bits[j]&UCHAR(buf, i)) != 0)
34516Salm					par++;
34616Salm			if ((par&01) == 01)
34716Salm				UCHAR(buf, i) = UCHAR(buf, i)&0177;
34816Salm			else
34916Salm				UCHAR(buf, i) = (UCHAR(buf, i)&0177)|0200;
35016Salm		}
35116Salm	}
35216Salm
35316Salm	DES_KEY(UBUFFER(buf));
35416Salm}
35516Salm
35616Salm
35716Salm/*
35816Salm * This encrypts using the Cipher Block Chaining mode of DES
35916Salm */
36016Salmcbcenc(msgbuf, n, fp)
36116Salm	char *msgbuf;
36216Salm	int n;
36316Salm	FILE *fp;
36416Salm{
36516Salm	int inverse = 0;	/* 0 to encrypt, 1 to decrypt */
36616Salm
36716Salm	/*
36816Salm	 * do the transformation
36916Salm	 */
37016Salm	if (n == 8) {
37116Salm		for (n = 0; n < 8; n++)
37216Salm			CHAR(msgbuf, n) ^= CHAR(ivec, n);
37316Salm		DES_XFORM(UBUFFER(msgbuf));
37416Salm		MEMCPY(BUFFER(ivec), BUFFER(msgbuf), 8);
37516Salm		return WRITE(BUFFER(msgbuf), 8, fp);
37616Salm	}
37716Salm	/*
37816Salm	 * at EOF or last block -- in either case, the last byte contains
37916Salm	 * the character representation of the number of bytes in it
38016Salm	 */
38116Salm/*
38216Salm	MEMZERO(msgbuf +  n, 8 - n);
38316Salm*/
38416Salm	/*
38516Salm	 *  Pad the last block randomly
38616Salm	 */
38716Salm	(void)MEMCPY(BUFFER(msgbuf + n), BUFFER(pvec), 8 - n);
38816Salm	CHAR(msgbuf, 7) = n;
38916Salm	for (n = 0; n < 8; n++)
39016Salm		CHAR(msgbuf, n) ^= CHAR(ivec, n);
39116Salm	DES_XFORM(UBUFFER(msgbuf));
39216Salm	return WRITE(BUFFER(msgbuf), 8, fp);
39316Salm}
39416Salm
39516Salm/*
39616Salm * This decrypts using the Cipher Block Chaining mode of DES
39716Salm */
39816Salmcbcdec(msgbuf, fp)
39916Salm	char *msgbuf;		/* I/O buffer */
40016Salm	FILE *fp;			/* input file descriptor */
40116Salm{
40216Salm	Desbuf ibuf;	/* temp buffer for initialization vector */
40316Salm	register int n;		/* number of bytes actually read */
40416Salm	register int c;		/* used to test for EOF */
40516Salm	int inverse = 1;	/* 0 to encrypt, 1 to decrypt */
40616Salm
40716Salm	if ((n = READ(BUFFER(msgbuf), 8, fp)) == 8) {
40816Salm		/*
40916Salm		 * do the transformation
41016Salm		 */
41116Salm		MEMCPY(BUFFER(ibuf), BUFFER(msgbuf), 8);
41216Salm		DES_XFORM(UBUFFER(msgbuf));
41316Salm		for (c = 0; c < 8; c++)
41416Salm			UCHAR(msgbuf, c) ^= UCHAR(ivec, c);
41516Salm		MEMCPY(BUFFER(ivec), BUFFER(ibuf), 8);
41616Salm		/*
41716Salm		 * if the last one, handle it specially
41816Salm		 */
41916Salm		if ((c = fgetc(fp)) == EOF) {
42016Salm			n = CHAR(msgbuf, 7);
42116Salm			if (n < 0 || n > 7) {
42216Salm				err("decryption failed (block corrupted)");
42316Salm				return EOF;
42416Salm			}
42516Salm		} else
42616Salm			(void)ungetc(c, fp);
42716Salm		return n;
42816Salm	}
42916Salm	if (n > 0)
43016Salm		err("decryption failed (incomplete block)");
43116Salm	else if (n < 0)
43216Salm		err("cannot read file");
43316Salm	return EOF;
43416Salm}
43516Salm#endif	/* DES */
436