xref: /onnv-gate/usr/src/cmd/des/des.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * DES encrypt/decrypt command
31*0Sstevel@tonic-gate  * Features:
32*0Sstevel@tonic-gate  *	Hardware or software implementation
33*0Sstevel@tonic-gate  *	Cipher Block Chaining (default) or Electronic Code Book (-b) modes
34*0Sstevel@tonic-gate  *  A word about the key:
35*0Sstevel@tonic-gate  * 	The DES standard specifies that the low bit of each of the 8 bytes
36*0Sstevel@tonic-gate  *	of the key is used for odd parity.  We prompt the user for an 8
37*0Sstevel@tonic-gate  *	byte ASCII key and add parity to the high bit and use the result
38*0Sstevel@tonic-gate  *	as the key.  The nature of parity is that given any 7 bits you can
39*0Sstevel@tonic-gate  *	figure out what the missing bit should be, so it doesn't matter which
40*0Sstevel@tonic-gate  *	bit is used for parity; the information (in the theoretical sense) is
41*0Sstevel@tonic-gate  * 	the same.
42*0Sstevel@tonic-gate  */
43*0Sstevel@tonic-gate #include <stdio.h>
44*0Sstevel@tonic-gate #include <string.h>
45*0Sstevel@tonic-gate #include <rpc/des_crypt.h>
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate #define DES_CBC	0
48*0Sstevel@tonic-gate #define DES_ECB 1
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate int ifd=0, ofd=1;		/* input and output descriptors */
52*0Sstevel@tonic-gate char *cmdname;			/* our command name */
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate struct des_info {
56*0Sstevel@tonic-gate 	char *key;			/* encryption key */
57*0Sstevel@tonic-gate 	char *ivec;			/* initialization vector: CBC mode only */
58*0Sstevel@tonic-gate 	unsigned flags;		/* direction, device flags */
59*0Sstevel@tonic-gate 	unsigned mode;		/* des mode: ecb or cbc */
60*0Sstevel@tonic-gate } g_des;
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate void des_setup(char *key, unsigned int mode, unsigned int flags);
64*0Sstevel@tonic-gate void fencrypt(void);
65*0Sstevel@tonic-gate void fdecrypt(void);
66*0Sstevel@tonic-gate void usage(void);
67*0Sstevel@tonic-gate static void putparity(char *p);
68*0Sstevel@tonic-gate int
main(int argc,char ** argv)69*0Sstevel@tonic-gate main(int argc, char **argv)
70*0Sstevel@tonic-gate {
71*0Sstevel@tonic-gate 	char *key = NULL, keybuf[8], *getpass();
72*0Sstevel@tonic-gate 	unsigned mode = DES_CBC;
73*0Sstevel@tonic-gate 	unsigned flags = DES_HW;
74*0Sstevel@tonic-gate 	int dirset = 0; 	/* set if dir set */
75*0Sstevel@tonic-gate 	int fflg = 0;	/* suppress warning if H/W DES not available */
76*0Sstevel@tonic-gate 	unsigned err;
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	cmdname = *argv++;
79*0Sstevel@tonic-gate 	argc--;
80*0Sstevel@tonic-gate 	while (argc > 0 && argv[0][0] == '-') {
81*0Sstevel@tonic-gate 		switch (argv[0][1]) {
82*0Sstevel@tonic-gate 		case 'e':	/* encrypt */
83*0Sstevel@tonic-gate 			flags |= DES_ENCRYPT;  	dirset++;
84*0Sstevel@tonic-gate 			break;
85*0Sstevel@tonic-gate 		case 'd':	/* decrypt */
86*0Sstevel@tonic-gate 			flags |= DES_DECRYPT;	dirset++;
87*0Sstevel@tonic-gate 			break;
88*0Sstevel@tonic-gate 		case 'b':	/* use Book mode */
89*0Sstevel@tonic-gate 			mode = DES_ECB;
90*0Sstevel@tonic-gate 			break;
91*0Sstevel@tonic-gate 		case 'f':	/* force silent */
92*0Sstevel@tonic-gate 			fflg++;
93*0Sstevel@tonic-gate 			break;
94*0Sstevel@tonic-gate 		case 's':	/* use software DES */
95*0Sstevel@tonic-gate 			flags |= DES_SW;
96*0Sstevel@tonic-gate 			break;
97*0Sstevel@tonic-gate 		case 'k':	/* key */
98*0Sstevel@tonic-gate 			if (--argc == 0)
99*0Sstevel@tonic-gate 				usage();
100*0Sstevel@tonic-gate 			strncpy(keybuf, *++argv, 8);
101*0Sstevel@tonic-gate 			for (key = *argv; *key; )
102*0Sstevel@tonic-gate 				*key++ = '\0';
103*0Sstevel@tonic-gate 			key = keybuf;
104*0Sstevel@tonic-gate 			break;
105*0Sstevel@tonic-gate 		default:
106*0Sstevel@tonic-gate 			usage();
107*0Sstevel@tonic-gate 		}
108*0Sstevel@tonic-gate 		argv++;
109*0Sstevel@tonic-gate 		argc--;
110*0Sstevel@tonic-gate 	}
111*0Sstevel@tonic-gate 	if (!dirset)
112*0Sstevel@tonic-gate 		usage();
113*0Sstevel@tonic-gate 	if (argc > 0) {
114*0Sstevel@tonic-gate 		ifd = open(*argv, 0);
115*0Sstevel@tonic-gate 		if (ifd < 0) {
116*0Sstevel@tonic-gate 			perror(*argv);
117*0Sstevel@tonic-gate 			exit(1);
118*0Sstevel@tonic-gate 		}
119*0Sstevel@tonic-gate 		argv++;
120*0Sstevel@tonic-gate 		argc--;
121*0Sstevel@tonic-gate 	}
122*0Sstevel@tonic-gate 	if (argc > 0) {
123*0Sstevel@tonic-gate 		ofd = creat(*argv, 0666);
124*0Sstevel@tonic-gate 		if (ofd < 0) {
125*0Sstevel@tonic-gate 			perror(*argv);
126*0Sstevel@tonic-gate 			exit(1);
127*0Sstevel@tonic-gate 		}
128*0Sstevel@tonic-gate 		argv++;
129*0Sstevel@tonic-gate 		argc--;
130*0Sstevel@tonic-gate 	}
131*0Sstevel@tonic-gate 	if (argc)
132*0Sstevel@tonic-gate 		usage();
133*0Sstevel@tonic-gate 	if (key == NULL) {
134*0Sstevel@tonic-gate 		if ((key = getpass("Enter key: ")) == NULL) {
135*0Sstevel@tonic-gate 			fprintf(stderr, "%s: unable to get key\n", cmdname);
136*0Sstevel@tonic-gate 			exit(1);
137*0Sstevel@tonic-gate 		}
138*0Sstevel@tonic-gate 		strncpy(keybuf, key, 8);
139*0Sstevel@tonic-gate 	}
140*0Sstevel@tonic-gate 	if ((flags & DES_DEVMASK) == DES_HW && no_hwdevice()) {
141*0Sstevel@tonic-gate 		flags &= ~DES_DEVMASK;	/* clear device bit */
142*0Sstevel@tonic-gate 		flags |= DES_SW;		/* set device to software */
143*0Sstevel@tonic-gate 		if (!fflg) {
144*0Sstevel@tonic-gate 			fprintf(stderr, "%s: WARNING: using software DES algorithm\n",
145*0Sstevel@tonic-gate 				cmdname);
146*0Sstevel@tonic-gate 		}
147*0Sstevel@tonic-gate 	}
148*0Sstevel@tonic-gate 	if ((flags & DES_DEVMASK) == DES_SW && no_swdevice()) {
149*0Sstevel@tonic-gate 		fprintf(stderr, "%s: no software encryption available\n",
150*0Sstevel@tonic-gate 			cmdname);
151*0Sstevel@tonic-gate 		exit(1);
152*0Sstevel@tonic-gate 	}
153*0Sstevel@tonic-gate 	des_setup(key, mode, flags);
154*0Sstevel@tonic-gate 	switch (flags & DES_DIRMASK) {
155*0Sstevel@tonic-gate 	case DES_ENCRYPT:
156*0Sstevel@tonic-gate 		fencrypt();
157*0Sstevel@tonic-gate 		break;
158*0Sstevel@tonic-gate 	case DES_DECRYPT:
159*0Sstevel@tonic-gate 		fdecrypt();
160*0Sstevel@tonic-gate 		break;
161*0Sstevel@tonic-gate 	}
162*0Sstevel@tonic-gate 	return (0);
163*0Sstevel@tonic-gate }
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate int
no_hwdevice(void)168*0Sstevel@tonic-gate no_hwdevice(void)
169*0Sstevel@tonic-gate {
170*0Sstevel@tonic-gate 	char key[8];
171*0Sstevel@tonic-gate 	char buf[8];
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	return (ecb_crypt(key,buf,8,DES_ENCRYPT | DES_HW) != 0);
174*0Sstevel@tonic-gate }
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate int
no_swdevice(void)178*0Sstevel@tonic-gate no_swdevice(void)
179*0Sstevel@tonic-gate {
180*0Sstevel@tonic-gate 	char key[8];
181*0Sstevel@tonic-gate 	char buf[8];
182*0Sstevel@tonic-gate 	int res;
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	return (ecb_crypt(key,buf,8,DES_ENCRYPT | DES_SW) != 0);
185*0Sstevel@tonic-gate }
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate void
des_setup(char * key,unsigned int mode,unsigned int flags)191*0Sstevel@tonic-gate des_setup(char *key, unsigned int mode, unsigned int flags)
192*0Sstevel@tonic-gate {
193*0Sstevel@tonic-gate 	static char ivec[8];
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	g_des.flags = flags;
196*0Sstevel@tonic-gate 	g_des.mode = mode;
197*0Sstevel@tonic-gate 	putparity(key);
198*0Sstevel@tonic-gate 	g_des.key = key;
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	memset(ivec, 0, 8);
201*0Sstevel@tonic-gate 	g_des.ivec = ivec;
202*0Sstevel@tonic-gate }
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate void
crypt(char * buf,unsigned int len)206*0Sstevel@tonic-gate crypt(char *buf, unsigned int len)
207*0Sstevel@tonic-gate {
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	if (g_des.mode == DES_ECB) {
210*0Sstevel@tonic-gate 		ecb_crypt(g_des.key, buf, len, g_des.flags);
211*0Sstevel@tonic-gate 	} else {
212*0Sstevel@tonic-gate 		cbc_crypt(g_des.key, buf, len, g_des.flags, g_des.ivec);
213*0Sstevel@tonic-gate 	}
214*0Sstevel@tonic-gate }
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate char buf[DES_MAXDATA];
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate /*
220*0Sstevel@tonic-gate  * Encrypt a file:
221*0Sstevel@tonic-gate  * Takes an arbitrary number of bytes of input and
222*0Sstevel@tonic-gate  * produces an encrypted output file which is always the
223*0Sstevel@tonic-gate  * the next multiple of 8 bytes bigger (e.g., 64 -> 72, 71 -> 72)
224*0Sstevel@tonic-gate  * The last byte, when decrypted, gives the number of actual data bytes
225*0Sstevel@tonic-gate  * in the last 8 bytes.  Other bytes are filled with random values to
226*0Sstevel@tonic-gate  * make it hard to cryptanalize.
227*0Sstevel@tonic-gate  */
228*0Sstevel@tonic-gate void
fencrypt(void)229*0Sstevel@tonic-gate fencrypt(void)
230*0Sstevel@tonic-gate {
231*0Sstevel@tonic-gate 	int n, k, j;
232*0Sstevel@tonic-gate 	char *cp;
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	while ((n = read(ifd, buf, sizeof buf)) > 0) {
235*0Sstevel@tonic-gate 		j = n;
236*0Sstevel@tonic-gate 		while (n & 7) {
237*0Sstevel@tonic-gate 			k = 8 - (n & 7);
238*0Sstevel@tonic-gate 			if ((j = read(ifd, buf+n, k)) <= 0)
239*0Sstevel@tonic-gate 				break;
240*0Sstevel@tonic-gate 			n += j;
241*0Sstevel@tonic-gate 		}
242*0Sstevel@tonic-gate 		k = n &~ 7;
243*0Sstevel@tonic-gate 		if (k == 0)
244*0Sstevel@tonic-gate 			break;
245*0Sstevel@tonic-gate 		crypt(buf, k);
246*0Sstevel@tonic-gate 		if (write(ofd, buf, k) != k)
247*0Sstevel@tonic-gate 			perror("write");
248*0Sstevel@tonic-gate 		if (j <= 0)
249*0Sstevel@tonic-gate 			break;
250*0Sstevel@tonic-gate 	}
251*0Sstevel@tonic-gate 	if (n >= 0) {
252*0Sstevel@tonic-gate 		cp = &buf[n];
253*0Sstevel@tonic-gate 		k = 7 - (n & 7);
254*0Sstevel@tonic-gate 		srand(getpid());
255*0Sstevel@tonic-gate 		for (j = 0; j < k; j++)
256*0Sstevel@tonic-gate 			*cp++ = rand();
257*0Sstevel@tonic-gate 		*cp++ = n & 7;
258*0Sstevel@tonic-gate 		cp -= 8;
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 		crypt(cp, 8);
261*0Sstevel@tonic-gate 		if (write(ofd, cp, 8) != 8)
262*0Sstevel@tonic-gate 			perror("write");
263*0Sstevel@tonic-gate 	} else
264*0Sstevel@tonic-gate 		perror("read");
265*0Sstevel@tonic-gate }
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate /*
271*0Sstevel@tonic-gate  * Decrypt a file:
272*0Sstevel@tonic-gate  * Look at the last byte of the last 8 byte block decrypted
273*0Sstevel@tonic-gate  * to determine how many of the last 8 bytes to save.
274*0Sstevel@tonic-gate  * This also serves as a check to see if the decryption succeeded
275*0Sstevel@tonic-gate  * with a probability of (256-8)/256.
276*0Sstevel@tonic-gate  */
277*0Sstevel@tonic-gate void
fdecrypt(void)278*0Sstevel@tonic-gate fdecrypt(void)
279*0Sstevel@tonic-gate {
280*0Sstevel@tonic-gate 	char last8buf[8], *last8;
281*0Sstevel@tonic-gate 	int n, k, j;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	last8 = NULL;
284*0Sstevel@tonic-gate 	while ((n = read(ifd, buf, sizeof buf)) > 0) {
285*0Sstevel@tonic-gate 		j = n;
286*0Sstevel@tonic-gate 		while (n & 7) {
287*0Sstevel@tonic-gate 			k = 8 - (n & 7);
288*0Sstevel@tonic-gate 			if ((j = read(ifd, buf+n, k)) <= 0)
289*0Sstevel@tonic-gate 				break;
290*0Sstevel@tonic-gate 			n += j;
291*0Sstevel@tonic-gate 		}
292*0Sstevel@tonic-gate 		if (j <= 0)
293*0Sstevel@tonic-gate 			break;
294*0Sstevel@tonic-gate 		crypt(buf, n);
295*0Sstevel@tonic-gate 		if (last8)
296*0Sstevel@tonic-gate 			write(ofd, last8, 8);
297*0Sstevel@tonic-gate 		last8 = last8buf;
298*0Sstevel@tonic-gate 		n -= 8;
299*0Sstevel@tonic-gate 		memcpy(last8, buf+n, 8);
300*0Sstevel@tonic-gate 		if (n && write(ofd, buf, n) != n)
301*0Sstevel@tonic-gate 			perror("write");
302*0Sstevel@tonic-gate 	}
303*0Sstevel@tonic-gate 	if (n >= 0) {
304*0Sstevel@tonic-gate 		if (last8 == NULL
305*0Sstevel@tonic-gate 		|| n != 0
306*0Sstevel@tonic-gate 		|| ((signed char)last8[7]) < 0
307*0Sstevel@tonic-gate 		|| last8[7] > 7)
308*0Sstevel@tonic-gate 			fprintf(stderr, "%s: decryption failed\n", cmdname);
309*0Sstevel@tonic-gate 		else if (((signed char)last8[7]) > 0)
310*0Sstevel@tonic-gate 			write(ofd, last8, last8[7]);
311*0Sstevel@tonic-gate 	} else
312*0Sstevel@tonic-gate 		perror("read");
313*0Sstevel@tonic-gate }
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate void
usage(void)317*0Sstevel@tonic-gate usage(void)
318*0Sstevel@tonic-gate {
319*0Sstevel@tonic-gate 	fprintf(stderr,
320*0Sstevel@tonic-gate 		"Usage: %s -e [-b] [-f] [-k key] [ infile [ outfile ] ]\n",
321*0Sstevel@tonic-gate 		cmdname);
322*0Sstevel@tonic-gate 	fprintf(stderr,
323*0Sstevel@tonic-gate 		"   or: %s -d [-b] [-f] [-k key] [ infile [ outfile ] ]\n",
324*0Sstevel@tonic-gate 		cmdname);
325*0Sstevel@tonic-gate 	fprintf(stderr, "Use -e to encrypt, -d to decrypt\n");
326*0Sstevel@tonic-gate 	exit(2);
327*0Sstevel@tonic-gate }
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate /*
333*0Sstevel@tonic-gate  * Table giving odd parity (in high bit) for ASCII characters
334*0Sstevel@tonic-gate  * program does not use des_setparity() (which puts parity
335*0Sstevel@tonic-gate  * in low bit) in order to maintain backward compatibility
336*0Sstevel@tonic-gate  */
337*0Sstevel@tonic-gate static unsigned char partab[128] = {
338*0Sstevel@tonic-gate     0x80, 0x01, 0x02, 0x83, 0x04, 0x85, 0x86, 0x07,
339*0Sstevel@tonic-gate     0x08, 0x89, 0x8a, 0x0b, 0x8c, 0x0d, 0x0e, 0x8f,
340*0Sstevel@tonic-gate     0x10, 0x91, 0x92, 0x13, 0x94, 0x15, 0x16, 0x97,
341*0Sstevel@tonic-gate     0x98, 0x19, 0x1a, 0x9b, 0x1c, 0x9d, 0x9e, 0x1f,
342*0Sstevel@tonic-gate     0x20, 0xa1, 0xa2, 0x23, 0xa4, 0x25, 0x26, 0xa7,
343*0Sstevel@tonic-gate     0xa8, 0x29, 0x2a, 0xab, 0x2c, 0xad, 0xae, 0x2f,
344*0Sstevel@tonic-gate     0xb0, 0x31, 0x32, 0xb3, 0x34, 0xb5, 0xb6, 0x37,
345*0Sstevel@tonic-gate     0x38, 0xb9, 0xba, 0x3b, 0xbc, 0x3d, 0x3e, 0xbf,
346*0Sstevel@tonic-gate     0x40, 0xc1, 0xc2, 0x43, 0xc4, 0x45, 0x46, 0xc7,
347*0Sstevel@tonic-gate     0xc8, 0x49, 0x4a, 0xcb, 0x4c, 0xcd, 0xce, 0x4f,
348*0Sstevel@tonic-gate     0xd0, 0x51, 0x52, 0xd3, 0x54, 0xd5, 0xd6, 0x57,
349*0Sstevel@tonic-gate     0x58, 0xd9, 0xda, 0x5b, 0xdc, 0x5d, 0x5e, 0xdf,
350*0Sstevel@tonic-gate     0xe0, 0x61, 0x62, 0xe3, 0x64, 0xe5, 0xe6, 0x67,
351*0Sstevel@tonic-gate     0x68, 0xe9, 0xea, 0x6b, 0xec, 0x6d, 0x6e, 0xef,
352*0Sstevel@tonic-gate     0x70, 0xf1, 0xf2, 0x73, 0xf4, 0x75, 0x76, 0xf7,
353*0Sstevel@tonic-gate     0xf8, 0x79, 0x7a, 0xfb, 0x7c, 0xfd, 0xfe, 0x7f,
354*0Sstevel@tonic-gate };
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate /*
359*0Sstevel@tonic-gate  * Add odd parity to high bit of 8 byte key
360*0Sstevel@tonic-gate  */
361*0Sstevel@tonic-gate static void
putparity(char * p)362*0Sstevel@tonic-gate putparity(char *p)
363*0Sstevel@tonic-gate {
364*0Sstevel@tonic-gate     int i;
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate     for (i = 0; i < 8; i++) {
367*0Sstevel@tonic-gate         *p = partab[*p & 0x7f];
368*0Sstevel@tonic-gate         p++;
369*0Sstevel@tonic-gate     }
370*0Sstevel@tonic-gate }
371