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