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