xref: /titanic_41/usr/src/cmd/cmd-inet/usr.lib/wanboot/encr/encr.c (revision e0724c534a46ca4754330bc022bf1e2a68f5bb93)
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 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <libintl.h>
33 #include <locale.h>
34 #include <sys/des.h>
35 #include <strings.h>
36 #include <errno.h>
37 #include <wanbootutil.h>
38 #include <sys/sysmacros.h>
39 #include <sys/wanboot_impl.h>
40 
41 /* Return codes */
42 #define	ENCR_SUCCESS	0
43 #define	ENCR_NOKEY	1
44 #define	ENCR_ERROR	2
45 
46 /* Private buffer length */
47 #define	ENCR_BUF_LEN		1024
48 
49 /* Encryption algorithm suboption. */
50 #define	TYPE	0
51 
52 static char *opts[] = { "type", NULL };
53 
54 /*
55  * This routine is used to parse the suboptions of '-o' option.
56  *
57  * The option should be of the form: type=<3des|aes>
58  *
59  * This routine will pass the value of the suboption back in the
60  * supplied arguments, 'ka'.
61  *
62  * Returns:
63  *	ENCR_SUCCESS or ENCR_ERROR.
64  */
65 static int
66 process_option(char *arg, wbku_key_attr_t *ka)
67 {
68 	char *value;
69 	wbku_retcode_t ret;
70 
71 	while (*arg != '\0') {
72 		switch (getsubopt(&arg, opts, &value)) {
73 		case TYPE:
74 			/*
75 			 * Key type.
76 			 */
77 			ret = wbku_str_to_keyattr(value, ka, WBKU_ENCR_KEY);
78 			if (ret != WBKU_SUCCESS) {
79 				wbku_printerr("%s\n", wbku_retmsg(ret));
80 				return (ENCR_ERROR);
81 			}
82 			break;
83 		default:
84 			wbku_printerr("Invalid option %s\n", value);
85 			return (ENCR_ERROR);
86 		}
87 	}
88 
89 	return (ENCR_SUCCESS);
90 }
91 
92 /*
93  * This routine is used to find the key of type defined by 'ka' and
94  * return it in 'key'. The key file should have been opened by the
95  * caller and the handle passed in 'key_fp'.
96  *
97  * Returns:
98  *	ENCR_SUCCESS, ENCR_ERROR or ENCR_NOKEY.
99  */
100 static int
101 get_key(FILE *key_fp, wbku_key_attr_t *ka, uint8_t *key)
102 {
103 	wbku_retcode_t ret;
104 
105 	/*
106 	 * Find the client key, if it exists.
107 	 */
108 	ret = wbku_find_key(key_fp, NULL, ka, key, B_FALSE);
109 	if (ret != WBKU_SUCCESS) {
110 		wbku_printerr("%s\n", wbku_retmsg(ret));
111 		if (ret == WBKU_NOKEY)
112 			return (ENCR_NOKEY);
113 		else
114 			return (ENCR_ERROR);
115 	}
116 	return (ENCR_SUCCESS);
117 }
118 
119 /*
120  * This routine is the common encryption routine used to encrypt data
121  * using the CBC handle initialized by the calling routine.  The data
122  * to be encrypted is read from stdin and the encrypted data is written to
123  * stdout.
124  *
125  * Returns:
126  *	ENCR_SUCCESS or ENCR_ERROR.
127  */
128 static int
129 encr_gen(cbc_handle_t *ch)
130 {
131 	uint8_t iv[WANBOOT_MAXBLOCKLEN];
132 	uint8_t buf[ENCR_BUF_LEN];
133 	uint8_t *bufp;
134 	int read_size;
135 	ssize_t i, j, k;
136 
137 	/*
138 	 * Use a random number as the IV
139 	 */
140 	if (wbio_nread_rand(iv, ch->blocklen) != 0) {
141 		wbku_printerr("Cannot generate initialization vector");
142 		return (ENCR_ERROR);
143 	}
144 
145 	/*
146 	 * Output the IV to stdout.
147 	 */
148 	if (wbio_nwrite(STDOUT_FILENO, iv, ch->blocklen) != 0) {
149 		wbku_printerr("Write error encountered\n");
150 		return (ENCR_ERROR);
151 	}
152 
153 	/*
154 	 * Try to read in multiple of block_size as CBC requires
155 	 * that data be encrypted in block_size chunks.
156 	 */
157 	read_size = ENCR_BUF_LEN / ch->blocklen * ch->blocklen;
158 	while ((i = read(STDIN_FILENO, buf, read_size)) > 0) {
159 		/*
160 		 * If data received is not a multiple of the block size,
161 		 * try to receive more.  If reach EOF, pad the rest with
162 		 * 0.
163 		 */
164 		if ((j = i % ch->blocklen) != 0) {
165 			/*
166 			 * Determine how more data need to be received to
167 			 * fill out the buffer so that it contains a
168 			 * multiple of block_size chunks.
169 			 */
170 			j = ch->blocklen - j;
171 			bufp = buf + i;
172 			k = j;
173 
174 			/*
175 			 * Try to fill the gap.
176 			 *
177 			 */
178 			while ((j = read(STDIN_FILENO, bufp, j)) != k &&
179 			    j != 0) {
180 				bufp += j;
181 				k -= j;
182 				j = k;
183 			}
184 
185 			/*
186 			 * This is the total length of the buffer.
187 			 */
188 			i = (i + ch->blocklen) - (i % ch->blocklen);
189 
190 			if (j == 0) {
191 				/* EOF, do padding. */
192 				(void) memset(bufp, 0, k);
193 				(void) cbc_encrypt(ch, buf, i, iv);
194 			} else if (j > 0) {
195 				/* The gap has been filled in */
196 				(void) cbc_encrypt(ch, buf, i, iv);
197 			} else {
198 				/* Oops. */
199 				wbku_printerr("Input error");
200 				return (ENCR_ERROR);
201 			}
202 		} else {
203 			/* A multiple of the block size was received */
204 			(void) cbc_encrypt(ch, buf, i, iv);
205 		}
206 		if (wbio_nwrite(STDOUT_FILENO, buf, i) != 0) {
207 			wbku_printerr("Write error encountered\n");
208 			return (ENCR_ERROR);
209 		}
210 	}
211 
212 	return (ENCR_SUCCESS);
213 }
214 
215 /*
216  * This routine initializes a CBC handle for 3DES and calls the
217  * common encryption routine to encrypt data.
218  *
219  * Returns:
220  *	ENCR_SUCCESS or ENCR_ERROR.
221  */
222 static int
223 encr_gen_3des(const wbku_key_attr_t *ka, const uint8_t *key)
224 {
225 	cbc_handle_t ch;
226 	void *eh;
227 	int ret;
228 
229 	/*
230 	 * Initialize a 3DES handle.
231 	 */
232 	if (des3_init(&eh) != 0) {
233 		return (ENCR_ERROR);
234 	}
235 	des3_key(eh, key);
236 
237 	/*
238 	 * Initialize the CBC handle.
239 	 */
240 	cbc_makehandle(&ch, eh, ka->ka_len, DES3_BLOCK_SIZE,
241 	    DES3_IV_SIZE, des3_encrypt, des3_decrypt);
242 
243 	/*
244 	 * Encrypt the data.
245 	 */
246 	ret = encr_gen(&ch);
247 
248 	/*
249 	 *  Free the 3DES resources.
250 	 */
251 	des3_fini(eh);
252 
253 	return (ret);
254 }
255 
256 /*
257  * This routine initializes a CBC handle for AES and calls the
258  * common encryption routine to encrypt data.
259  *
260  * Returns:
261  *	ENCR_SUCCESS or ENCR_ERROR.
262  */
263 static int
264 encr_gen_aes(const wbku_key_attr_t *ka, const uint8_t *key)
265 {
266 	cbc_handle_t ch;
267 	void *eh;
268 	int ret;
269 
270 	/*
271 	 * Initialize an AES handle.
272 	 */
273 	if (aes_init(&eh) != 0) {
274 		return (ENCR_ERROR);
275 	}
276 	aes_key(eh, key, ka->ka_len);
277 
278 	/*
279 	 * Initialize the CBC handle.
280 	 */
281 	cbc_makehandle(&ch, eh, ka->ka_len, AES_BLOCK_SIZE,
282 	    AES_IV_SIZE, aes_encrypt, aes_decrypt);
283 
284 	/*
285 	 * Encrypt the data.
286 	 */
287 	ret = encr_gen(&ch);
288 
289 	/*
290 	 *  Free the AES resources.
291 	 */
292 	aes_fini(eh);
293 
294 	return (ret);
295 }
296 
297 /*
298  * Prints usage().
299  */
300 static void
301 usage(const char *cmd)
302 {
303 	(void) fprintf(stderr,
304 	    gettext("Usage: %s -o type=<%s|%s> -k key_file\n"),
305 	    cmd, WBKU_KW_3DES, WBKU_KW_AES_128);
306 }
307 
308 /*
309  * This program is used to encrypt data read from stdin and print it to
310  * stdout. The path to the key file and the algorithm to use are
311  * provided by the user.
312  *
313  * Returns:
314  *	ENCR_SUCCESS, ENCR_ERROR or ENCR_NOKEY.
315  */
316 int
317 main(int argc, char **argv)
318 {
319 	uint8_t key[WANBOOT_MAXKEYLEN];
320 	int c;
321 	char *keyfile_name = NULL;
322 	wbku_key_attr_t ka;
323 	FILE *key_fp;
324 	int ret;
325 
326 	/*
327 	 * Do the necessary magic for localization support.
328 	 */
329 	(void) setlocale(LC_ALL, "");
330 #if !defined(TEXT_DOMAIN)
331 #define	TEXT_DOMAIN "SYS_TEST"
332 #endif
333 	(void) textdomain(TEXT_DOMAIN);
334 
335 	/*
336 	 * Initialize program name for use by wbku_printerr().
337 	 */
338 	wbku_errinit(argv[0]);
339 
340 	/*
341 	 * Should be five arguments.
342 	 */
343 	if (argc < 5) {
344 		usage(argv[0]);
345 		return (ENCR_ERROR);
346 	}
347 
348 	/*
349 	 * Parse the options.
350 	 */
351 	ka.ka_type = WBKU_KEY_UNKNOWN;
352 	while ((c = getopt(argc, argv, "o:k:")) != EOF) {
353 		switch (c) {
354 		case 'o':
355 			/*
356 			 * Suboptions.
357 			 */
358 			ret = process_option(optarg, &ka);
359 			if (ret != ENCR_SUCCESS) {
360 				usage(argv[0]);
361 				return (ret);
362 			}
363 			break;
364 		case 'k':
365 			/*
366 			 * Path to key file.
367 			 */
368 			keyfile_name = optarg;
369 			break;
370 		default:
371 			usage(argv[0]);
372 			return (ENCR_ERROR);
373 		}
374 	}
375 
376 	/*
377 	 * Gotta have a key file.
378 	 */
379 	if (keyfile_name == NULL) {
380 		wbku_printerr("Must specify the key_file\n");
381 		return (ENCR_ERROR);
382 	}
383 
384 	/*
385 	 * Gotta have a key type.
386 	 */
387 	if (ka.ka_type == WBKU_KEY_UNKNOWN) {
388 		wbku_printerr("Unsupported encryption algorithm\n");
389 		return (ENCR_ERROR);
390 	}
391 
392 	/*
393 	 * Open the key file for reading.
394 	 */
395 	if ((key_fp = fopen(keyfile_name, "r")) == NULL) {
396 		wbku_printerr("Cannot open %s", keyfile_name);
397 		return (ENCR_ERROR);
398 	}
399 
400 	/*
401 	 * Get the key from the key file and call the right
402 	 * encryption routine.
403 	 */
404 	ret = get_key(key_fp, &ka, key);
405 	if (ret == ENCR_SUCCESS) {
406 		switch (ka.ka_type) {
407 		case WBKU_KEY_3DES:
408 			ret = encr_gen_3des(&ka, key);
409 			break;
410 		case WBKU_KEY_AES_128:
411 			ret = encr_gen_aes(&ka, key);
412 			break;
413 		default:
414 			ret = ENCR_ERROR;	/* Internal error only */
415 		}
416 	}
417 
418 	(void) fclose(key_fp);
419 	return (ret);
420 }
421