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 #define BUFFERSIZE (2048) /* Buffer size for reading file */ 79 #define BLOCKSIZE (128) /* Largest guess for block size */ 80 #define PROGRESSSIZE (BUFFERSIZE*20) /* stdin progress indicator size */ 81 82 #define SUNW_ENCRYPT_FILE_VERSION 1 83 84 /* 85 * Exit Status codes 86 */ 87 #ifndef EXIT_SUCCESS 88 #define EXIT_SUCCESS 0 /* No errors */ 89 #define EXIT_FAILURE 1 /* All errors except usage */ 90 #endif /* EXIT_SUCCESS */ 91 92 #define EXIT_USAGE 2 /* usage/syntax error */ 93 94 #define ENCRYPT_NAME "encrypt" /* name of encrypt command */ 95 #define ENCRYPT_OPTIONS "a:T:K:k:i:o:lv" /* options for encrypt */ 96 #define DECRYPT_NAME "decrypt" /* name of decrypt command */ 97 #define DECRYPT_OPTIONS "a:T:K:k:i:o:lv" /* options for decrypt */ 98 99 /* 100 * Structure containing info for encrypt/decrypt 101 * command 102 */ 103 struct CommandInfo { 104 char *name; /* name of the command */ 105 char *options; /* command line options */ 106 CK_FLAGS flags; 107 CK_ATTRIBUTE_TYPE type; /* type of command */ 108 109 /* function pointers for various operations */ 110 CK_RV (*Init)(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE); 111 CK_RV (*Update)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, 112 CK_ULONG_PTR); 113 CK_RV (*Crypt)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, 114 CK_ULONG_PTR); 115 CK_RV (*Final)(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR); 116 }; 117 118 static struct CommandInfo encrypt_cmd = { 119 ENCRYPT_NAME, 120 ENCRYPT_OPTIONS, 121 CKF_ENCRYPT, 122 CKA_ENCRYPT, 123 C_EncryptInit, 124 C_EncryptUpdate, 125 C_Encrypt, 126 C_EncryptFinal 127 }; 128 129 static struct CommandInfo decrypt_cmd = { 130 DECRYPT_NAME, 131 DECRYPT_OPTIONS, 132 CKF_DECRYPT, 133 CKA_DECRYPT, 134 C_DecryptInit, 135 C_DecryptUpdate, 136 C_Decrypt, 137 C_DecryptFinal 138 }; 139 140 struct mech_alias { 141 CK_MECHANISM_TYPE type; 142 char *alias; 143 CK_ULONG keysize_min; 144 CK_ULONG keysize_max; 145 int keysize_unit; 146 int ivlen; 147 boolean_t available; 148 }; 149 150 #define MECH_ALIASES_COUNT 4 151 152 static struct mech_alias mech_aliases[] = { 153 { CKM_AES_CBC_PAD, "aes", ULONG_MAX, 0L, 8, 16, B_FALSE }, 154 { CKM_RC4, "arcfour", ULONG_MAX, 0L, 1, 0, B_FALSE }, 155 { CKM_DES_CBC_PAD, "des", 8, 8, 8, 8, B_FALSE }, 156 { CKM_DES3_CBC_PAD, "3des", 24, 24, 8, 8, B_FALSE }, 157 }; 158 159 static CK_BBOOL truevalue = TRUE; 160 static CK_BBOOL falsevalue = FALSE; 161 162 static boolean_t aflag = B_FALSE; /* -a <algorithm> flag, required */ 163 static boolean_t kflag = B_FALSE; /* -k <keyfile> flag */ 164 static boolean_t iflag = B_FALSE; /* -i <infile> flag, use stdin if absent */ 165 static boolean_t oflag = B_FALSE; /* -o <outfile> flag, use stdout if absent */ 166 static boolean_t lflag = B_FALSE; /* -l flag (list) */ 167 static boolean_t vflag = B_FALSE; /* -v flag (verbose) */ 168 static boolean_t Tflag = B_FALSE; /* -T flag (tokenspec) */ 169 static boolean_t Kflag = B_FALSE; /* -K flag (keylabel) */ 170 171 static char *keyfile = NULL; /* name of keyfile */ 172 static char *inputfile = NULL; /* name of input file */ 173 static char *outputfile = NULL; /* name of output file */ 174 static char *token_label = NULL; /* name of PKCS#11 token */ 175 static char *key_label = NULL; /* name of PKCS#11 token key label */ 176 177 static int status_pos = 0; /* current position of progress bar element */ 178 179 /* 180 * function prototypes 181 */ 182 static void usage(struct CommandInfo *cmd); 183 static int execute_cmd(struct CommandInfo *cmd, char *algo_str); 184 static int crypt_multipart(struct CommandInfo *cmd, CK_SESSION_HANDLE hSession, 185 int infd, int outfd, off_t insize); 186 187 int 188 main(int argc, char **argv) 189 { 190 191 extern char *optarg; 192 extern int optind; 193 char *optstr; 194 char c; /* current getopts flag */ 195 char *algo_str = NULL; /* algorithm string */ 196 struct CommandInfo *cmd; 197 char *cmdname; /* name of command */ 198 boolean_t errflag = B_FALSE; 199 200 (void) setlocale(LC_ALL, ""); 201 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 202 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 203 #endif 204 (void) textdomain(TEXT_DOMAIN); 205 206 /* 207 * Based on command name, determine 208 * type of command. 209 */ 210 cmdname = basename(argv[0]); 211 212 cryptodebug_init(cmdname); 213 214 if (strcmp(cmdname, encrypt_cmd.name) == 0) { 215 cmd = &encrypt_cmd; 216 } else if (strcmp(cmdname, decrypt_cmd.name) == 0) { 217 cmd = &decrypt_cmd; 218 } else { 219 cryptoerror(LOG_STDERR, gettext( 220 "command name must be either encrypt or decrypt")); 221 exit(EXIT_USAGE); 222 } 223 224 optstr = cmd->options; 225 226 /* Parse command line arguments */ 227 while (!errflag && (c = getopt(argc, argv, optstr)) != -1) { 228 229 switch (c) { 230 case 'a': 231 aflag = B_TRUE; 232 algo_str = optarg; 233 break; 234 case 'k': 235 kflag = B_TRUE; 236 keyfile = optarg; 237 break; 238 case 'T': 239 Tflag = B_TRUE; 240 token_label = optarg; 241 break; 242 case 'K': 243 Kflag = B_TRUE; 244 key_label = optarg; 245 break; 246 case 'i': 247 iflag = B_TRUE; 248 inputfile = optarg; 249 break; 250 case 'o': 251 oflag = B_TRUE; 252 outputfile = optarg; 253 break; 254 case 'l': 255 lflag = B_TRUE; 256 break; 257 case 'v': 258 vflag = B_TRUE; 259 break; 260 default: 261 errflag = B_TRUE; 262 } 263 } 264 265 if (errflag || (!aflag && !lflag) || (lflag && argc > 2) || 266 (kflag && Kflag) || (Tflag && !Kflag) || 267 (optind < argc)) { 268 usage(cmd); 269 exit(EXIT_USAGE); 270 } 271 272 return (execute_cmd(cmd, algo_str)); 273 } 274 275 /* 276 * usage message 277 */ 278 static void 279 usage(struct CommandInfo *cmd) 280 { 281 (void) fprintf(stderr, gettext("Usage:\n")); 282 if (cmd->type == CKA_ENCRYPT) { 283 (void) fprintf(stderr, gettext(" encrypt -l\n")); 284 (void) fprintf(stderr, gettext(" encrypt -a <algorithm> " 285 "[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] " 286 "[-i <infile>] [-o <outfile>]\n")); 287 288 } else { 289 (void) fprintf(stderr, gettext(" decrypt -l\n")); 290 (void) fprintf(stderr, gettext(" decrypt -a <algorithm> " 291 "[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] " 292 "[-i <infile>] [-o <outfile>]\n")); 293 } 294 } 295 296 /* 297 * Print out list of algorithms in default and verbose mode 298 */ 299 static void 300 algorithm_list() 301 { 302 int mech; 303 304 (void) printf(gettext("Algorithm Keysize: Min Max (bits)\n" 305 "------------------------------------------\n")); 306 307 for (mech = 0; mech < MECH_ALIASES_COUNT; mech++) { 308 309 if (mech_aliases[mech].available == B_FALSE) 310 continue; 311 312 (void) printf("%-15s", mech_aliases[mech].alias); 313 314 if (mech_aliases[mech].keysize_min != UINT_MAX && 315 mech_aliases[mech].keysize_max != 0) 316 (void) printf(" %5lu %5lu\n", 317 (mech_aliases[mech].keysize_min * 318 mech_aliases[mech].keysize_unit), 319 (mech_aliases[mech].keysize_max * 320 mech_aliases[mech].keysize_unit)); 321 else 322 (void) printf("\n"); 323 324 } 325 } 326 327 /* 328 * This function will login into the token with the provided password and 329 * find the token key object with the specified keytype and keylabel. 330 */ 331 static int 332 get_token_key(CK_SESSION_HANDLE hSession, CK_KEY_TYPE keytype, 333 char *keylabel, CK_BYTE *password, int password_len, 334 CK_OBJECT_HANDLE *keyobj) 335 { 336 CK_RV rv; 337 CK_ATTRIBUTE pTmpl[10]; 338 CK_OBJECT_CLASS class = CKO_SECRET_KEY; 339 CK_BBOOL true = 1; 340 CK_BBOOL is_token = 1; 341 CK_ULONG key_obj_count = 1; 342 int i; 343 CK_KEY_TYPE ckKeyType = keytype; 344 345 346 rv = C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)password, 347 (CK_ULONG)password_len); 348 if (rv != CKR_OK) { 349 (void) fprintf(stderr, "Cannot login to the token." 350 " error = %s\n", pkcs11_strerror(rv)); 351 return (-1); 352 } 353 354 i = 0; 355 pTmpl[i].type = CKA_TOKEN; 356 pTmpl[i].pValue = &is_token; 357 pTmpl[i].ulValueLen = sizeof (CK_BBOOL); 358 i++; 359 360 pTmpl[i].type = CKA_CLASS; 361 pTmpl[i].pValue = &class; 362 pTmpl[i].ulValueLen = sizeof (class); 363 i++; 364 365 pTmpl[i].type = CKA_LABEL; 366 pTmpl[i].pValue = keylabel; 367 pTmpl[i].ulValueLen = strlen(keylabel); 368 i++; 369 370 pTmpl[i].type = CKA_KEY_TYPE; 371 pTmpl[i].pValue = &ckKeyType; 372 pTmpl[i].ulValueLen = sizeof (ckKeyType); 373 i++; 374 375 pTmpl[i].type = CKA_PRIVATE; 376 pTmpl[i].pValue = &true; 377 pTmpl[i].ulValueLen = sizeof (true); 378 i++; 379 380 rv = C_FindObjectsInit(hSession, pTmpl, i); 381 if (rv != CKR_OK) { 382 goto out; 383 } 384 385 rv = C_FindObjects(hSession, keyobj, 1, &key_obj_count); 386 387 (void) C_FindObjectsFinal(hSession); 388 389 out: 390 if (rv != CKR_OK) { 391 (void) fprintf(stderr, 392 "Cannot retrieve key object. error = %s\n", 393 pkcs11_strerror(rv)); 394 return (-1); 395 } 396 397 if (key_obj_count == 0) { 398 (void) fprintf(stderr, "Cannot find the key object.\n"); 399 return (-1); 400 } 401 402 return (0); 403 } 404 405 406 /* 407 * Execute the command. 408 * cmd - command pointing to type of operation. 409 * algo_str - alias of the algorithm passed. 410 */ 411 static int 412 execute_cmd(struct CommandInfo *cmd, char *algo_str) 413 { 414 CK_RV rv; 415 CK_ULONG slotcount; 416 CK_SLOT_ID slotID; 417 CK_SLOT_ID_PTR pSlotList = NULL; 418 CK_MECHANISM_TYPE mech_type = 0; 419 CK_MECHANISM_INFO info, kg_info; 420 CK_MECHANISM mech; 421 CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; 422 CK_BYTE_PTR pkeydata = NULL; 423 CK_BYTE salt[CK_PKCS5_PBKD2_SALT_SIZE]; 424 CK_ULONG keysize = 0; 425 int i, slot, mek; /* index variables */ 426 int status; 427 struct stat insbuf; /* stat buf for infile */ 428 struct stat outsbuf; /* stat buf for outfile */ 429 char tmpnam[PATH_MAX]; /* tmp file name */ 430 CK_OBJECT_HANDLE key = (CK_OBJECT_HANDLE) 0; 431 int infd = 0; /* input file, stdin default */ 432 int outfd = 1; /* output file, stdout default */ 433 char *outfilename = NULL; 434 boolean_t errflag = B_TRUE; 435 boolean_t inoutsame = B_FALSE; /* if both input & output are same */ 436 boolean_t leavefilealone = B_FALSE; 437 CK_BYTE_PTR pivbuf = NULL_PTR; 438 CK_ULONG ivlen = 0L; 439 int mech_match = 0; 440 uint32_t iterations = CK_PKCS5_PBKD2_ITERATIONS; 441 CK_ULONG keylen; 442 uint32_t version = SUNW_ENCRYPT_FILE_VERSION; 443 CK_KEY_TYPE keytype; 444 KMF_RETURN kmfrv; 445 CK_SLOT_ID token_slot_id; 446 447 if (aflag) { 448 /* Determine if algorithm is valid */ 449 for (mech_match = 0; mech_match < MECH_ALIASES_COUNT; 450 mech_match++) { 451 if (strcmp(algo_str, 452 mech_aliases[mech_match].alias) == 0) { 453 mech_type = mech_aliases[mech_match].type; 454 break; 455 } 456 } 457 458 if (mech_match == MECH_ALIASES_COUNT) { 459 cryptoerror(LOG_STDERR, 460 gettext("unknown algorithm -- %s"), algo_str); 461 return (EXIT_FAILURE); 462 } 463 464 /* 465 * Process keyfile or get the token pin if -K is specified. 466 * 467 * If a keyfile is provided, get the key data from 468 * the file. Otherwise, prompt for a passphrase. The 469 * passphrase is used as the key data. 470 */ 471 if (Kflag) { 472 /* get the pin of the token */ 473 if (token_label == NULL || !strlen(token_label)) { 474 token_label = pkcs11_default_token(); 475 } 476 477 status = pkcs11_get_pass(token_label, 478 (char **)&pkeydata, (size_t *)&keysize, 0, B_FALSE); 479 } else if (kflag) { 480 /* get the key file */ 481 status = pkcs11_read_data(keyfile, (void **)&pkeydata, 482 (size_t *)&keysize); 483 } else { 484 /* get the key from input */ 485 status = pkcs11_get_pass(NULL, (char **)&pkeydata, 486 (size_t *)&keysize, 0, 487 (cmd->type == CKA_ENCRYPT) ? B_TRUE : B_FALSE); 488 } 489 490 if (status != 0 || keysize == 0L) { 491 cryptoerror(LOG_STDERR, 492 kflag ? gettext("invalid key.") : 493 gettext("invalid passphrase.")); 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_get_urandom((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 /* Cannot open file, should leave it alone */ 722 leavefilealone = B_TRUE; 723 goto cleanup; 724 } 725 } 726 } 727 728 /* 729 * Read the version number from the head of the file 730 * to know how to interpret the data that follows. 731 */ 732 if (cmd->type == CKA_DECRYPT) { 733 if (read(infd, &version, sizeof (version)) != 734 sizeof (version)) { 735 cryptoerror(LOG_STDERR, gettext( 736 "failed to get format version from " 737 "input file.")); 738 goto cleanup; 739 } 740 /* convert to host byte order */ 741 version = ntohl(version); 742 743 switch (version) { 744 case 1: 745 /* 746 * Version 1 output format: 747 * - Output format version 1 (4 bytes) 748 * - Iterations used in key gen function (4 bytes) 749 * - IV ('ivlen' bytes). The length algorithm-dependent 750 * - Salt data used in key gen (16 bytes) 751 * - Cipher text data (remainder of the file) 752 * 753 * An encrypted file has IV as first block (0 or 754 * more bytes depending on mechanism) followed 755 * by cipher text. Get the IV from the encrypted 756 * file. 757 */ 758 /* 759 * Read iteration count and salt data. 760 */ 761 if (read(infd, &iterations, 762 sizeof (iterations)) != sizeof (iterations)) { 763 cryptoerror(LOG_STDERR, gettext( 764 "failed to get iterations from " 765 "input file.")); 766 goto cleanup; 767 } 768 /* convert to host byte order */ 769 iterations = ntohl(iterations); 770 if (ivlen > 0 && 771 read(infd, pivbuf, ivlen) != ivlen) { 772 cryptoerror(LOG_STDERR, gettext( 773 "failed to get initialization " 774 "vector from input file.")); 775 goto cleanup; 776 } 777 if (read(infd, salt, sizeof (salt)) 778 != sizeof (salt)) { 779 cryptoerror(LOG_STDERR, gettext( 780 "failed to get salt data from " 781 "input file.")); 782 goto cleanup; 783 } 784 break; 785 default: 786 cryptoerror(LOG_STDERR, gettext( 787 "Unrecognized format version read from " 788 "input file - expected %d, got %d."), 789 SUNW_ENCRYPT_FILE_VERSION, version); 790 goto cleanup; 791 break; 792 } 793 } 794 795 /* 796 * If Kflag is set, let's find the token key now. 797 * 798 * If Kflag is not set and if encrypting, we need some random 799 * salt data to create the key. If decrypting, 800 * the salt should come from head of the file 801 * to be decrypted. 802 */ 803 if (Kflag) { 804 rv = get_token_key(hSession, keytype, key_label, pkeydata, 805 keysize, &key); 806 if (rv != CKR_OK) { 807 cryptoerror(LOG_STDERR, gettext( 808 "Can not find the token key")); 809 goto cleanup; 810 } else { 811 goto do_crypto; 812 } 813 } else if (cmd->type == CKA_ENCRYPT) { 814 rv = pkcs11_get_urandom((void *)salt, sizeof (salt)); 815 if (rv != 0) { 816 cryptoerror(LOG_STDERR, 817 gettext("unable to generate random " 818 "data for key salt.")); 819 goto cleanup; 820 } 821 } 822 823 824 /* 825 * If key input is read from a file, treat it as 826 * raw key data, unless it is to be used with RC4, 827 * in which case it must be used to generate a pkcs5 828 * key to address security concerns with RC4 keys. 829 */ 830 if (kflag && keyfile != NULL && keytype != CKK_RC4) { 831 /* XXX : why wasn't SUNW_C_KeyToObject used here? */ 832 CK_OBJECT_CLASS objclass = CKO_SECRET_KEY; 833 CK_ATTRIBUTE template[5]; 834 int nattr = 0; 835 836 template[nattr].type = CKA_CLASS; 837 template[nattr].pValue = &objclass; 838 template[nattr].ulValueLen = sizeof (objclass); 839 nattr++; 840 841 template[nattr].type = CKA_KEY_TYPE; 842 template[nattr].pValue = &keytype; 843 template[nattr].ulValueLen = sizeof (keytype); 844 nattr++; 845 846 template[nattr].type = cmd->type; 847 template[nattr].pValue = &truevalue; 848 template[nattr].ulValueLen = sizeof (truevalue); 849 nattr++; 850 851 template[nattr].type = CKA_TOKEN; 852 template[nattr].pValue = &falsevalue; 853 template[nattr].ulValueLen = sizeof (falsevalue); 854 nattr++; 855 856 template[nattr].type = CKA_VALUE; 857 template[nattr].pValue = pkeydata; 858 template[nattr].ulValueLen = keysize; 859 nattr++; 860 861 rv = C_CreateObject(hSession, template, nattr, &key); 862 } else { 863 /* 864 * If the encryption type has a fixed key length, 865 * then its not necessary to set the key length 866 * parameter when generating the key. 867 */ 868 if (keytype == CKK_DES || keytype == CKK_DES3) 869 keylen = 0; 870 else 871 keylen = 16; 872 873 /* 874 * Generate a cryptographically secure key using 875 * the key read from the file given (-k keyfile) or 876 * the passphrase entered by the user. 877 */ 878 rv = pkcs11_PasswdToPBKD2Object(hSession, (char *)pkeydata, 879 (size_t)keysize, (void *)salt, sizeof (salt), iterations, 880 keytype, keylen, cmd->flags, &key); 881 } 882 883 if (rv != CKR_OK) { 884 cryptoerror(LOG_STDERR, gettext( 885 "failed to generate a key: %s"), 886 pkcs11_strerror(rv)); 887 goto cleanup; 888 } 889 890 891 do_crypto: 892 /* Setup up mechanism */ 893 mech.mechanism = mech_type; 894 mech.pParameter = (CK_VOID_PTR)pivbuf; 895 mech.ulParameterLen = ivlen; 896 897 if ((rv = cmd->Init(hSession, &mech, key)) != CKR_OK) { 898 cryptoerror(LOG_STDERR, gettext( 899 "failed to initialize crypto operation: %s"), 900 pkcs11_strerror(rv)); 901 goto cleanup; 902 } 903 904 /* Write the version header encrypt command */ 905 if (cmd->type == CKA_ENCRYPT) { 906 /* convert to network order for storage */ 907 uint32_t netversion = htonl(version); 908 uint32_t netiter; 909 910 if (write(outfd, &netversion, sizeof (netversion)) 911 != sizeof (netversion)) { 912 cryptoerror(LOG_STDERR, gettext( 913 "failed to write version number " 914 "to output file.")); 915 goto cleanup; 916 } 917 /* 918 * Write the iteration and salt data, even if they 919 * were not used to generate a key. 920 */ 921 netiter = htonl(iterations); 922 if (write(outfd, &netiter, 923 sizeof (netiter)) != sizeof (netiter)) { 924 cryptoerror(LOG_STDERR, gettext( 925 "failed to write iterations to output")); 926 goto cleanup; 927 } 928 if (ivlen > 0 && write(outfd, pivbuf, ivlen) != ivlen) { 929 cryptoerror(LOG_STDERR, gettext( 930 "failed to write initialization vector " 931 "to output")); 932 goto cleanup; 933 } 934 if (write(outfd, salt, sizeof (salt)) != sizeof (salt)) { 935 cryptoerror(LOG_STDERR, gettext( 936 "failed to write salt data to output")); 937 goto cleanup; 938 } 939 } 940 941 if (crypt_multipart(cmd, hSession, infd, outfd, insbuf.st_size) == -1) { 942 goto cleanup; 943 } 944 945 errflag = B_FALSE; 946 947 /* 948 * Clean up 949 */ 950 cleanup: 951 /* Clear the key data, so others cannot snoop */ 952 if (pkeydata != NULL) { 953 bzero(pkeydata, keysize); 954 free(pkeydata); 955 pkeydata = NULL; 956 } 957 958 /* Destroy key object */ 959 if (Kflag != B_FALSE && key != (CK_OBJECT_HANDLE) 0) { 960 (void) C_DestroyObject(hSession, key); 961 } 962 963 /* free allocated memory */ 964 if (pSlotList != NULL) 965 free(pSlotList); 966 if (pivbuf != NULL) 967 free(pivbuf); 968 969 /* close all the files */ 970 if (iflag && (infd != -1)) 971 (void) close(infd); 972 if (oflag && (outfd != -1)) 973 (void) close(outfd); 974 975 /* rename tmp output to input file */ 976 if (inoutsame) { 977 if (rename(outfilename, inputfile) == -1) { 978 (void) unlink(outfilename); 979 cryptoerror(LOG_STDERR, gettext("rename failed.")); 980 } 981 } 982 983 /* If error occurred and the file was new, remove the output file */ 984 if (errflag && (outfilename != NULL) && !leavefilealone) { 985 (void) unlink(outfilename); 986 } 987 988 /* close pkcs11 session */ 989 if (hSession != CK_INVALID_HANDLE) 990 (void) C_CloseSession(hSession); 991 992 (void) C_Finalize(NULL); 993 994 return (errflag); 995 } 996 997 /* 998 * Function for printing progress bar when the verbose flag 999 * is set. 1000 * 1001 * The vertical bar is printed at 25, 50, and 75% complete. 1002 * 1003 * The function is passed the number of positions on the screen it needs to 1004 * advance and loops. 1005 */ 1006 1007 static void 1008 print_status(int pos_to_advance) 1009 { 1010 1011 while (pos_to_advance > 0) { 1012 switch (status_pos) { 1013 case 0: 1014 (void) fprintf(stderr, gettext("[")); 1015 break; 1016 case 19: 1017 case 39: 1018 case 59: 1019 (void) fprintf(stderr, gettext("|")); 1020 break; 1021 default: 1022 (void) fprintf(stderr, gettext(".")); 1023 } 1024 pos_to_advance--; 1025 status_pos++; 1026 } 1027 } 1028 1029 /* 1030 * Encrypt/Decrypt in multi part. 1031 * 1032 * This function reads the input file (infd) and writes the 1033 * encrypted/decrypted output to file (outfd). 1034 * 1035 * cmd - pointing to commandinfo 1036 * hSession - pkcs session 1037 * infd - input file descriptor 1038 * outfd - output file descriptor 1039 * 1040 */ 1041 1042 static int 1043 crypt_multipart(struct CommandInfo *cmd, CK_SESSION_HANDLE hSession, 1044 int infd, int outfd, off_t insize) 1045 { 1046 CK_RV rv; 1047 CK_ULONG resultlen; 1048 CK_ULONG resultbuflen; 1049 CK_BYTE_PTR resultbuf; 1050 CK_ULONG datalen; 1051 CK_BYTE databuf[BUFFERSIZE]; 1052 CK_BYTE outbuf[BUFFERSIZE+BLOCKSIZE]; 1053 CK_ULONG status_index = 0; /* current total file size read */ 1054 float status_last = 0.0; /* file size of last element used */ 1055 float status_incr = 0.0; /* file size element increments */ 1056 int pos; /* # of progress bar elements to be print */ 1057 ssize_t nread; 1058 boolean_t errflag = B_FALSE; 1059 1060 datalen = sizeof (databuf); 1061 resultbuflen = sizeof (outbuf); 1062 resultbuf = outbuf; 1063 1064 /* Divide into 79 increments for progress bar element spacing */ 1065 if (vflag && iflag) 1066 status_incr = (insize / 79.0); 1067 1068 while ((nread = read(infd, databuf, datalen)) > 0) { 1069 1070 /* Start with the initial buffer */ 1071 resultlen = resultbuflen; 1072 rv = cmd->Update(hSession, databuf, (CK_ULONG)nread, 1073 resultbuf, &resultlen); 1074 1075 /* Need a bigger buffer? */ 1076 if (rv == CKR_BUFFER_TOO_SMALL) { 1077 1078 /* free the old buffer */ 1079 if (resultbuf != NULL && resultbuf != outbuf) { 1080 bzero(resultbuf, resultbuflen); 1081 free(resultbuf); 1082 } 1083 1084 /* allocate a new big buffer */ 1085 if ((resultbuf = malloc((size_t)resultlen)) == NULL) { 1086 int err = errno; 1087 cryptoerror(LOG_STDERR, gettext("malloc: %s"), 1088 strerror(err)); 1089 return (-1); 1090 } 1091 resultbuflen = resultlen; 1092 1093 /* Try again with bigger buffer */ 1094 rv = cmd->Update(hSession, databuf, (CK_ULONG)nread, 1095 resultbuf, &resultlen); 1096 } 1097 1098 if (rv != CKR_OK) { 1099 errflag = B_TRUE; 1100 cryptoerror(LOG_STDERR, gettext( 1101 "crypto operation failed: %s"), 1102 pkcs11_strerror(rv)); 1103 break; 1104 } 1105 1106 /* write the output */ 1107 if (write(outfd, resultbuf, resultlen) != resultlen) { 1108 cryptoerror(LOG_STDERR, gettext( 1109 "failed to write result to output file.")); 1110 errflag = B_TRUE; 1111 break; 1112 } 1113 1114 if (vflag) { 1115 status_index += resultlen; 1116 1117 /* 1118 * If input is from stdin, do a our own progress bar 1119 * by printing periods at a pre-defined increment 1120 * until the file is done. 1121 */ 1122 if (!iflag) { 1123 1124 /* 1125 * Print at least 1 element in case the file 1126 * is small, it looks better than nothing. 1127 */ 1128 if (status_pos == 0) { 1129 (void) fprintf(stderr, gettext(".")); 1130 status_pos = 1; 1131 } 1132 1133 if ((status_index - status_last) > 1134 (PROGRESSSIZE)) { 1135 (void) fprintf(stderr, gettext(".")); 1136 status_last = status_index; 1137 } 1138 continue; 1139 } 1140 1141 /* Calculate the number of elements need to be print */ 1142 if (insize <= BUFFERSIZE) 1143 pos = 78; 1144 else 1145 pos = (int)((status_index - status_last) / 1146 status_incr); 1147 1148 /* Add progress bar elements, if needed */ 1149 if (pos > 0) { 1150 print_status(pos); 1151 status_last += (status_incr * pos); 1152 } 1153 } 1154 } 1155 1156 /* Print verbose completion */ 1157 if (vflag) { 1158 if (iflag) 1159 (void) fprintf(stderr, "]"); 1160 1161 (void) fprintf(stderr, "\n%s\n", gettext("Done.")); 1162 } 1163 1164 /* Error in reading */ 1165 if (nread == -1) { 1166 cryptoerror(LOG_STDERR, gettext( 1167 "error reading from input file")); 1168 errflag = B_TRUE; 1169 } 1170 1171 if (!errflag) { 1172 1173 /* Do the final part */ 1174 1175 rv = cmd->Final(hSession, resultbuf, &resultlen); 1176 1177 if (rv == CKR_OK) { 1178 /* write the output */ 1179 if (write(outfd, resultbuf, resultlen) != resultlen) { 1180 cryptoerror(LOG_STDERR, gettext( 1181 "failed to write result to output file.")); 1182 errflag = B_TRUE; 1183 } 1184 } else { 1185 cryptoerror(LOG_STDERR, gettext( 1186 "crypto operation failed: %s"), 1187 pkcs11_strerror(rv)); 1188 errflag = B_TRUE; 1189 } 1190 1191 } 1192 1193 if (resultbuf != NULL && resultbuf != outbuf) { 1194 bzero(resultbuf, resultbuflen); 1195 free(resultbuf); 1196 } 1197 1198 if (errflag) { 1199 return (-1); 1200 } else { 1201 return (0); 1202 } 1203 } 1204