cbc.c revision 7165
1252190Srpaulo/* cbc.c: This file contains the encryption routines for the ed line editor */
2252190Srpaulo/*-
3252190Srpaulo * Copyright (c) 1993 The Regents of the University of California.
4252190Srpaulo * All rights reserved.
5252190Srpaulo *
6252190Srpaulo * Copyright (c) 1993 Andrew Moore, Talke Studio.
7252190Srpaulo * All rights reserved.
8252190Srpaulo *
9252190Srpaulo * Redistribution and use in source and binary forms, with or without
10252190Srpaulo * modification, are permitted provided that the following conditions
11252190Srpaulo * are met:
12252190Srpaulo * 1. Redistributions of source code must retain the above copyright
13252190Srpaulo *    notice, this list of conditions and the following disclaimer.
14252190Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
15252190Srpaulo *    notice, this list of conditions and the following disclaimer in the
16252190Srpaulo *    documentation and/or other materials provided with the distribution.
17252190Srpaulo * 3. All advertising materials mentioning features or use of this software
18252190Srpaulo *    must display the following acknowledgement:
19252190Srpaulo *	This product includes software developed by the University of
20252190Srpaulo *	California, Berkeley and its contributors.
21252190Srpaulo * 4. Neither the name of the University nor the names of its contributors
22252190Srpaulo *    may be used to endorse or promote products derived from this software
23252190Srpaulo *    without specific prior written permission.
24252190Srpaulo *
25252190Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26252190Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27252190Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28252190Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29252190Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30252190Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31252190Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32252190Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33252190Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34252190Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35252190Srpaulo * SUCH DAMAGE.
36252190Srpaulo *
37252190Srpaulo *	from: @(#)bdes.c	5.5 (Berkeley) 6/27/91
38252190Srpaulo *	$Id: cbc.c,v 1.4 1994/09/24 02:55:24 davidg Exp $
39252190Srpaulo */
40252190Srpaulo
41252190Srpaulo#ifndef lint
42252190Srpaulostatic char *rcsid = "@(#)cbc.c,v 1.2 1994/02/01 00:34:36 alm Exp";
43252190Srpaulo#endif /* not lint */
44252190Srpaulo
45252190Srpaulo#include <sys/types.h>
46252190Srpaulo#include <ctype.h>
47252190Srpaulo#include <errno.h>
48252190Srpaulo#include <pwd.h>
49252190Srpaulo
50252190Srpaulo#include "ed.h"
51252190Srpaulo
52252190Srpaulo
53252190Srpaulo/*
54252190Srpaulo * Define a divisor for rand() that yields a uniform distribution in the
55252190Srpaulo * range 0-255.
56252190Srpaulo */
57252190Srpaulo#define	RAND_DIV (((unsigned) RAND_MAX + 1) >> 8)
58252190Srpaulo
59252190Srpaulo/*
60252190Srpaulo * BSD and System V systems offer special library calls that do
61252190Srpaulo * block move_liness and fills, so if possible we take advantage of them
62252190Srpaulo */
63252190Srpaulo#define	MEMCPY(dest,src,len)	memcpy((dest),(src),(len))
64252190Srpaulo#define	MEMZERO(dest,len)	memset((dest), 0, (len))
65252190Srpaulo
66252190Srpaulo/* Hide the calls to the primitive encryption routines. */
67252190Srpaulo#define	DES_KEY(buf) \
68252190Srpaulo	if (des_setkey(buf)) \
69252190Srpaulo		des_error("des_setkey");
70252190Srpaulo#define	DES_XFORM(buf) \
71252190Srpaulo	if (des_cipher(buf, buf, 0L, (inverse ? -1 : 1))) \
72252190Srpaulo		des_error("des_cipher");
73252190Srpaulo
74252190Srpaulo/*
75252190Srpaulo * read/write - no error checking
76252190Srpaulo */
77252190Srpaulo#define	READ(buf, n, fp)	fread(buf, sizeof(char), n, fp)
78252190Srpaulo#define WRITE(buf, n, fp)	fwrite(buf, sizeof(char), n, fp)
79252190Srpaulo
80252190Srpaulo/*
81252190Srpaulo * some things to make references easier
82252190Srpaulo */
83252190Srpaulotypedef char Desbuf[8];
84252190Srpaulo#define	CHAR(x,i)	(x[i])
85252190Srpaulo#define	UCHAR(x,i)	(x[i])
86252190Srpaulo#define	BUFFER(x)	(x)
87252190Srpaulo#define	UBUFFER(x)	(x)
88252190Srpaulo
89252190Srpaulo/*
90252190Srpaulo * global variables and related macros
91252190Srpaulo */
92252190Srpaulo
93252190Srpauloenum { 					/* encrypt, decrypt, authenticate */
94252190Srpaulo	MODE_ENCRYPT, MODE_DECRYPT, MODE_AUTHENTICATE
95252190Srpaulo} mode = MODE_ENCRYPT;
96252190Srpaulo
97252190SrpauloDesbuf ivec;				/* initialization vector */
98252190SrpauloDesbuf pvec;				/* padding vector */
99252190Srpaulochar bits[] = {				/* used to extract bits from a char */
100252190Srpaulo	'\200', '\100', '\040', '\020', '\010', '\004', '\002', '\001'
101252190Srpaulo};
102252190Srpauloint pflag;				/* 1 to preserve parity bits */
103252190Srpaulo
104252190Srpaulounsigned char des_buf[8];	/* shared buffer for get_des_char/put_des_char */
105252190Srpauloint des_ct = 0;			/* count for get_des_char/put_des_char */
106252190Srpauloint des_n = 0;			/* index for put_des_char/get_des_char */
107252190Srpaulo
108252190Srpaulo
109252190Srpaulo/* init_des_cipher: initialize DES */
110252190Srpaulovoid
111252190Srpauloinit_des_cipher()
112252190Srpaulo{
113252190Srpaulo#ifdef DES
114252190Srpaulo	int i;
115252190Srpaulo
116252190Srpaulo	des_ct = des_n = 0;
117252190Srpaulo
118252190Srpaulo	/* initialize the initialization vector */
119252190Srpaulo	MEMZERO(ivec, 8);
120252190Srpaulo
121252190Srpaulo	/* intialize the padding vector */
122252190Srpaulo	srand((unsigned) time((time_t *) 0));
123252190Srpaulo	for (i = 0; i < 8; i++)
124252190Srpaulo		CHAR(pvec, i) = (char) (rand()/RAND_DIV);
125252190Srpaulo#endif
126252190Srpaulo}
127252190Srpaulo
128252190Srpaulo
129252190Srpaulo/* get_des_char: return next char in an encrypted file */
130252190Srpauloint
131252190Srpauloget_des_char(fp)
132252190Srpaulo	FILE *fp;
133252190Srpaulo{
134252190Srpaulo#ifdef DES
135252190Srpaulo	if (des_n >= des_ct) {
136252190Srpaulo		des_n = 0;
137252190Srpaulo		des_ct = cbc_decode(des_buf, fp);
138252190Srpaulo	}
139252190Srpaulo	return (des_ct > 0) ? des_buf[des_n++] : EOF;
140252190Srpaulo#else
141252190Srpaulo	return (getc(fp));
142252190Srpaulo#endif
143252190Srpaulo}
144252190Srpaulo
145252190Srpaulo
146252190Srpaulo/* put_des_char: write a char to an encrypted file; return char written */
147252190Srpauloint
148252190Srpauloput_des_char(c, fp)
149252190Srpaulo	int c;
150252190Srpaulo	FILE *fp;
151252190Srpaulo{
152252190Srpaulo#ifdef DES
153252190Srpaulo	if (des_n == sizeof des_buf) {
154252190Srpaulo		des_ct = cbc_encode(des_buf, des_n, fp);
155252190Srpaulo		des_n = 0;
156252190Srpaulo	}
157252190Srpaulo	return (des_ct >= 0) ? (des_buf[des_n++] = c) : EOF;
158252190Srpaulo#else
159252190Srpaulo	return (fputc(c, fp));
160252190Srpaulo#endif
161252190Srpaulo}
162252190Srpaulo
163252190Srpaulo
164252190Srpaulo/* flush_des_file: flush an encrypted file's output; return status */
165252190Srpauloint
166252190Srpauloflush_des_file(fp)
167252190Srpaulo	FILE *fp;
168252190Srpaulo{
169252190Srpaulo#ifdef DES
170252190Srpaulo	if (des_n == sizeof des_buf) {
171252190Srpaulo		des_ct = cbc_encode(des_buf, des_n, fp);
172252190Srpaulo		des_n = 0;
173252190Srpaulo	}
174252190Srpaulo	return (des_ct >= 0 && cbc_encode(des_buf, des_n, fp) >= 0) ? 0 : EOF;
175252190Srpaulo#else
176252190Srpaulo	return (fflush(fp));
177252190Srpaulo#endif
178252190Srpaulo}
179252190Srpaulo
180252190Srpaulo#ifdef DES
181252190Srpaulo/*
182252190Srpaulo * get keyword from tty or stdin
183252190Srpaulo */
184252190Srpauloint
185252190Srpauloget_keyword()
186252190Srpaulo{
187252190Srpaulo	register char *p;		/* used to obtain the key */
188252190Srpaulo	Desbuf msgbuf;			/* I/O buffer */
189252190Srpaulo
190252190Srpaulo	/*
191252190Srpaulo	 * get the key
192252190Srpaulo	 */
193252190Srpaulo	if (*(p = getpass("Enter key: "))) {
194252190Srpaulo
195252190Srpaulo		/*
196252190Srpaulo		 * copy it, nul-padded, into the key area
197252190Srpaulo		 */
198252190Srpaulo		expand_des_key(BUFFER(msgbuf), p);
199252190Srpaulo		MEMZERO(p, _PASSWORD_LEN);
200252190Srpaulo		set_des_key(msgbuf);
201252190Srpaulo		MEMZERO(msgbuf, sizeof msgbuf);
202252190Srpaulo		return 1;
203252190Srpaulo	}
204252190Srpaulo	return 0;
205252190Srpaulo}
206252190Srpaulo
207252190Srpaulo
208252190Srpaulo/*
209252190Srpaulo * print a warning message and, possibly, terminate
210252190Srpaulo */
211252190Srpaulovoid
212252190Srpaulodes_error(s)
213252190Srpaulo	char *s;		/* the message */
214252190Srpaulo{
215252190Srpaulo	(void)sprintf(errmsg, "%s", s ? s : strerror(errno));
216252190Srpaulo}
217252190Srpaulo
218252190Srpaulo/*
219252190Srpaulo * map a hex character to an integer
220252190Srpaulo */
221252190Srpauloint
222252190Srpaulohex_to_binary(c, radix)
223252190Srpaulo	int c;			/* char to be converted */
224252190Srpaulo	int radix;		/* base (2 to 16) */
225252190Srpaulo{
226252190Srpaulo	switch(c) {
227252190Srpaulo	case '0':		return(0x0);
228252190Srpaulo	case '1':		return(0x1);
229252190Srpaulo	case '2':		return(radix > 2 ? 0x2 : -1);
230252190Srpaulo	case '3':		return(radix > 3 ? 0x3 : -1);
231252190Srpaulo	case '4':		return(radix > 4 ? 0x4 : -1);
232252190Srpaulo	case '5':		return(radix > 5 ? 0x5 : -1);
233252190Srpaulo	case '6':		return(radix > 6 ? 0x6 : -1);
234252190Srpaulo	case '7':		return(radix > 7 ? 0x7 : -1);
235252190Srpaulo	case '8':		return(radix > 8 ? 0x8 : -1);
236252190Srpaulo	case '9':		return(radix > 9 ? 0x9 : -1);
237252190Srpaulo	case 'A': case 'a':	return(radix > 10 ? 0xa : -1);
238252190Srpaulo	case 'B': case 'b':	return(radix > 11 ? 0xb : -1);
239252190Srpaulo	case 'C': case 'c':	return(radix > 12 ? 0xc : -1);
240252190Srpaulo	case 'D': case 'd':	return(radix > 13 ? 0xd : -1);
241252190Srpaulo	case 'E': case 'e':	return(radix > 14 ? 0xe : -1);
242252190Srpaulo	case 'F': case 'f':	return(radix > 15 ? 0xf : -1);
243252190Srpaulo	}
244252190Srpaulo	/*
245252190Srpaulo	 * invalid character
246252190Srpaulo	 */
247252190Srpaulo	return(-1);
248252190Srpaulo}
249252190Srpaulo
250252190Srpaulo/*
251252190Srpaulo * convert the key to a bit pattern
252252190Srpaulo */
253252190Srpaulovoid
254252190Srpauloexpand_des_key(obuf, ibuf)
255252190Srpaulo	char *obuf;			/* bit pattern */
256252190Srpaulo	char *ibuf;			/* the key itself */
257252190Srpaulo{
258252190Srpaulo	register int i, j;		/* counter in a for loop */
259252190Srpaulo	int nbuf[64];			/* used for hex/key translation */
260252190Srpaulo
261252190Srpaulo	/*
262252190Srpaulo	 * leading '0x' or '0X' == hex key
263252190Srpaulo	 */
264252190Srpaulo	if (ibuf[0] == '0' && (ibuf[1] == 'x' || ibuf[1] == 'X')) {
265252190Srpaulo		ibuf = &ibuf[2];
266252190Srpaulo		/*
267252190Srpaulo		 * now translate it, bombing on any illegal hex digit
268252190Srpaulo		 */
269252190Srpaulo		for (i = 0; ibuf[i] && i < 16; i++)
270252190Srpaulo			if ((nbuf[i] = hex_to_binary((int) ibuf[i], 16)) == -1)
271252190Srpaulo				des_error("bad hex digit in key");
272252190Srpaulo		while (i < 16)
273252190Srpaulo			nbuf[i++] = 0;
274252190Srpaulo		for (i = 0; i < 8; i++)
275252190Srpaulo			obuf[i] =
276252190Srpaulo			    ((nbuf[2*i]&0xf)<<4) | (nbuf[2*i+1]&0xf);
277252190Srpaulo		/* preserve parity bits */
278252190Srpaulo		pflag = 1;
279252190Srpaulo		return;
280252190Srpaulo	}
281252190Srpaulo	/*
282252190Srpaulo	 * leading '0b' or '0B' == binary key
283252190Srpaulo	 */
284252190Srpaulo	if (ibuf[0] == '0' && (ibuf[1] == 'b' || ibuf[1] == 'B')) {
285252190Srpaulo		ibuf = &ibuf[2];
286252190Srpaulo		/*
287252190Srpaulo		 * now translate it, bombing on any illegal binary digit
288252190Srpaulo		 */
289252190Srpaulo		for (i = 0; ibuf[i] && i < 16; i++)
290252190Srpaulo			if ((nbuf[i] = hex_to_binary((int) ibuf[i], 2)) == -1)
291252190Srpaulo				des_error("bad binary digit in key");
292252190Srpaulo		while (i < 64)
293252190Srpaulo			nbuf[i++] = 0;
294252190Srpaulo		for (i = 0; i < 8; i++)
295252190Srpaulo			for (j = 0; j < 8; j++)
296252190Srpaulo				obuf[i] = (obuf[i]<<1)|nbuf[8*i+j];
297252190Srpaulo		/* preserve parity bits */
298252190Srpaulo		pflag = 1;
299252190Srpaulo		return;
300252190Srpaulo	}
301252190Srpaulo	/*
302252190Srpaulo	 * no special leader -- ASCII
303252190Srpaulo	 */
304252190Srpaulo	(void)strncpy(obuf, ibuf, 8);
305252190Srpaulo}
306252190Srpaulo
307252190Srpaulo/*****************
308252190Srpaulo * DES FUNCTIONS *
309252190Srpaulo *****************/
310252190Srpaulo/*
311252190Srpaulo * This sets the DES key and (if you're using the deszip version)
312252190Srpaulo * the direction of the transformation.  This uses the Sun
313252190Srpaulo * to map the 64-bit key onto the 56 bits that the key schedule
314252190Srpaulo * generation routines use: the old way, which just uses the user-
315252190Srpaulo * supplied 64 bits as is, and the new way, which resets the parity
316252190Srpaulo * bit to be the same as the low-order bit in each character.  The
317252190Srpaulo * new way generates a greater variety of key schedules, since many
318252190Srpaulo * systems set the parity (high) bit of each character to 0, and the
319252190Srpaulo * DES ignores the low order bit of each character.
320252190Srpaulo */
321252190Srpaulovoid
322252190Srpauloset_des_key(buf)
323252190Srpaulo	Desbuf buf;				/* key block */
324252190Srpaulo{
325252190Srpaulo	register int i, j;			/* counter in a for loop */
326252190Srpaulo	register int par;			/* parity counter */
327252190Srpaulo
328252190Srpaulo	/*
329252190Srpaulo	 * if the parity is not preserved, flip it
330252190Srpaulo	 */
331252190Srpaulo	if (!pflag) {
332252190Srpaulo		for (i = 0; i < 8; i++) {
333252190Srpaulo			par = 0;
334252190Srpaulo			for (j = 1; j < 8; j++)
335252190Srpaulo				if ((bits[j]&UCHAR(buf, i)) != 0)
336252190Srpaulo					par++;
337252190Srpaulo			if ((par&01) == 01)
338252190Srpaulo				UCHAR(buf, i) = UCHAR(buf, i)&0177;
339252190Srpaulo			else
340252190Srpaulo				UCHAR(buf, i) = (UCHAR(buf, i)&0177)|0200;
341252190Srpaulo		}
342252190Srpaulo	}
343252190Srpaulo
344252190Srpaulo	DES_KEY(UBUFFER(buf));
345252190Srpaulo}
346252190Srpaulo
347252190Srpaulo
348252190Srpaulo/*
349252190Srpaulo * This encrypts using the Cipher Block Chaining mode of DES
350252190Srpaulo */
351252190Srpauloint
352252190Srpaulocbc_encode(msgbuf, n, fp)
353252190Srpaulo	char *msgbuf;
354252190Srpaulo	int n;
355252190Srpaulo	FILE *fp;
356252190Srpaulo{
357252190Srpaulo	int inverse = 0;	/* 0 to encrypt, 1 to decrypt */
358252190Srpaulo
359252190Srpaulo	/*
360252190Srpaulo	 * do the transformation
361252190Srpaulo	 */
362252190Srpaulo	if (n == 8) {
363252190Srpaulo		for (n = 0; n < 8; n++)
364252190Srpaulo			CHAR(msgbuf, n) ^= CHAR(ivec, n);
365252190Srpaulo		DES_XFORM(UBUFFER(msgbuf));
366252190Srpaulo		MEMCPY(BUFFER(ivec), BUFFER(msgbuf), 8);
367252190Srpaulo		return WRITE(BUFFER(msgbuf), 8, fp);
368252190Srpaulo	}
369252190Srpaulo	/*
370252190Srpaulo	 * at EOF or last block -- in either case, the last byte contains
371252190Srpaulo	 * the character representation of the number of bytes in it
372252190Srpaulo	 */
373252190Srpaulo/*
374252190Srpaulo	MEMZERO(msgbuf +  n, 8 - n);
375252190Srpaulo*/
376252190Srpaulo	/*
377252190Srpaulo	 *  Pad the last block randomly
378252190Srpaulo	 */
379252190Srpaulo	(void)MEMCPY(BUFFER(msgbuf + n), BUFFER(pvec), 8 - n);
380252190Srpaulo	CHAR(msgbuf, 7) = n;
381252190Srpaulo	for (n = 0; n < 8; n++)
382252190Srpaulo		CHAR(msgbuf, n) ^= CHAR(ivec, n);
383252190Srpaulo	DES_XFORM(UBUFFER(msgbuf));
384252190Srpaulo	return WRITE(BUFFER(msgbuf), 8, fp);
385252190Srpaulo}
386252190Srpaulo
387252190Srpaulo/*
388252190Srpaulo * This decrypts using the Cipher Block Chaining mode of DES
389252190Srpaulo */
390252190Srpauloint
391252190Srpaulocbc_decode(msgbuf, fp)
392252190Srpaulo	char *msgbuf;		/* I/O buffer */
393252190Srpaulo	FILE *fp;			/* input file descriptor */
394252190Srpaulo{
395252190Srpaulo	Desbuf ibuf;	/* temp buffer for initialization vector */
396252190Srpaulo	register int n;		/* number of bytes actually read */
397252190Srpaulo	register int c;		/* used to test for EOF */
398252190Srpaulo	int inverse = 1;	/* 0 to encrypt, 1 to decrypt */
399252190Srpaulo
400252190Srpaulo	if ((n = READ(BUFFER(msgbuf), 8, fp)) == 8) {
401252190Srpaulo		/*
402252190Srpaulo		 * do the transformation
403252190Srpaulo		 */
404252190Srpaulo		MEMCPY(BUFFER(ibuf), BUFFER(msgbuf), 8);
405252190Srpaulo		DES_XFORM(UBUFFER(msgbuf));
406252190Srpaulo		for (c = 0; c < 8; c++)
407252190Srpaulo			UCHAR(msgbuf, c) ^= UCHAR(ivec, c);
408252190Srpaulo		MEMCPY(BUFFER(ivec), BUFFER(ibuf), 8);
409252190Srpaulo		/*
410252190Srpaulo		 * if the last one, handle it specially
411252190Srpaulo		 */
412252190Srpaulo		if ((c = fgetc(fp)) == EOF) {
413252190Srpaulo			n = CHAR(msgbuf, 7);
414252190Srpaulo			if (n < 0 || n > 7) {
415252190Srpaulo				des_error("decryption failed (block corrupted)");
416252190Srpaulo				return EOF;
417252190Srpaulo			}
418252190Srpaulo		} else
419252190Srpaulo			(void)ungetc(c, fp);
420252190Srpaulo		return n;
421252190Srpaulo	}
422252190Srpaulo	if (n > 0)
423252190Srpaulo		des_error("decryption failed (incomplete block)");
424252190Srpaulo	else if (n < 0)
425252190Srpaulo		des_error("cannot read file");
426252190Srpaulo	return EOF;
427252190Srpaulo}
428252190Srpaulo#endif	/* DES */
429252190Srpaulo