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