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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* Portions Copyright 2005 Richard Lowe */ 22 /* 23 * Copyright 2008 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 * decrypt.c 31 * 32 * Implements encrypt(1) and decrypt(1) commands 33 * 34 * One binary performs both encrypt/decrypt operation. 35 * 36 * Usage: 37 * -a algorithm mechanism name without CKM_ prefix. Case 38 * does not matter 39 * -k keyfile file containing key data. If not specified user is 40 * prompted to enter key. key length > 0 is required 41 * -i infile input file to encrypt/decrypt. If omitted, stdin used. 42 * -o outfile output file to encrypt/decrypt. If omitted, stdout used. 43 * if infile & outfile are same, a temp file is used for 44 * output and infile is replaced with this file after 45 * operation is complete 46 * -l Display the list of algorithms 47 * -v Display verbose information 48 * -T tokenspec Specify a PKCS#11 token (optionally used with -K) 49 * -K keylabel Specify the symmetric PKCS#11 token key label 50 * 51 * Implementation notes: 52 * IV data - It is generated by random bytes equal to one block size. 53 * 54 * Encrypted output format - 55 * - Output format version number (1) - 4 bytes in network byte order. 56 * - Iterations used in key gen function, 4 bytes in network byte order. 57 * - IV ('ivlen' bytes). Length is algorithm-dependent (see mech_aliases) 58 * - Salt data used in key gen (16 bytes) 59 * - Cipher text data (remainder of the file) 60 */ 61 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <unistd.h> 65 #include <errno.h> 66 #include <fcntl.h> 67 #include <ctype.h> 68 #include <strings.h> 69 #include <libintl.h> 70 #include <libgen.h> 71 #include <locale.h> 72 #include <limits.h> 73 #include <sys/types.h> 74 #include <sys/stat.h> 75 #include <netinet/in.h> 76 #include <security/cryptoki.h> 77 #include <cryptoutil.h> 78 #include <kmfapi.h> 79 80 #define BUFFERSIZE (2048) /* Buffer size for reading file */ 81 #define BLOCKSIZE (128) /* Largest guess for block size */ 82 #define PROGRESSSIZE (BUFFERSIZE*20) /* stdin progress indicator size */ 83 84 #define SUNW_ENCRYPT_FILE_VERSION 1 85 86 /* 87 * Exit Status codes 88 */ 89 #ifndef EXIT_SUCCESS 90 #define EXIT_SUCCESS 0 /* No errors */ 91 #define EXIT_FAILURE 1 /* All errors except usage */ 92 #endif /* EXIT_SUCCESS */ 93 94 #define EXIT_USAGE 2 /* usage/syntax error */ 95 96 #define ENCRYPT_NAME "encrypt" /* name of encrypt command */ 97 #define ENCRYPT_OPTIONS "a:T:K:k:i:o:lv" /* options for encrypt */ 98 #define DECRYPT_NAME "decrypt" /* name of decrypt command */ 99 #define DECRYPT_OPTIONS "a:T:K:k:i:o:lv" /* options for decrypt */ 100 101 /* 102 * Structure containing info for encrypt/decrypt 103 * command 104 */ 105 struct CommandInfo { 106 char *name; /* name of the command */ 107 char *options; /* command line options */ 108 CK_FLAGS flags; 109 CK_ATTRIBUTE_TYPE type; /* type of command */ 110 111 /* function pointers for various operations */ 112 CK_RV (*Init)(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE); 113 CK_RV (*Update)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, 114 CK_ULONG_PTR); 115 CK_RV (*Crypt)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, 116 CK_ULONG_PTR); 117 CK_RV (*Final)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR); 118 }; 119 120 static struct CommandInfo encrypt_cmd = { 121 ENCRYPT_NAME, 122 ENCRYPT_OPTIONS, 123 CKF_ENCRYPT, 124 CKA_ENCRYPT, 125 C_EncryptInit, 126 C_EncryptUpdate, 127 C_Encrypt, 128 C_EncryptFinal 129 }; 130 131 static struct CommandInfo decrypt_cmd = { 132 DECRYPT_NAME, 133 DECRYPT_OPTIONS, 134 CKF_DECRYPT, 135 CKA_DECRYPT, 136 C_DecryptInit, 137 C_DecryptUpdate, 138 C_Decrypt, 139 C_DecryptFinal 140 }; 141 142 struct mech_alias { 143 CK_MECHANISM_TYPE type; 144 char *alias; 145 CK_ULONG keysize_min; 146 CK_ULONG keysize_max; 147 int keysize_unit; 148 int ivlen; 149 boolean_t available; 150 }; 151 152 #define MECH_ALIASES_COUNT 4 153 154 static struct mech_alias mech_aliases[] = { 155 { CKM_AES_CBC_PAD, "aes", ULONG_MAX, 0L, 8, 16, B_FALSE }, 156 { CKM_RC4, "arcfour", ULONG_MAX, 0L, 1, 0, B_FALSE }, 157 { CKM_DES_CBC_PAD, "des", 8, 8, 8, 8, B_FALSE }, 158 { CKM_DES3_CBC_PAD, "3des", 24, 24, 8, 8, B_FALSE }, 159 }; 160 161 static CK_BBOOL truevalue = TRUE; 162 static CK_BBOOL falsevalue = FALSE; 163 164 static boolean_t aflag = B_FALSE; /* -a <algorithm> flag, required */ 165 static boolean_t kflag = B_FALSE; /* -k <keyfile> flag */ 166 static boolean_t iflag = B_FALSE; /* -i <infile> flag, use stdin if absent */ 167 static boolean_t oflag = B_FALSE; /* -o <outfile> flag, use stdout if absent */ 168 static boolean_t lflag = B_FALSE; /* -l flag (list) */ 169 static boolean_t vflag = B_FALSE; /* -v flag (verbose) */ 170 static boolean_t Tflag = B_FALSE; /* -T flag (tokenspec) */ 171 static boolean_t Kflag = B_FALSE; /* -K flag (keylabel) */ 172 173 static char *keyfile = NULL; /* name of keyfile */ 174 static char *inputfile = NULL; /* name of input file */ 175 static char *outputfile = NULL; /* name of output file */ 176 static char *token_label = NULL; /* name of PKCS#11 token */ 177 static char *key_label = NULL; /* name of PKCS#11 token key label */ 178 179 static int status_pos = 0; /* current position of progress bar element */ 180 181 /* 182 * function prototypes 183 */ 184 static void usage(struct CommandInfo *cmd); 185 static int execute_cmd(struct CommandInfo *cmd, char *algo_str); 186 static int crypt_multipart(struct CommandInfo *cmd, CK_SESSION_HANDLE hSession, 187 int infd, int outfd, off_t insize); 188 189 int 190 main(int argc, char **argv) 191 { 192 193 extern char *optarg; 194 extern int optind; 195 char *optstr; 196 char c; /* current getopts flag */ 197 char *algo_str = NULL; /* algorithm string */ 198 struct CommandInfo *cmd; 199 char *cmdname; /* name of command */ 200 boolean_t errflag = B_FALSE; 201 202 (void) setlocale(LC_ALL, ""); 203 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 204 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 205 #endif 206 (void) textdomain(TEXT_DOMAIN); 207 208 /* 209 * Based on command name, determine 210 * type of command. 211 */ 212 cmdname = basename(argv[0]); 213 214 cryptodebug_init(cmdname); 215 216 if (strcmp(cmdname, encrypt_cmd.name) == 0) { 217 cmd = &encrypt_cmd; 218 } else if (strcmp(cmdname, decrypt_cmd.name) == 0) { 219 cmd = &decrypt_cmd; 220 } else { 221 cryptoerror(LOG_STDERR, gettext( 222 "command name must be either encrypt or decrypt")); 223 exit(EXIT_USAGE); 224 } 225 226 optstr = cmd->options; 227 228 /* Parse command line arguments */ 229 while (!errflag && (c = getopt(argc, argv, optstr)) != -1) { 230 231 switch (c) { 232 case 'a': 233 aflag = B_TRUE; 234 algo_str = optarg; 235 break; 236 case 'k': 237 kflag = B_TRUE; 238 keyfile = optarg; 239 break; 240 case 'T': 241 Tflag = B_TRUE; 242 token_label = optarg; 243 break; 244 case 'K': 245 Kflag = B_TRUE; 246 key_label = optarg; 247 break; 248 case 'i': 249 iflag = B_TRUE; 250 inputfile = optarg; 251 break; 252 case 'o': 253 oflag = B_TRUE; 254 outputfile = optarg; 255 break; 256 case 'l': 257 lflag = B_TRUE; 258 break; 259 case 'v': 260 vflag = B_TRUE; 261 break; 262 default: 263 errflag = B_TRUE; 264 } 265 } 266 267 if (errflag || (!aflag && !lflag) || (lflag && argc > 2) || 268 (kflag && Kflag) || (Tflag && !Kflag) || 269 (optind < argc)) { 270 usage(cmd); 271 exit(EXIT_USAGE); 272 } 273 274 return (execute_cmd(cmd, algo_str)); 275 } 276 277 /* 278 * usage message 279 */ 280 static void 281 usage(struct CommandInfo *cmd) 282 { 283 (void) fprintf(stderr, gettext("Usage:\n")); 284 if (cmd->type == CKA_ENCRYPT) { 285 (void) fprintf(stderr, gettext(" encrypt -l\n")); 286 (void) fprintf(stderr, gettext(" encrypt -a <algorithm> " 287 "[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] " 288 "[-i <infile>] [-o <outfile>]\n")); 289 290 } else { 291 (void) fprintf(stderr, gettext(" decrypt -l\n")); 292 (void) fprintf(stderr, gettext(" decrypt -a <algorithm> " 293 "[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] " 294 "[-i <infile>] [-o <outfile>]\n")); 295 } 296 } 297 298 /* 299 * Print out list of algorithms in default and verbose mode 300 */ 301 static void 302 algorithm_list() 303 { 304 int mech; 305 306 (void) printf(gettext("Algorithm Keysize: Min Max (bits)\n" 307 "------------------------------------------\n")); 308 309 for (mech = 0; mech < MECH_ALIASES_COUNT; mech++) { 310 311 if (mech_aliases[mech].available == B_FALSE) 312 continue; 313 314 (void) printf("%-15s", mech_aliases[mech].alias); 315 316 if (mech_aliases[mech].keysize_min != UINT_MAX && 317 mech_aliases[mech].keysize_max != 0) 318 (void) printf(" %5lu %5lu\n", 319 (mech_aliases[mech].keysize_min * 320 mech_aliases[mech].keysize_unit), 321 (mech_aliases[mech].keysize_max * 322 mech_aliases[mech].keysize_unit)); 323 else 324 (void) printf("\n"); 325 326 } 327 } 328 329 /* 330 * This function will login into the token with the provided password and 331 * find the token key object with the specified keytype and keylabel. 332 */ 333 static int 334 get_token_key(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keytype, 335 char *keylabel, CK_BYTE *password, int password_len, 336 CK_OBJECT_HANDLE *keyobj) 337 { 338 CK_RV rv; 339 CK_ATTRIBUTE pTmpl[10]; 340 CK_OBJECT_CLASS class = CKO_SECRET_KEY; 341 CK_BBOOL true = 1; 342 CK_BBOOL is_token = 1; 343 CK_ULONG key_obj_count = 1; 344 int i; 345 CK_KEY_TYPE ckKeyType = keytype; 346 347 348 rv = C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)password, 349 (CK_ULONG)password_len); 350 if (rv != CKR_OK) { 351 (void) fprintf(stderr, "Cannot login to the token." 352 " error = %s\n", pkcs11_strerror(rv)); 353 return (-1); 354 } 355 356 i = 0; 357 pTmpl[i].type = CKA_TOKEN; 358 pTmpl[i].pValue = &is_token; 359 pTmpl[i].ulValueLen = sizeof (CK_BBOOL); 360 i++; 361 362 pTmpl[i].type = CKA_CLASS; 363 pTmpl[i].pValue = &class; 364 pTmpl[i].ulValueLen = sizeof (class); 365 i++; 366 367 pTmpl[i].type = CKA_LABEL; 368 pTmpl[i].pValue = keylabel; 369 pTmpl[i].ulValueLen = strlen(keylabel); 370 i++; 371 372 pTmpl[i].type = CKA_KEY_TYPE; 373 pTmpl[i].pValue = &ckKeyType; 374 pTmpl[i].ulValueLen = sizeof (ckKeyType); 375 i++; 376 377 pTmpl[i].type = CKA_PRIVATE; 378 pTmpl[i].pValue = &true; 379 pTmpl[i].ulValueLen = sizeof (true); 380 i++; 381 382 rv = C_FindObjectsInit(hSession, pTmpl, i); 383 if (rv != CKR_OK) { 384 goto out; 385 } 386 387 rv = C_FindObjects(hSession, keyobj, 1, &key_obj_count); 388 389 (void) C_FindObjectsFinal(hSession); 390 391 out: 392 if (rv != CKR_OK) { 393 (void) fprintf(stderr, 394 "Cannot retrieve key object. error = %s\n", 395 pkcs11_strerror(rv)); 396 return (-1); 397 } 398 399 if (key_obj_count == 0) { 400 (void) fprintf(stderr, "Cannot find the key object.\n"); 401 return (-1); 402 } 403 404 return (0); 405 } 406 407 408 /* 409 * Execute the command. 410 * cmd - command pointing to type of operation. 411 * algo_str - alias of the algorithm passed. 412 */ 413 static int 414 execute_cmd(struct CommandInfo *cmd, char *algo_str) 415 { 416 CK_RV rv; 417 CK_ULONG slotcount; 418 CK_SLOT_ID slotID; 419 CK_SLOT_ID_PTR pSlotList = NULL; 420 CK_MECHANISM_TYPE mech_type = 0; 421 CK_MECHANISM_INFO info, kg_info; 422 CK_MECHANISM mech; 423 CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; 424 CK_BYTE_PTR pkeydata = NULL; 425 CK_BYTE salt[CK_PKCS5_PBKD2_SALT_SIZE]; 426 CK_ULONG keysize = 0; 427 int i, slot, mek; /* index variables */ 428 int status; 429 struct stat insbuf; /* stat buf for infile */ 430 struct stat outsbuf; /* stat buf for outfile */ 431 char tmpnam[PATH_MAX]; /* tmp file name */ 432 CK_OBJECT_HANDLE key = (CK_OBJECT_HANDLE) 0; 433 int infd = 0; /* input file, stdin default */ 434 int outfd = 1; /* output file, stdout default */ 435 char *outfilename = NULL; 436 boolean_t errflag = B_TRUE; 437 boolean_t inoutsame = B_FALSE; /* if both input & output are same */ 438 CK_BYTE_PTR pivbuf = NULL_PTR; 439 CK_ULONG ivlen = 0L; 440 int mech_match = 0; 441 uint32_t iterations = CK_PKCS5_PBKD2_ITERATIONS; 442 CK_ULONG keylen; 443 uint32_t version = SUNW_ENCRYPT_FILE_VERSION; 444 CK_KEY_TYPE keytype; 445 KMF_RETURN kmfrv; 446 CK_SLOT_ID token_slot_id; 447 448 if (aflag) { 449 /* Determine if algorithm is valid */ 450 for (mech_match = 0; mech_match < MECH_ALIASES_COUNT; 451 mech_match++) { 452 if (strcmp(algo_str, 453 mech_aliases[mech_match].alias) == 0) { 454 mech_type = mech_aliases[mech_match].type; 455 break; 456 } 457 } 458 459 if (mech_match == MECH_ALIASES_COUNT) { 460 cryptoerror(LOG_STDERR, 461 gettext("unknown algorithm -- %s"), algo_str); 462 return (EXIT_FAILURE); 463 } 464 465 /* 466 * Process keyfile or get the token pin if -K is specified. 467 * 468 * If a keyfile is provided, get the key data from 469 * the file. Otherwise, prompt for a passphrase. The 470 * passphrase is used as the key data. 471 */ 472 if (Kflag) { 473 /* get the pin of the token */ 474 if (token_label == NULL || !strlen(token_label)) { 475 token_label = pkcs11_default_token(); 476 } 477 478 status = pkcs11_get_pass(token_label, 479 (char **)&pkeydata, (size_t *)&keysize, 0, B_FALSE); 480 } else if (kflag) { 481 /* get the key file */ 482 status = pkcs11_read_data(keyfile, (void **)&pkeydata, 483 (size_t *)&keysize); 484 } else { 485 /* get the key from input */ 486 status = pkcs11_get_pass(NULL, (char **)&pkeydata, 487 (size_t *)&keysize, 0, B_FALSE); 488 } 489 490 if (status == -1 || keysize == 0L) { 491 cryptoerror(LOG_STDERR, 492 Kflag ? gettext("invalid password.") : 493 gettext("invalid key.")); 494 return (EXIT_FAILURE); 495 } 496 } 497 498 bzero(salt, sizeof (salt)); 499 /* Initialize pkcs */ 500 rv = C_Initialize(NULL); 501 if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { 502 cryptoerror(LOG_STDERR, gettext("failed to initialize " 503 "PKCS #11 framework: %s"), pkcs11_strerror(rv)); 504 goto cleanup; 505 } 506 507 /* Get slot count */ 508 rv = C_GetSlotList(0, NULL_PTR, &slotcount); 509 if (rv != CKR_OK || slotcount == 0) { 510 cryptoerror(LOG_STDERR, gettext( 511 "failed to find any cryptographic provider," 512 "please check with your system administrator: %s"), 513 pkcs11_strerror(rv)); 514 goto cleanup; 515 } 516 517 /* Found at least one slot, allocate memory for slot list */ 518 pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID)); 519 if (pSlotList == NULL_PTR) { 520 int err = errno; 521 cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(err)); 522 goto cleanup; 523 } 524 525 /* Get the list of slots */ 526 if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) { 527 cryptoerror(LOG_STDERR, gettext( 528 "failed to find any cryptographic provider," 529 "please check with your system administrator: %s"), 530 pkcs11_strerror(rv)); 531 goto cleanup; 532 } 533 534 if (lflag) { 535 536 /* Iterate through slots */ 537 for (slot = 0; slot < slotcount; slot++) { 538 539 /* Iterate through each mechanism */ 540 for (mek = 0; mek < MECH_ALIASES_COUNT; mek++) { 541 rv = C_GetMechanismInfo(pSlotList[slot], 542 mech_aliases[mek].type, &info); 543 544 if (rv != CKR_OK) 545 continue; 546 547 /* 548 * Set to minimum/maximum key sizes assuming 549 * the values available are not 0. 550 */ 551 if (info.ulMinKeySize && (info.ulMinKeySize < 552 mech_aliases[mek].keysize_min)) 553 mech_aliases[mek].keysize_min = 554 info.ulMinKeySize; 555 556 if (info.ulMaxKeySize && (info.ulMaxKeySize > 557 mech_aliases[mek].keysize_max)) 558 mech_aliases[mek].keysize_max = 559 info.ulMaxKeySize; 560 561 mech_aliases[mek].available = B_TRUE; 562 } 563 564 } 565 566 algorithm_list(); 567 568 errflag = B_FALSE; 569 goto cleanup; 570 } 571 572 573 /* 574 * Find a slot with matching mechanism 575 * 576 * If -K is specified, we find the slot id for the token first, then 577 * check if the slot supports the algorithm. 578 */ 579 i = 0; 580 if (Kflag) { 581 kmfrv = kmf_pk11_token_lookup(NULL, token_label, 582 &token_slot_id); 583 if (kmfrv != KMF_OK) { 584 cryptoerror(LOG_STDERR, 585 gettext("no matching PKCS#11 token")); 586 errflag = B_TRUE; 587 goto cleanup; 588 } 589 rv = C_GetMechanismInfo(token_slot_id, mech_type, &info); 590 if (rv == CKR_OK && (info.flags & cmd->flags)) 591 slotID = token_slot_id; 592 else 593 i = slotcount; 594 } else { 595 for (i = 0; i < slotcount; i++) { 596 slotID = pSlotList[i]; 597 rv = C_GetMechanismInfo(slotID, mech_type, &info); 598 if (rv != CKR_OK) { 599 continue; /* to the next slot */ 600 } else { 601 /* 602 * If the slot support the crypto, also 603 * make sure it supports the correct 604 * key generation mech if needed. 605 * 606 * We need PKCS5 when RC4 is used or 607 * when the key is entered on cmd line. 608 */ 609 if ((info.flags & cmd->flags) && 610 (mech_type == CKM_RC4) || 611 (keyfile == NULL)) { 612 rv = C_GetMechanismInfo(slotID, 613 CKM_PKCS5_PBKD2, &kg_info); 614 if (rv == CKR_OK) 615 break; 616 } else if (info.flags & cmd->flags) { 617 break; 618 } 619 } 620 } 621 } 622 623 /* Show error if no matching mechanism found */ 624 if (i == slotcount) { 625 cryptoerror(LOG_STDERR, 626 gettext("no cryptographic provider was " 627 "found for this algorithm -- %s"), algo_str); 628 goto cleanup; 629 } 630 631 /* Open a session */ 632 rv = C_OpenSession(slotID, CKF_SERIAL_SESSION, 633 NULL_PTR, NULL, &hSession); 634 635 if (rv != CKR_OK) { 636 cryptoerror(LOG_STDERR, 637 gettext("can not open PKCS #11 session: %s"), 638 pkcs11_strerror(rv)); 639 goto cleanup; 640 } 641 642 /* 643 * Generate IV data for encrypt. 644 */ 645 ivlen = mech_aliases[mech_match].ivlen; 646 if ((pivbuf = malloc((size_t)ivlen)) == NULL) { 647 int err = errno; 648 cryptoerror(LOG_STDERR, gettext("malloc: %s"), 649 strerror(err)); 650 goto cleanup; 651 } 652 653 if (cmd->type == CKA_ENCRYPT) { 654 if ((pkcs11_random_data((void *)pivbuf, 655 mech_aliases[mech_match].ivlen)) != 0) { 656 cryptoerror(LOG_STDERR, gettext( 657 "Unable to generate random " 658 "data for initialization vector.")); 659 goto cleanup; 660 } 661 } 662 663 /* 664 * Create the key object 665 */ 666 rv = pkcs11_mech2keytype(mech_type, &keytype); 667 if (rv != CKR_OK) { 668 cryptoerror(LOG_STDERR, 669 gettext("unable to find key type for algorithm.")); 670 goto cleanup; 671 } 672 673 /* Open input file */ 674 if (iflag) { 675 if ((infd = open(inputfile, O_RDONLY | O_NONBLOCK)) == -1) { 676 cryptoerror(LOG_STDERR, gettext( 677 "can not open input file %s"), inputfile); 678 goto cleanup; 679 } 680 681 /* Get info on input file */ 682 if (fstat(infd, &insbuf) == -1) { 683 cryptoerror(LOG_STDERR, gettext( 684 "can not stat input file %s"), inputfile); 685 goto cleanup; 686 } 687 } 688 689 /* 690 * Prepare output file 691 * If the input & output file are same, 692 * the output is written to a temp 693 * file first, then renamed to the original file 694 * after the crypt operation 695 */ 696 inoutsame = B_FALSE; 697 if (oflag) { 698 outfilename = outputfile; 699 if ((stat(outputfile, &outsbuf) != -1) && 700 (insbuf.st_ino == outsbuf.st_ino)) { 701 char *dir; 702 703 /* create temp file on same dir */ 704 dir = dirname(outputfile); 705 (void) snprintf(tmpnam, sizeof (tmpnam), 706 "%s/encrXXXXXX", dir); 707 outfilename = tmpnam; 708 if ((outfd = mkstemp(tmpnam)) == -1) { 709 cryptoerror(LOG_STDERR, gettext( 710 "cannot create temp file")); 711 goto cleanup; 712 } 713 inoutsame = B_TRUE; 714 } else { 715 /* Create file for output */ 716 if ((outfd = open(outfilename, 717 O_CREAT|O_WRONLY|O_TRUNC, 0644)) == -1) { 718 cryptoerror(LOG_STDERR, gettext( 719 "cannot open output file %s"), 720 outfilename); 721 goto cleanup; 722 } 723 } 724 } 725 726 /* 727 * Read the version number from the head of the file 728 * to know how to interpret the data that follows. 729 */ 730 if (cmd->type == CKA_DECRYPT) { 731 if (read(infd, &version, sizeof (version)) != 732 sizeof (version)) { 733 cryptoerror(LOG_STDERR, gettext( 734 "failed to get format version from " 735 "input file.")); 736 goto cleanup; 737 } 738 /* convert to host byte order */ 739 version = ntohl(version); 740 741 switch (version) { 742 case 1: 743 /* 744 * Version 1 output format: 745 * - Output format version 1 (4 bytes) 746 * - Iterations used in key gen function (4 bytes) 747 * - IV ('ivlen' bytes). The length algorithm-dependent 748 * - Salt data used in key gen (16 bytes) 749 * - Cipher text data (remainder of the file) 750 * 751 * An encrypted file has IV as first block (0 or 752 * more bytes depending on mechanism) followed 753 * by cipher text. Get the IV from the encrypted 754 * file. 755 */ 756 /* 757 * Read iteration count and salt data. 758 */ 759 if (read(infd, &iterations, 760 sizeof (iterations)) != sizeof (iterations)) { 761 cryptoerror(LOG_STDERR, gettext( 762 "failed to get iterations from " 763 "input file.")); 764 goto cleanup; 765 } 766 /* convert to host byte order */ 767 iterations = ntohl(iterations); 768 if (ivlen > 0 && 769 read(infd, pivbuf, ivlen) != ivlen) { 770 cryptoerror(LOG_STDERR, gettext( 771 "failed to get initialization " 772 "vector from input file.")); 773 goto cleanup; 774 } 775 if (read(infd, salt, sizeof (salt)) 776 != sizeof (salt)) { 777 cryptoerror(LOG_STDERR, gettext( 778 "failed to get salt data from " 779 "input file.")); 780 goto cleanup; 781 } 782 break; 783 default: 784 cryptoerror(LOG_STDERR, gettext( 785 "Unrecognized format version read from " 786 "input file - expected %d, got %d."), 787 SUNW_ENCRYPT_FILE_VERSION, version); 788 goto cleanup; 789 break; 790 } 791 } 792 793 /* 794 * If Kflag is set, let's find the token key now. 795 * 796 * If Kflag is not set and if encrypting, we need some random 797 * salt data to create the key. If decrypting, 798 * the salt should come from head of the file 799 * to be decrypted. 800 */ 801 if (Kflag) { 802 rv = get_token_key(hSession, keytype, key_label, pkeydata, 803 keysize, &key); 804 if (rv != CKR_OK) { 805 cryptoerror(LOG_STDERR, gettext( 806 "Can not find the token key")); 807 goto cleanup; 808 } else { 809 goto do_crypto; 810 } 811 } else if (cmd->type == CKA_ENCRYPT) { 812 rv = pkcs11_random_data((void *)salt, sizeof (salt)); 813 if (rv != 0) { 814 cryptoerror(LOG_STDERR, 815 gettext("unable to generate random " 816 "data for key salt.")); 817 goto cleanup; 818 } 819 } 820 821 822 /* 823 * If key input is read from a file, treat it as 824 * raw key data, unless it is to be used with RC4, 825 * in which case it must be used to generate a pkcs5 826 * key to address security concerns with RC4 keys. 827 */ 828 if (kflag && keyfile != NULL && keytype != CKK_RC4) { 829 /* XXX : why wasn't SUNW_C_KeyToObject used here? */ 830 CK_OBJECT_CLASS objclass = CKO_SECRET_KEY; 831 CK_ATTRIBUTE template[5]; 832 int nattr = 0; 833 834 template[nattr].type = CKA_CLASS; 835 template[nattr].pValue = &objclass; 836 template[nattr].ulValueLen = sizeof (objclass); 837 nattr++; 838 839 template[nattr].type = CKA_KEY_TYPE; 840 template[nattr].pValue = &keytype; 841 template[nattr].ulValueLen = sizeof (keytype); 842 nattr++; 843 844 template[nattr].type = cmd->type; 845 template[nattr].pValue = &truevalue; 846 template[nattr].ulValueLen = sizeof (truevalue); 847 nattr++; 848 849 template[nattr].type = CKA_TOKEN; 850 template[nattr].pValue = &falsevalue; 851 template[nattr].ulValueLen = sizeof (falsevalue); 852 nattr++; 853 854 template[nattr].type = CKA_VALUE; 855 template[nattr].pValue = pkeydata; 856 template[nattr].ulValueLen = keysize; 857 nattr++; 858 859 rv = C_CreateObject(hSession, template, nattr, &key); 860 } else { 861 /* 862 * If the encryption type has a fixed key length, 863 * then its not necessary to set the key length 864 * parameter when generating the key. 865 */ 866 if (keytype == CKK_DES || keytype == CKK_DES3) 867 keylen = 0; 868 else 869 keylen = 16; 870 871 /* 872 * Generate a cryptographically secure key using 873 * the key read from the file given (-k keyfile) or 874 * the passphrase entered by the user. 875 */ 876 rv = pkcs11_PasswdToPBKD2Object(hSession, (char *)pkeydata, 877 (size_t)keysize, (void *)salt, sizeof (salt), iterations, 878 keytype, keylen, cmd->flags, &key); 879 } 880 881 if (rv != CKR_OK) { 882 cryptoerror(LOG_STDERR, gettext( 883 "failed to generate a key: %s"), 884 pkcs11_strerror(rv)); 885 goto cleanup; 886 } 887 888 889 do_crypto: 890 /* Setup up mechanism */ 891 mech.mechanism = mech_type; 892 mech.pParameter = (CK_VOID_PTR)pivbuf; 893 mech.ulParameterLen = ivlen; 894 895 if ((rv = cmd->Init(hSession, &mech, key)) != CKR_OK) { 896 cryptoerror(LOG_STDERR, gettext( 897 "failed to initialize crypto operation: %s"), 898 pkcs11_strerror(rv)); 899 goto cleanup; 900 } 901 902 /* Write the version header encrypt command */ 903 if (cmd->type == CKA_ENCRYPT) { 904 /* convert to network order for storage */ 905 uint32_t netversion = htonl(version); 906 uint32_t netiter; 907 908 if (write(outfd, &netversion, sizeof (netversion)) 909 != sizeof (netversion)) { 910 cryptoerror(LOG_STDERR, gettext( 911 "failed to write version number " 912 "to output file.")); 913 goto cleanup; 914 } 915 /* 916 * Write the iteration and salt data, even if they 917 * were not used to generate a key. 918 */ 919 netiter = htonl(iterations); 920 if (write(outfd, &netiter, 921 sizeof (netiter)) != sizeof (netiter)) { 922 cryptoerror(LOG_STDERR, gettext( 923 "failed to write iterations to output")); 924 goto cleanup; 925 } 926 if (ivlen > 0 && write(outfd, pivbuf, ivlen) != ivlen) { 927 cryptoerror(LOG_STDERR, gettext( 928 "failed to write initialization vector " 929 "to output")); 930 goto cleanup; 931 } 932 if (write(outfd, salt, sizeof (salt)) != sizeof (salt)) { 933 cryptoerror(LOG_STDERR, gettext( 934 "failed to write salt data to output")); 935 goto cleanup; 936 } 937 } 938 939 if (crypt_multipart(cmd, hSession, infd, outfd, insbuf.st_size) == -1) { 940 goto cleanup; 941 } 942 943 errflag = B_FALSE; 944 945 /* 946 * Clean up 947 */ 948 cleanup: 949 /* Clear the key data, so others cannot snoop */ 950 if (pkeydata != NULL) { 951 bzero(pkeydata, keysize); 952 free(pkeydata); 953 pkeydata = NULL; 954 } 955 956 /* Destroy key object */ 957 if (Kflag != B_FALSE && key != (CK_OBJECT_HANDLE) 0) { 958 (void) C_DestroyObject(hSession, key); 959 } 960 961 /* free allocated memory */ 962 if (pSlotList != NULL) 963 free(pSlotList); 964 if (pivbuf != NULL) 965 free(pivbuf); 966 967 /* close all the files */ 968 if (iflag && (infd != -1)) 969 (void) close(infd); 970 if (oflag && (outfd != -1)) 971 (void) close(outfd); 972 973 /* rename tmp output to input file */ 974 if (inoutsame) { 975 if (rename(outfilename, inputfile) == -1) { 976 (void) unlink(outfilename); 977 cryptoerror(LOG_STDERR, gettext("rename failed.")); 978 } 979 } 980 981 /* If error occurred, remove the output file */ 982 if (errflag && outfilename != NULL) { 983 (void) unlink(outfilename); 984 } 985 986 /* close pkcs11 session */ 987 if (hSession != CK_INVALID_HANDLE) 988 (void) C_CloseSession(hSession); 989 990 (void) C_Finalize(NULL); 991 992 return (errflag); 993 } 994 995 /* 996 * Function for printing progress bar when the verbose flag 997 * is set. 998 * 999 * The vertical bar is printed at 25, 50, and 75% complete. 1000 * 1001 * The function is passed the number of positions on the screen it needs to 1002 * advance and loops. 1003 */ 1004 1005 static void 1006 print_status(int pos_to_advance) 1007 { 1008 1009 while (pos_to_advance > 0) { 1010 switch (status_pos) { 1011 case 0: 1012 (void) fprintf(stderr, gettext("[")); 1013 break; 1014 case 19: 1015 case 39: 1016 case 59: 1017 (void) fprintf(stderr, gettext("|")); 1018 break; 1019 default: 1020 (void) fprintf(stderr, gettext(".")); 1021 } 1022 pos_to_advance--; 1023 status_pos++; 1024 } 1025 } 1026 1027 /* 1028 * Encrypt/Decrypt in multi part. 1029 * 1030 * This function reads the input file (infd) and writes the 1031 * encrypted/decrypted output to file (outfd). 1032 * 1033 * cmd - pointing to commandinfo 1034 * hSession - pkcs session 1035 * infd - input file descriptor 1036 * outfd - output file descriptor 1037 * 1038 */ 1039 1040 static int 1041 crypt_multipart(struct CommandInfo *cmd, CK_SESSION_HANDLE hSession, 1042 int infd, int outfd, off_t insize) 1043 { 1044 CK_RV rv; 1045 CK_ULONG resultlen; 1046 CK_ULONG resultbuflen; 1047 CK_BYTE_PTR resultbuf; 1048 CK_ULONG datalen; 1049 CK_BYTE databuf[BUFFERSIZE]; 1050 CK_BYTE outbuf[BUFFERSIZE+BLOCKSIZE]; 1051 CK_ULONG status_index = 0; /* current total file size read */ 1052 float status_last = 0.0; /* file size of last element used */ 1053 float status_incr = 0.0; /* file size element increments */ 1054 int pos; /* # of progress bar elements to be print */ 1055 ssize_t nread; 1056 boolean_t errflag = B_FALSE; 1057 1058 datalen = sizeof (databuf); 1059 resultbuflen = sizeof (outbuf); 1060 resultbuf = outbuf; 1061 1062 /* Divide into 79 increments for progress bar element spacing */ 1063 if (vflag && iflag) 1064 status_incr = (insize / 79.0); 1065 1066 while ((nread = read(infd, databuf, datalen)) > 0) { 1067 1068 /* Start with the initial buffer */ 1069 resultlen = resultbuflen; 1070 rv = cmd->Update(hSession, databuf, (CK_ULONG)nread, 1071 resultbuf, &resultlen); 1072 1073 /* Need a bigger buffer? */ 1074 if (rv == CKR_BUFFER_TOO_SMALL) { 1075 1076 /* free the old buffer */ 1077 if (resultbuf != NULL && resultbuf != outbuf) { 1078 bzero(resultbuf, resultbuflen); 1079 free(resultbuf); 1080 } 1081 1082 /* allocate a new big buffer */ 1083 if ((resultbuf = malloc((size_t)resultlen)) == NULL) { 1084 int err = errno; 1085 cryptoerror(LOG_STDERR, gettext("malloc: %s"), 1086 strerror(err)); 1087 return (-1); 1088 } 1089 resultbuflen = resultlen; 1090 1091 /* Try again with bigger buffer */ 1092 rv = cmd->Update(hSession, databuf, (CK_ULONG)nread, 1093 resultbuf, &resultlen); 1094 } 1095 1096 if (rv != CKR_OK) { 1097 errflag = B_TRUE; 1098 cryptoerror(LOG_STDERR, gettext( 1099 "crypto operation failed: %s"), 1100 pkcs11_strerror(rv)); 1101 break; 1102 } 1103 1104 /* write the output */ 1105 if (write(outfd, resultbuf, resultlen) != resultlen) { 1106 cryptoerror(LOG_STDERR, gettext( 1107 "failed to write result to output file.")); 1108 errflag = B_TRUE; 1109 break; 1110 } 1111 1112 if (vflag) { 1113 status_index += resultlen; 1114 1115 /* 1116 * If input is from stdin, do a our own progress bar 1117 * by printing periods at a pre-defined increment 1118 * until the file is done. 1119 */ 1120 if (!iflag) { 1121 1122 /* 1123 * Print at least 1 element in case the file 1124 * is small, it looks better than nothing. 1125 */ 1126 if (status_pos == 0) { 1127 (void) fprintf(stderr, gettext(".")); 1128 status_pos = 1; 1129 } 1130 1131 if ((status_index - status_last) > 1132 (PROGRESSSIZE)) { 1133 (void) fprintf(stderr, gettext(".")); 1134 status_last = status_index; 1135 } 1136 continue; 1137 } 1138 1139 /* Calculate the number of elements need to be print */ 1140 if (insize <= BUFFERSIZE) 1141 pos = 78; 1142 else 1143 pos = (int)((status_index - status_last) / 1144 status_incr); 1145 1146 /* Add progress bar elements, if needed */ 1147 if (pos > 0) { 1148 print_status(pos); 1149 status_last += (status_incr * pos); 1150 } 1151 } 1152 } 1153 1154 /* Print verbose completion */ 1155 if (vflag) { 1156 if (iflag) 1157 (void) fprintf(stderr, "]"); 1158 1159 (void) fprintf(stderr, "\n%s\n", gettext("Done.")); 1160 } 1161 1162 /* Error in reading */ 1163 if (nread == -1) { 1164 cryptoerror(LOG_STDERR, gettext( 1165 "error reading from input file")); 1166 errflag = B_TRUE; 1167 } 1168 1169 if (!errflag) { 1170 1171 /* Do the final part */ 1172 1173 rv = cmd->Final(hSession, resultbuf, &resultlen); 1174 1175 if (rv == CKR_OK) { 1176 /* write the output */ 1177 if (write(outfd, resultbuf, resultlen) != resultlen) { 1178 cryptoerror(LOG_STDERR, gettext( 1179 "failed to write result to output file.")); 1180 errflag = B_TRUE; 1181 } 1182 } else { 1183 cryptoerror(LOG_STDERR, gettext( 1184 "crypto operation failed: %s"), 1185 pkcs11_strerror(rv)); 1186 errflag = B_TRUE; 1187 } 1188 1189 } 1190 1191 if (resultbuf != NULL && resultbuf != outbuf) { 1192 bzero(resultbuf, resultbuflen); 1193 free(resultbuf); 1194 } 1195 1196 if (errflag) { 1197 return (-1); 1198 } else { 1199 return (0); 1200 } 1201 } 1202