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 */ 26 27 /* 28 * decrypt.c 29 * 30 * Implements encrypt(1) and decrypt(1) commands 31 * 32 * One binary performs both encrypt/decrypt operation. 33 * 34 * Usage: 35 * -a algorithm mechanism name without CKM_ prefix. Case 36 * does not matter 37 * -k keyfile file containing key data. If not specified user is 38 * prompted to enter key. key length > 0 is required 39 * -i infile input file to encrypt/decrypt. If omitted, stdin used. 40 * -o outfile output file to encrypt/decrypt. If omitted, stdout used. 41 * if infile & outfile are same, a temp file is used for 42 * output and infile is replaced with this file after 43 * operation is complete 44 * -l Display the list of algorithms 45 * -v Display verbose information 46 * -T tokenspec Specify a PKCS#11 token (optionally used with -K) 47 * -K keylabel Specify the symmetric PKCS#11 token key label 48 * 49 * Implementation notes: 50 * IV data - It is generated by random bytes equal to one block size. 51 * 52 * Encrypted output format - 53 * - Output format version number (1) - 4 bytes in network byte order. 54 * - Iterations used in key gen function, 4 bytes in network byte order. 55 * - IV ('ivlen' bytes). Length is algorithm-dependent (see mech_aliases) 56 * - Salt data used in key gen (16 bytes) 57 * - Cipher text data (remainder of the file) 58 */ 59 60 #include <stdio.h> 61 #include <stdlib.h> 62 #include <unistd.h> 63 #include <errno.h> 64 #include <fcntl.h> 65 #include <ctype.h> 66 #include <strings.h> 67 #include <libintl.h> 68 #include <libgen.h> 69 #include <locale.h> 70 #include <limits.h> 71 #include <sys/types.h> 72 #include <sys/stat.h> 73 #include <netinet/in.h> 74 #include <security/cryptoki.h> 75 #include <cryptoutil.h> 76 #include <kmfapi.h> 77 78 /* 79 * Buffer size for reading file. This is given a rather high value 80 * to get better performance when a hardware provider is present. 81 */ 82 #define BUFFERSIZE (1024 * 64) 83 #define BLOCKSIZE (128) /* Largest guess for block size */ 84 #define PROGRESSSIZE (1024 * 40) /* stdin progress indicator size */ 85 86 #define SUNW_ENCRYPT_FILE_VERSION 1 87 88 /* 89 * Exit Status codes 90 */ 91 #ifndef EXIT_SUCCESS 92 #define EXIT_SUCCESS 0 /* No errors */ 93 #define EXIT_FAILURE 1 /* All errors except usage */ 94 #endif /* EXIT_SUCCESS */ 95 96 #define EXIT_USAGE 2 /* usage/syntax error */ 97 98 #define ENCRYPT_NAME "encrypt" /* name of encrypt command */ 99 #define ENCRYPT_OPTIONS "a:T:K:k:i:o:lv" /* options for encrypt */ 100 #define DECRYPT_NAME "decrypt" /* name of decrypt command */ 101 #define DECRYPT_OPTIONS "a:T:K:k:i:o:lv" /* options for decrypt */ 102 103 /* 104 * Structure containing info for encrypt/decrypt 105 * command 106 */ 107 struct CommandInfo { 108 char *name; /* name of the command */ 109 char *options; /* command line options */ 110 CK_FLAGS flags; 111 CK_ATTRIBUTE_TYPE type; /* type of command */ 112 113 /* function pointers for various operations */ 114 CK_RV (*Init)(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE); 115 CK_RV (*Update)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, 116 CK_ULONG_PTR); 117 CK_RV (*Crypt)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, 118 CK_ULONG_PTR); 119 CK_RV (*Final)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR); 120 }; 121 122 static struct CommandInfo encrypt_cmd = { 123 ENCRYPT_NAME, 124 ENCRYPT_OPTIONS, 125 CKF_ENCRYPT, 126 CKA_ENCRYPT, 127 C_EncryptInit, 128 C_EncryptUpdate, 129 C_Encrypt, 130 C_EncryptFinal 131 }; 132 133 static struct CommandInfo decrypt_cmd = { 134 DECRYPT_NAME, 135 DECRYPT_OPTIONS, 136 CKF_DECRYPT, 137 CKA_DECRYPT, 138 C_DecryptInit, 139 C_DecryptUpdate, 140 C_Decrypt, 141 C_DecryptFinal 142 }; 143 144 struct mech_alias { 145 CK_MECHANISM_TYPE type; 146 char *alias; 147 CK_ULONG keysize_min; 148 CK_ULONG keysize_max; 149 int keysize_unit; 150 int ivlen; 151 boolean_t available; 152 }; 153 154 #define MECH_ALIASES_COUNT 4 155 156 static struct mech_alias mech_aliases[] = { 157 { CKM_AES_CBC_PAD, "aes", ULONG_MAX, 0L, 8, 16, B_FALSE }, 158 { CKM_RC4, "arcfour", ULONG_MAX, 0L, 1, 0, B_FALSE }, 159 { CKM_DES_CBC_PAD, "des", 8, 8, 8, 8, B_FALSE }, 160 { CKM_DES3_CBC_PAD, "3des", 24, 24, 8, 8, B_FALSE }, 161 }; 162 163 static CK_BBOOL truevalue = TRUE; 164 static CK_BBOOL falsevalue = FALSE; 165 166 static boolean_t aflag = B_FALSE; /* -a <algorithm> flag, required */ 167 static boolean_t kflag = B_FALSE; /* -k <keyfile> flag */ 168 static boolean_t iflag = B_FALSE; /* -i <infile> flag, use stdin if absent */ 169 static boolean_t oflag = B_FALSE; /* -o <outfile> flag, use stdout if absent */ 170 static boolean_t lflag = B_FALSE; /* -l flag (list) */ 171 static boolean_t vflag = B_FALSE; /* -v flag (verbose) */ 172 static boolean_t Tflag = B_FALSE; /* -T flag (tokenspec) */ 173 static boolean_t Kflag = B_FALSE; /* -K flag (keylabel) */ 174 175 static char *keyfile = NULL; /* name of keyfile */ 176 static char *inputfile = NULL; /* name of input file */ 177 static char *outputfile = NULL; /* name of output file */ 178 static char *token_label = NULL; /* name of PKCS#11 token */ 179 static char *key_label = NULL; /* name of PKCS#11 token key label */ 180 181 static int status_pos = 0; /* current position of progress bar element */ 182 183 /* 184 * function prototypes 185 */ 186 static void usage(struct CommandInfo *cmd); 187 static int execute_cmd(struct CommandInfo *cmd, char *algo_str); 188 static int crypt_multipart(struct CommandInfo *cmd, CK_SESSION_HANDLE hSession, 189 int infd, int outfd, off_t insize); 190 191 int 192 main(int argc, char **argv) 193 { 194 195 extern char *optarg; 196 extern int optind; 197 char *optstr; 198 char c; /* current getopts flag */ 199 char *algo_str = NULL; /* algorithm string */ 200 struct CommandInfo *cmd; 201 char *cmdname; /* name of command */ 202 boolean_t errflag = B_FALSE; 203 204 (void) setlocale(LC_ALL, ""); 205 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 206 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 207 #endif 208 (void) textdomain(TEXT_DOMAIN); 209 210 /* 211 * Based on command name, determine 212 * type of command. 213 */ 214 cmdname = basename(argv[0]); 215 216 cryptodebug_init(cmdname); 217 218 if (strcmp(cmdname, encrypt_cmd.name) == 0) { 219 cmd = &encrypt_cmd; 220 } else if (strcmp(cmdname, decrypt_cmd.name) == 0) { 221 cmd = &decrypt_cmd; 222 } else { 223 cryptoerror(LOG_STDERR, gettext( 224 "command name must be either encrypt or decrypt")); 225 exit(EXIT_USAGE); 226 } 227 228 optstr = cmd->options; 229 230 /* Parse command line arguments */ 231 while (!errflag && (c = getopt(argc, argv, optstr)) != -1) { 232 233 switch (c) { 234 case 'a': 235 aflag = B_TRUE; 236 algo_str = optarg; 237 break; 238 case 'k': 239 kflag = B_TRUE; 240 keyfile = optarg; 241 break; 242 case 'T': 243 Tflag = B_TRUE; 244 token_label = optarg; 245 break; 246 case 'K': 247 Kflag = B_TRUE; 248 key_label = optarg; 249 break; 250 case 'i': 251 iflag = B_TRUE; 252 inputfile = optarg; 253 break; 254 case 'o': 255 oflag = B_TRUE; 256 outputfile = optarg; 257 break; 258 case 'l': 259 lflag = B_TRUE; 260 break; 261 case 'v': 262 vflag = B_TRUE; 263 break; 264 default: 265 errflag = B_TRUE; 266 } 267 } 268 269 if (errflag || (!aflag && !lflag) || (lflag && argc > 2) || 270 (kflag && Kflag) || (Tflag && !Kflag) || 271 (optind < argc)) { 272 usage(cmd); 273 exit(EXIT_USAGE); 274 } 275 276 return (execute_cmd(cmd, algo_str)); 277 } 278 279 /* 280 * usage message 281 */ 282 static void 283 usage(struct CommandInfo *cmd) 284 { 285 (void) fprintf(stderr, gettext("Usage:\n")); 286 if (cmd->type == CKA_ENCRYPT) { 287 (void) fprintf(stderr, gettext(" encrypt -l\n")); 288 (void) fprintf(stderr, gettext(" encrypt -a <algorithm> " 289 "[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] " 290 "[-i <infile>] [-o <outfile>]\n")); 291 292 } else { 293 (void) fprintf(stderr, gettext(" decrypt -l\n")); 294 (void) fprintf(stderr, gettext(" decrypt -a <algorithm> " 295 "[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] " 296 "[-i <infile>] [-o <outfile>]\n")); 297 } 298 } 299 300 /* 301 * Print out list of algorithms in default and verbose mode 302 */ 303 static void 304 algorithm_list() 305 { 306 int mech; 307 308 (void) printf(gettext("Algorithm Keysize: Min Max (bits)\n" 309 "------------------------------------------\n")); 310 311 for (mech = 0; mech < MECH_ALIASES_COUNT; mech++) { 312 313 if (mech_aliases[mech].available == B_FALSE) 314 continue; 315 316 (void) printf("%-15s", mech_aliases[mech].alias); 317 318 if (mech_aliases[mech].keysize_min != UINT_MAX && 319 mech_aliases[mech].keysize_max != 0) 320 (void) printf(" %5lu %5lu\n", 321 (mech_aliases[mech].keysize_min * 322 mech_aliases[mech].keysize_unit), 323 (mech_aliases[mech].keysize_max * 324 mech_aliases[mech].keysize_unit)); 325 else 326 (void) printf("\n"); 327 328 } 329 } 330 331 /* 332 * This function will login into the token with the provided password and 333 * find the token key object with the specified keytype and keylabel. 334 */ 335 static int 336 get_token_key(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keytype, 337 char *keylabel, CK_BYTE *password, int password_len, 338 CK_OBJECT_HANDLE *keyobj) 339 { 340 CK_RV rv; 341 CK_ATTRIBUTE pTmpl[10]; 342 CK_OBJECT_CLASS class = CKO_SECRET_KEY; 343 CK_BBOOL true = 1; 344 CK_BBOOL is_token = 1; 345 CK_ULONG key_obj_count = 1; 346 int i; 347 CK_KEY_TYPE ckKeyType = keytype; 348 349 350 rv = C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)password, 351 (CK_ULONG)password_len); 352 if (rv != CKR_OK) { 353 (void) fprintf(stderr, "Cannot login to the token." 354 " error = %s\n", pkcs11_strerror(rv)); 355 return (-1); 356 } 357 358 i = 0; 359 pTmpl[i].type = CKA_TOKEN; 360 pTmpl[i].pValue = &is_token; 361 pTmpl[i].ulValueLen = sizeof (CK_BBOOL); 362 i++; 363 364 pTmpl[i].type = CKA_CLASS; 365 pTmpl[i].pValue = &class; 366 pTmpl[i].ulValueLen = sizeof (class); 367 i++; 368 369 pTmpl[i].type = CKA_LABEL; 370 pTmpl[i].pValue = keylabel; 371 pTmpl[i].ulValueLen = strlen(keylabel); 372 i++; 373 374 pTmpl[i].type = CKA_KEY_TYPE; 375 pTmpl[i].pValue = &ckKeyType; 376 pTmpl[i].ulValueLen = sizeof (ckKeyType); 377 i++; 378 379 pTmpl[i].type = CKA_PRIVATE; 380 pTmpl[i].pValue = &true; 381 pTmpl[i].ulValueLen = sizeof (true); 382 i++; 383 384 rv = C_FindObjectsInit(hSession, pTmpl, i); 385 if (rv != CKR_OK) { 386 goto out; 387 } 388 389 rv = C_FindObjects(hSession, keyobj, 1, &key_obj_count); 390 391 (void) C_FindObjectsFinal(hSession); 392 393 out: 394 if (rv != CKR_OK) { 395 (void) fprintf(stderr, 396 "Cannot retrieve key object. error = %s\n", 397 pkcs11_strerror(rv)); 398 return (-1); 399 } 400 401 if (key_obj_count == 0) { 402 (void) fprintf(stderr, "Cannot find the key object.\n"); 403 return (-1); 404 } 405 406 return (0); 407 } 408 409 410 /* 411 * Execute the command. 412 * cmd - command pointing to type of operation. 413 * algo_str - alias of the algorithm passed. 414 */ 415 static int 416 execute_cmd(struct CommandInfo *cmd, char *algo_str) 417 { 418 CK_RV rv; 419 CK_ULONG slotcount; 420 CK_SLOT_ID slotID; 421 CK_SLOT_ID_PTR pSlotList = NULL; 422 CK_MECHANISM_TYPE mech_type = 0; 423 CK_MECHANISM_INFO info, kg_info; 424 CK_MECHANISM mech; 425 CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; 426 CK_BYTE_PTR pkeydata = NULL; 427 CK_BYTE salt[CK_PKCS5_PBKD2_SALT_SIZE]; 428 CK_ULONG keysize = 0; 429 int i, slot, mek; /* index variables */ 430 int status; 431 struct stat insbuf; /* stat buf for infile */ 432 struct stat outsbuf; /* stat buf for outfile */ 433 char tmpnam[PATH_MAX]; /* tmp file name */ 434 CK_OBJECT_HANDLE key = (CK_OBJECT_HANDLE) 0; 435 int infd = 0; /* input file, stdin default */ 436 int outfd = 1; /* output file, stdout default */ 437 char *outfilename = NULL; 438 boolean_t errflag = B_TRUE; 439 boolean_t inoutsame = B_FALSE; /* if both input & output are same */ 440 boolean_t leavefilealone = B_FALSE; 441 CK_BYTE_PTR pivbuf = NULL_PTR; 442 CK_ULONG ivlen = 0L; 443 int mech_match = 0; 444 uint32_t iterations = CK_PKCS5_PBKD2_ITERATIONS; 445 CK_ULONG keylen; 446 uint32_t version = SUNW_ENCRYPT_FILE_VERSION; 447 CK_KEY_TYPE keytype; 448 KMF_RETURN kmfrv; 449 CK_SLOT_ID token_slot_id; 450 451 if (aflag) { 452 /* Determine if algorithm is valid */ 453 for (mech_match = 0; mech_match < MECH_ALIASES_COUNT; 454 mech_match++) { 455 if (strcmp(algo_str, 456 mech_aliases[mech_match].alias) == 0) { 457 mech_type = mech_aliases[mech_match].type; 458 break; 459 } 460 } 461 462 if (mech_match == MECH_ALIASES_COUNT) { 463 cryptoerror(LOG_STDERR, 464 gettext("unknown algorithm -- %s"), algo_str); 465 return (EXIT_FAILURE); 466 } 467 468 /* 469 * Process keyfile or get the token pin if -K is specified. 470 * 471 * If a keyfile is provided, get the key data from 472 * the file. Otherwise, prompt for a passphrase. The 473 * passphrase is used as the key data. 474 */ 475 if (Kflag) { 476 /* get the pin of the token */ 477 if (token_label == NULL || !strlen(token_label)) { 478 token_label = pkcs11_default_token(); 479 } 480 481 status = pkcs11_get_pass(token_label, 482 (char **)&pkeydata, (size_t *)&keysize, 0, B_FALSE); 483 } else if (kflag) { 484 /* get the key file */ 485 status = pkcs11_read_data(keyfile, (void **)&pkeydata, 486 (size_t *)&keysize); 487 } else { 488 /* get the key from input */ 489 status = pkcs11_get_pass(NULL, (char **)&pkeydata, 490 (size_t *)&keysize, 0, 491 (cmd->type == CKA_ENCRYPT) ? B_TRUE : B_FALSE); 492 } 493 494 if (status != 0 || keysize == 0L) { 495 cryptoerror(LOG_STDERR, 496 kflag ? gettext("invalid key.") : 497 gettext("invalid passphrase.")); 498 return (EXIT_FAILURE); 499 } 500 } 501 502 bzero(salt, sizeof (salt)); 503 /* Initialize pkcs */ 504 rv = C_Initialize(NULL); 505 if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { 506 cryptoerror(LOG_STDERR, gettext("failed to initialize " 507 "PKCS #11 framework: %s"), pkcs11_strerror(rv)); 508 goto cleanup; 509 } 510 511 /* Get slot count */ 512 rv = C_GetSlotList(0, NULL_PTR, &slotcount); 513 if (rv != CKR_OK || slotcount == 0) { 514 cryptoerror(LOG_STDERR, gettext( 515 "failed to find any cryptographic provider," 516 "please check with your system administrator: %s"), 517 pkcs11_strerror(rv)); 518 goto cleanup; 519 } 520 521 /* Found at least one slot, allocate memory for slot list */ 522 pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID)); 523 if (pSlotList == NULL_PTR) { 524 int err = errno; 525 cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(err)); 526 goto cleanup; 527 } 528 529 /* Get the list of slots */ 530 if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) { 531 cryptoerror(LOG_STDERR, gettext( 532 "failed to find any cryptographic provider," 533 "please check with your system administrator: %s"), 534 pkcs11_strerror(rv)); 535 goto cleanup; 536 } 537 538 if (lflag) { 539 540 /* Iterate through slots */ 541 for (slot = 0; slot < slotcount; slot++) { 542 543 /* Iterate through each mechanism */ 544 for (mek = 0; mek < MECH_ALIASES_COUNT; mek++) { 545 rv = C_GetMechanismInfo(pSlotList[slot], 546 mech_aliases[mek].type, &info); 547 548 if (rv != CKR_OK) 549 continue; 550 551 /* 552 * Set to minimum/maximum key sizes assuming 553 * the values available are not 0. 554 */ 555 if (info.ulMinKeySize && (info.ulMinKeySize < 556 mech_aliases[mek].keysize_min)) 557 mech_aliases[mek].keysize_min = 558 info.ulMinKeySize; 559 560 if (info.ulMaxKeySize && (info.ulMaxKeySize > 561 mech_aliases[mek].keysize_max)) 562 mech_aliases[mek].keysize_max = 563 info.ulMaxKeySize; 564 565 mech_aliases[mek].available = B_TRUE; 566 } 567 568 } 569 570 algorithm_list(); 571 572 errflag = B_FALSE; 573 goto cleanup; 574 } 575 576 577 /* 578 * Find a slot with matching mechanism 579 * 580 * If -K is specified, we find the slot id for the token first, then 581 * check if the slot supports the algorithm. 582 */ 583 i = 0; 584 if (Kflag) { 585 kmfrv = kmf_pk11_token_lookup(NULL, token_label, 586 &token_slot_id); 587 if (kmfrv != KMF_OK) { 588 cryptoerror(LOG_STDERR, 589 gettext("no matching PKCS#11 token")); 590 errflag = B_TRUE; 591 goto cleanup; 592 } 593 rv = C_GetMechanismInfo(token_slot_id, mech_type, &info); 594 if (rv == CKR_OK && (info.flags & cmd->flags)) 595 slotID = token_slot_id; 596 else 597 i = slotcount; 598 } else { 599 for (i = 0; i < slotcount; i++) { 600 slotID = pSlotList[i]; 601 rv = C_GetMechanismInfo(slotID, mech_type, &info); 602 if (rv != CKR_OK) { 603 continue; /* to the next slot */ 604 } else { 605 /* 606 * If the slot support the crypto, also 607 * make sure it supports the correct 608 * key generation mech if needed. 609 * 610 * We need PKCS5 when RC4 is used or 611 * when the key is entered on cmd line. 612 */ 613 if ((info.flags & cmd->flags) && 614 (mech_type == CKM_RC4) || 615 (keyfile == NULL)) { 616 rv = C_GetMechanismInfo(slotID, 617 CKM_PKCS5_PBKD2, &kg_info); 618 if (rv == CKR_OK) 619 break; 620 } else if (info.flags & cmd->flags) { 621 break; 622 } 623 } 624 } 625 } 626 627 /* Show error if no matching mechanism found */ 628 if (i == slotcount) { 629 cryptoerror(LOG_STDERR, 630 gettext("no cryptographic provider was " 631 "found for this algorithm -- %s"), algo_str); 632 goto cleanup; 633 } 634 635 /* Open a session */ 636 rv = C_OpenSession(slotID, CKF_SERIAL_SESSION, 637 NULL_PTR, NULL, &hSession); 638 639 if (rv != CKR_OK) { 640 cryptoerror(LOG_STDERR, 641 gettext("can not open PKCS #11 session: %s"), 642 pkcs11_strerror(rv)); 643 goto cleanup; 644 } 645 646 /* 647 * Generate IV data for encrypt. 648 */ 649 ivlen = mech_aliases[mech_match].ivlen; 650 if ((pivbuf = malloc((size_t)ivlen)) == NULL) { 651 int err = errno; 652 cryptoerror(LOG_STDERR, gettext("malloc: %s"), 653 strerror(err)); 654 goto cleanup; 655 } 656 657 if (cmd->type == CKA_ENCRYPT) { 658 if ((pkcs11_get_urandom((void *)pivbuf, 659 mech_aliases[mech_match].ivlen)) != 0) { 660 cryptoerror(LOG_STDERR, gettext( 661 "Unable to generate random " 662 "data for initialization vector.")); 663 goto cleanup; 664 } 665 } 666 667 /* 668 * Create the key object 669 */ 670 rv = pkcs11_mech2keytype(mech_type, &keytype); 671 if (rv != CKR_OK) { 672 cryptoerror(LOG_STDERR, 673 gettext("unable to find key type for algorithm.")); 674 goto cleanup; 675 } 676 677 /* Open input file */ 678 if (iflag) { 679 if ((infd = open(inputfile, O_RDONLY | O_NONBLOCK)) == -1) { 680 cryptoerror(LOG_STDERR, gettext( 681 "can not open input file %s"), inputfile); 682 goto cleanup; 683 } 684 685 /* Get info on input file */ 686 if (fstat(infd, &insbuf) == -1) { 687 cryptoerror(LOG_STDERR, gettext( 688 "can not stat input file %s"), inputfile); 689 goto cleanup; 690 } 691 } 692 693 /* 694 * Prepare output file 695 * If the input & output file are same, 696 * the output is written to a temp 697 * file first, then renamed to the original file 698 * after the crypt operation 699 */ 700 inoutsame = B_FALSE; 701 if (oflag) { 702 outfilename = outputfile; 703 if ((stat(outputfile, &outsbuf) != -1) && 704 (insbuf.st_ino == outsbuf.st_ino)) { 705 char *dir; 706 707 /* create temp file on same dir */ 708 dir = dirname(outputfile); 709 (void) snprintf(tmpnam, sizeof (tmpnam), 710 "%s/encrXXXXXX", dir); 711 outfilename = tmpnam; 712 if ((outfd = mkstemp(tmpnam)) == -1) { 713 cryptoerror(LOG_STDERR, gettext( 714 "cannot create temp file")); 715 goto cleanup; 716 } 717 inoutsame = B_TRUE; 718 } else { 719 /* Create file for output */ 720 if ((outfd = open(outfilename, 721 O_CREAT|O_WRONLY|O_TRUNC, 0644)) == -1) { 722 cryptoerror(LOG_STDERR, gettext( 723 "cannot open output file %s"), 724 outfilename); 725 /* Cannot open file, should leave it alone */ 726 leavefilealone = B_TRUE; 727 goto cleanup; 728 } 729 } 730 } 731 732 /* 733 * Read the version number from the head of the file 734 * to know how to interpret the data that follows. 735 */ 736 if (cmd->type == CKA_DECRYPT) { 737 if (read(infd, &version, sizeof (version)) != 738 sizeof (version)) { 739 cryptoerror(LOG_STDERR, gettext( 740 "failed to get format version from " 741 "input file.")); 742 goto cleanup; 743 } 744 /* convert to host byte order */ 745 version = ntohl(version); 746 747 switch (version) { 748 case 1: 749 /* 750 * Version 1 output format: 751 * - Output format version 1 (4 bytes) 752 * - Iterations used in key gen function (4 bytes) 753 * - IV ('ivlen' bytes). The length algorithm-dependent 754 * - Salt data used in key gen (16 bytes) 755 * - Cipher text data (remainder of the file) 756 * 757 * An encrypted file has IV as first block (0 or 758 * more bytes depending on mechanism) followed 759 * by cipher text. Get the IV from the encrypted 760 * file. 761 */ 762 /* 763 * Read iteration count and salt data. 764 */ 765 if (read(infd, &iterations, 766 sizeof (iterations)) != sizeof (iterations)) { 767 cryptoerror(LOG_STDERR, gettext( 768 "failed to get iterations from " 769 "input file.")); 770 goto cleanup; 771 } 772 /* convert to host byte order */ 773 iterations = ntohl(iterations); 774 if (ivlen > 0 && 775 read(infd, pivbuf, ivlen) != ivlen) { 776 cryptoerror(LOG_STDERR, gettext( 777 "failed to get initialization " 778 "vector from input file.")); 779 goto cleanup; 780 } 781 if (read(infd, salt, sizeof (salt)) 782 != sizeof (salt)) { 783 cryptoerror(LOG_STDERR, gettext( 784 "failed to get salt data from " 785 "input file.")); 786 goto cleanup; 787 } 788 break; 789 default: 790 cryptoerror(LOG_STDERR, gettext( 791 "Unrecognized format version read from " 792 "input file - expected %d, got %d."), 793 SUNW_ENCRYPT_FILE_VERSION, version); 794 goto cleanup; 795 break; 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