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
process_option(char * arg,wbku_key_attr_t * ka)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
get_key(FILE * key_fp,wbku_key_attr_t * ka,uint8_t * key)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
encr_gen(cbc_handle_t * ch)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
encr_gen_3des(const wbku_key_attr_t * ka,const uint8_t * key)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
encr_gen_aes(const wbku_key_attr_t * ka,const uint8_t * key)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
usage(const char * cmd)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
main(int argc,char ** argv)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