1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * decrypt.c 31 * 32 * Implements encrypt(1) and decrypt(1) commands 33 * 34 * One binary performs both encrypt/decrypt operation. 35 * 36 * usage: 37 * 38 * algorithm - mechanism name without CKM_ prefix. Case 39 * does not matter 40 * keyfile - file containing key data. If not specified user is 41 * prompted to enter key. key length > 0 is required 42 * infile - input file to encrypt/decrypt. If omitted, stdin used. 43 * outfile - output file to encrypt/decrypt. If omitted, stdout used. 44 * if infile & outfile are same, a temp file is used for 45 * output and infile is replaced with this file after 46 * operation is complete. 47 * 48 * Implementation notes: 49 * iv data - It is generated by random bytes equal to one block size. 50 * 51 * encrypted output format - 52 * - Output format version number - 4 bytes in network byte order. 53 * - Iterations used in key gen function, 4 bytes in network byte order. 54 * - IV ( 'ivlen' bytes) 55 * - Salt data used in key gen (16 bytes) 56 * - cipher text data. 57 * 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 77 #define BUFFERSIZE (2048) /* Buffer size for reading file */ 78 #define BLOCKSIZE (128) /* Largest guess for block size */ 79 #define PROGRESSSIZE (BUFFERSIZE*20) /* stdin progress indicator size */ 80 81 #define PBKD2_ITERATIONS (1000) 82 #define PBKD2_SALT_SIZE 16 83 84 #define SUNW_ENCRYPT_FILE_VERSION 1 85 86 /* 87 * Exit Status codes 88 */ 89 #ifndef EXIT_SUCCESS 90 #define EXIT_SUCCESS 0 /* No errors */ 91 #define EXIT_FAILURE 1 /* All errors except usage */ 92 #endif /* EXIT_SUCCESS */ 93 94 #define EXIT_USAGE 2 /* usage/syntax error */ 95 96 #define RANDOM_DEVICE "/dev/urandom" /* random device name */ 97 98 #define ENCRYPT_NAME "encrypt" /* name of encrypt command */ 99 #define ENCRYPT_OPTIONS "a:k:i:o:lv" /* options for encrypt */ 100 #define DECRYPT_NAME "decrypt" /* name of decrypt command */ 101 #define DECRYPT_OPTIONS "a: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 173 static char *keyfile = NULL; /* name of keyfile */ 174 static char *inputfile = NULL; /* name of input file */ 175 static char *outputfile = NULL; /* name of output file */ 176 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 cryptogetkey(CK_BYTE_PTR *pkeydata, CK_ULONG_PTR pkeysize); 185 static int cryptoreadfile(char *filename, CK_BYTE_PTR *pdata, 186 CK_ULONG_PTR pdatalen); 187 static int get_random_data(CK_BYTE_PTR pivbuf, int ivlen); 188 static int crypt_multipart(struct CommandInfo *cmd, CK_SESSION_HANDLE hSession, 189 int infd, int outfd, struct stat in); 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 defiend 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 'i': 243 iflag = B_TRUE; 244 inputfile = optarg; 245 break; 246 case 'o': 247 oflag = B_TRUE; 248 outputfile = optarg; 249 break; 250 case 'l': 251 lflag = B_TRUE; 252 break; 253 case 'v': 254 vflag = B_TRUE; 255 break; 256 default: 257 errflag = B_TRUE; 258 } 259 } 260 261 if (errflag || (!aflag && !lflag) || (lflag && argc > 2) || 262 (optind < argc)) { 263 usage(cmd); 264 exit(EXIT_USAGE); 265 } 266 267 return (execute_cmd(cmd, algo_str)); 268 } 269 270 /* 271 * usage message 272 */ 273 static void 274 usage(struct CommandInfo *cmd) 275 { 276 if (cmd->type == CKA_ENCRYPT) { 277 cryptoerror(LOG_STDERR, gettext("usage: encrypt -l | -a " 278 "<algorithm> [-k <keyfile>] [-i <infile>]" 279 "\n\t\t\t[-o <outfile>]")); 280 } else { 281 cryptoerror(LOG_STDERR, gettext("usage: decrypt -l | -a " 282 "<algorithm> [-k <keyfile>] [-i <infile>]" 283 "\n\t\t\t[-o <outfile>]")); 284 } 285 } 286 287 /* 288 * Print out list of algorithms in default and verbose mode 289 */ 290 static void 291 algorithm_list() 292 { 293 int mech; 294 295 (void) printf(gettext("Algorithm Keysize: Min Max (bits)\n" 296 "------------------------------------------\n")); 297 298 for (mech = 0; mech < MECH_ALIASES_COUNT; mech++) { 299 300 if (mech_aliases[mech].available == B_FALSE) 301 continue; 302 303 (void) printf("%-15s", mech_aliases[mech].alias); 304 305 if (mech_aliases[mech].keysize_min != UINT_MAX && 306 mech_aliases[mech].keysize_max != 0) 307 (void) printf(" %5lu %5lu\n", 308 (mech_aliases[mech].keysize_min * 309 mech_aliases[mech].keysize_unit), 310 (mech_aliases[mech].keysize_max * 311 mech_aliases[mech].keysize_unit)); 312 else 313 (void) printf("\n"); 314 315 } 316 } 317 318 static CK_RV 319 generate_pkcs5_key(CK_SESSION_HANDLE hSession, 320 CK_BYTE *pSaltData, 321 CK_ULONG saltLen, 322 CK_ULONG iterations, 323 CK_BYTE *pkeydata, /* user entered passphrase */ 324 CK_KEY_TYPE keytype, 325 CK_ULONG passwd_size, 326 CK_ULONG keylen, /* desired length of generated key */ 327 CK_ATTRIBUTE_TYPE operation, 328 CK_OBJECT_HANDLE *hKey) 329 { 330 CK_RV rv; 331 CK_PKCS5_PBKD2_PARAMS params; 332 CK_MECHANISM mechanism; 333 CK_OBJECT_CLASS class = CKO_SECRET_KEY; 334 CK_ATTRIBUTE tmpl[4]; 335 int attrs = 0; 336 337 mechanism.mechanism = CKM_PKCS5_PBKD2; 338 mechanism.pParameter = ¶ms; 339 mechanism.ulParameterLen = sizeof (params); 340 341 tmpl[attrs].type = CKA_CLASS; 342 tmpl[attrs].pValue = &class; 343 tmpl[attrs].ulValueLen = sizeof (class); 344 attrs++; 345 346 tmpl[attrs].type = CKA_KEY_TYPE; 347 tmpl[attrs].pValue = &keytype; 348 tmpl[attrs].ulValueLen = sizeof (keytype); 349 attrs++; 350 351 tmpl[attrs].type = operation; 352 tmpl[attrs].pValue = &truevalue; 353 tmpl[attrs].ulValueLen = sizeof (CK_BBOOL); 354 attrs++; 355 356 if (keylen > 0) { 357 tmpl[attrs].type = CKA_VALUE_LEN; 358 tmpl[attrs].pValue = &keylen; 359 tmpl[attrs].ulValueLen = sizeof (keylen); 360 attrs++; 361 } 362 363 params.saltSource = CKZ_SALT_SPECIFIED; 364 params.pSaltSourceData = (void *)pSaltData; 365 params.ulSaltSourceDataLen = saltLen; 366 params.iterations = iterations; 367 params.prf = CKP_PKCS5_PBKD2_HMAC_SHA1; 368 params.pPrfData = NULL; 369 params.ulPrfDataLen = 0; 370 params.pPassword = (CK_UTF8CHAR_PTR)pkeydata; 371 params.ulPasswordLen = &passwd_size; 372 373 mechanism.mechanism = CKM_PKCS5_PBKD2; 374 mechanism.pParameter = ¶ms; 375 mechanism.ulParameterLen = sizeof (params); 376 377 rv = C_GenerateKey(hSession, &mechanism, tmpl, 378 attrs, hKey); 379 380 return (rv); 381 } 382 383 384 /* 385 * Execute the command. 386 * cmd - command pointing to type of operation. 387 * algo_str - alias of the algorithm passed. 388 */ 389 static int 390 execute_cmd(struct CommandInfo *cmd, char *algo_str) 391 { 392 CK_RV rv; 393 CK_ULONG slotcount; 394 CK_SLOT_ID slotID; 395 CK_SLOT_ID_PTR pSlotList = NULL; 396 CK_MECHANISM_TYPE mech_type = 0; 397 CK_MECHANISM_INFO info, kg_info; 398 CK_MECHANISM mech; 399 CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; 400 CK_BYTE_PTR pkeydata = NULL; 401 CK_BYTE salt[PBKD2_SALT_SIZE]; 402 CK_ULONG keysize = 0; 403 int i, slot, mek; /* index variables */ 404 int status; 405 struct stat insbuf; /* stat buf for infile */ 406 struct stat outsbuf; /* stat buf for outfile */ 407 char tmpnam[PATH_MAX]; /* tmp file name */ 408 CK_OBJECT_HANDLE key = (CK_OBJECT_HANDLE) 0; 409 int infd = 0; /* input file, stdin default */ 410 int outfd = 1; /* output file, stdout default */ 411 char *outfilename = NULL; 412 boolean_t errflag = B_TRUE; 413 boolean_t inoutsame = B_FALSE; /* if both input & output are same */ 414 CK_BYTE_PTR pivbuf = NULL_PTR; 415 CK_ULONG ivlen = 0L; 416 int mech_match = 0; 417 CK_ULONG iterations = PBKD2_ITERATIONS; 418 CK_ULONG keylen; 419 int version = SUNW_ENCRYPT_FILE_VERSION; 420 CK_KEY_TYPE keytype; 421 422 if (aflag) { 423 /* Determine if algorithm is valid */ 424 for (mech_match = 0; mech_match < MECH_ALIASES_COUNT; 425 mech_match++) { 426 if (strcmp(algo_str, 427 mech_aliases[mech_match].alias) == 0) { 428 mech_type = mech_aliases[mech_match].type; 429 break; 430 } 431 } 432 433 if (mech_match == MECH_ALIASES_COUNT) { 434 cryptoerror(LOG_STDERR, 435 gettext("unknown algorithm -- %s"), algo_str); 436 return (EXIT_FAILURE); 437 } 438 439 /* 440 * Process keyfile 441 * 442 * If a keyfile is provided, get the key data from 443 * the file. Otherwise, prompt for a passphrase. The 444 * passphrase is used as the key data. 445 */ 446 if (kflag) { 447 status = cryptoreadfile(keyfile, &pkeydata, &keysize); 448 } else { 449 status = cryptogetkey(&pkeydata, &keysize); 450 } 451 452 if (status == -1 || keysize == 0L) { 453 cryptoerror(LOG_STDERR, gettext("invalid key.")); 454 return (EXIT_FAILURE); 455 } 456 } 457 458 bzero(salt, sizeof (salt)); 459 /* Initialize pkcs */ 460 if ((rv = C_Initialize(NULL)) != CKR_OK) { 461 cryptoerror(LOG_STDERR, gettext("failed to initialize " 462 "PKCS #11 framework: %s"), pkcs11_strerror(rv)); 463 goto cleanup; 464 } 465 466 /* Get slot count */ 467 rv = C_GetSlotList(0, NULL_PTR, &slotcount); 468 if (rv != CKR_OK || slotcount == 0) { 469 cryptoerror(LOG_STDERR, gettext( 470 "failed to find any cryptographic provider," 471 "please check with your system administrator: %s"), 472 pkcs11_strerror(rv)); 473 goto cleanup; 474 } 475 476 /* Found at least one slot, allocate memory for slot list */ 477 pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID)); 478 if (pSlotList == NULL_PTR) { 479 int err = errno; 480 cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(err)); 481 goto cleanup; 482 } 483 484 /* Get the list of slots */ 485 if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) { 486 cryptoerror(LOG_STDERR, gettext( 487 "failed to find any cryptographic provider," 488 "please check with your system administrator: %s"), 489 pkcs11_strerror(rv)); 490 goto cleanup; 491 } 492 493 if (lflag) { 494 495 /* Iterate through slots */ 496 for (slot = 0; slot < slotcount; slot++) { 497 498 /* Iterate through each mechanism */ 499 for (mek = 0; mek < MECH_ALIASES_COUNT; mek++) { 500 rv = C_GetMechanismInfo(pSlotList[slot], 501 mech_aliases[mek].type, &info); 502 503 if (rv != CKR_OK) 504 continue; 505 506 /* 507 * Set to minimum/maximum key sizes assuming 508 * the values available are not 0. 509 */ 510 if (info.ulMinKeySize && (info.ulMinKeySize < 511 mech_aliases[mek].keysize_min)) 512 mech_aliases[mek].keysize_min = 513 info.ulMinKeySize; 514 515 if (info.ulMaxKeySize && (info.ulMaxKeySize > 516 mech_aliases[mek].keysize_max)) 517 mech_aliases[mek].keysize_max = 518 info.ulMaxKeySize; 519 520 mech_aliases[mek].available = B_TRUE; 521 } 522 523 } 524 525 algorithm_list(); 526 527 errflag = B_FALSE; 528 goto cleanup; 529 } 530 531 /* Find a slot with matching mechanism */ 532 for (i = 0; i < slotcount; i++) { 533 slotID = pSlotList[i]; 534 rv = C_GetMechanismInfo(slotID, mech_type, &info); 535 if (rv != CKR_OK) { 536 continue; /* to the next slot */ 537 } else { 538 /* 539 * If the slot support the crypto, also 540 * make sure it supports the correct 541 * key generation mech if needed. 542 * 543 * We need PKCS5 when RC4 is used or 544 * when the key is entered on cmd line. 545 */ 546 if ((info.flags & cmd->flags) && 547 (mech_type == CKM_RC4) || (keyfile == NULL)) { 548 rv = C_GetMechanismInfo(slotID, 549 CKM_PKCS5_PBKD2, &kg_info); 550 if (rv == CKR_OK) 551 break; 552 } else if (info.flags & cmd->flags) { 553 break; 554 } 555 } 556 } 557 558 /* Show error if no matching mechanism found */ 559 if (i == slotcount) { 560 cryptoerror(LOG_STDERR, 561 gettext("no cryptographic provider was " 562 "found for this algorithm -- %s"), algo_str); 563 goto cleanup; 564 } 565 566 567 /* Open a session */ 568 rv = C_OpenSession(slotID, CKF_SERIAL_SESSION, 569 NULL_PTR, NULL, &hSession); 570 571 if (rv != CKR_OK) { 572 cryptoerror(LOG_STDERR, 573 gettext("can not open PKCS #11 session: %s"), 574 pkcs11_strerror(rv)); 575 goto cleanup; 576 } 577 578 /* 579 * Generate IV data for encrypt. 580 */ 581 ivlen = mech_aliases[mech_match].ivlen; 582 if ((pivbuf = malloc((size_t)ivlen)) == NULL) { 583 int err = errno; 584 cryptoerror(LOG_STDERR, gettext("malloc: %s"), 585 strerror(err)); 586 goto cleanup; 587 } 588 589 if (cmd->type == CKA_ENCRYPT) { 590 if ((get_random_data(pivbuf, 591 mech_aliases[mech_match].ivlen)) != 0) { 592 cryptoerror(LOG_STDERR, gettext( 593 "Unable to generate random " 594 "data for initialization vector.")); 595 goto cleanup; 596 } 597 } 598 599 /* 600 * Create the key object 601 */ 602 rv = pkcs11_mech2keytype(mech_type, &keytype); 603 if (rv != CKR_OK) { 604 cryptoerror(LOG_STDERR, 605 gettext("unable to find key type for algorithm.")); 606 goto cleanup; 607 } 608 609 /* Open input file */ 610 if (iflag) { 611 if ((infd = open(inputfile, O_RDONLY | O_NONBLOCK)) == -1) { 612 cryptoerror(LOG_STDERR, gettext( 613 "can not open input file %s"), inputfile); 614 goto cleanup; 615 } 616 617 /* Get info on input file */ 618 if (fstat(infd, &insbuf) == -1) { 619 cryptoerror(LOG_STDERR, gettext( 620 "can not stat input file %s"), inputfile); 621 goto cleanup; 622 } 623 } 624 625 /* 626 * Prepare output file 627 * If the input & output file are same, 628 * the output is written to a temp 629 * file first, then renamed to the original file 630 * after the crypt operation 631 */ 632 inoutsame = B_FALSE; 633 if (oflag) { 634 outfilename = outputfile; 635 if ((stat(outputfile, &outsbuf) != -1) && 636 (insbuf.st_ino == outsbuf.st_ino)) { 637 char *dir; 638 639 /* create temp file on same dir */ 640 dir = dirname(outputfile); 641 (void) snprintf(tmpnam, sizeof (tmpnam), 642 "%s/encrXXXXXX", dir); 643 outfilename = tmpnam; 644 if ((outfd = mkstemp(tmpnam)) == -1) { 645 cryptoerror(LOG_STDERR, gettext( 646 "cannot create temp file")); 647 goto cleanup; 648 } 649 inoutsame = B_TRUE; 650 } else { 651 /* Create file for output */ 652 if ((outfd = open(outfilename, 653 O_CREAT|O_WRONLY|O_TRUNC, 654 0644)) == -1) { 655 cryptoerror(LOG_STDERR, gettext( 656 "cannot open output file %s"), 657 outfilename); 658 goto cleanup; 659 } 660 } 661 } 662 663 /* 664 * Read the version number from the head of the file 665 * to know how to interpret the data that follows. 666 */ 667 if (cmd->type == CKA_DECRYPT) { 668 if (read(infd, &version, sizeof (version)) != 669 sizeof (version)) { 670 cryptoerror(LOG_STDERR, gettext( 671 "failed to get format version from " 672 "input file.")); 673 goto cleanup; 674 } 675 /* convert to host byte order */ 676 version = ntohl(version); 677 678 switch (version) { 679 case 1: 680 /* 681 * Version 1 output format: 682 * - Iterations used in key gen function (4 bytes) 683 * - IV ( 'ivlen' bytes) 684 * - Salt data used in key gen (16 bytes) 685 * 686 * An encrypted file has IV as first block (0 or 687 * more bytes depending on mechanism) followed 688 * by cipher text. Get the IV from the encrypted 689 * file. 690 */ 691 /* 692 * Read iteration count and salt data. 693 */ 694 if (read(infd, &iterations, 695 sizeof (iterations)) != 696 sizeof (iterations)) { 697 cryptoerror(LOG_STDERR, gettext( 698 "failed to get iterations from " 699 "input file.")); 700 goto cleanup; 701 } 702 /* convert to host byte order */ 703 iterations = ntohl(iterations); 704 if (ivlen > 0 && 705 read(infd, pivbuf, ivlen) != ivlen) { 706 cryptoerror(LOG_STDERR, gettext( 707 "failed to get initialization " 708 "vector from input file.")); 709 goto cleanup; 710 } 711 if (read(infd, salt, sizeof (salt)) 712 != sizeof (salt)) { 713 cryptoerror(LOG_STDERR, gettext( 714 "failed to get salt data from " 715 "input file.")); 716 goto cleanup; 717 } 718 break; 719 default: 720 cryptoerror(LOG_STDERR, gettext( 721 "Unrecognized format version read from " 722 "input file - expected %d, got %d."), 723 SUNW_ENCRYPT_FILE_VERSION, version); 724 goto cleanup; 725 break; 726 } 727 } 728 /* 729 * If encrypting, we need some random 730 * salt data to create the key. If decrypting, 731 * the salt should come from head of the file 732 * to be decrypted. 733 */ 734 if (cmd->type == CKA_ENCRYPT) { 735 rv = get_random_data(salt, sizeof (salt)); 736 if (rv != 0) { 737 cryptoerror(LOG_STDERR, 738 gettext("unable to generate random " 739 "data for key salt.")); 740 goto cleanup; 741 } 742 } 743 744 /* 745 * If key input is read from a file, treat it as 746 * raw key data, unless it is to be used with RC4, 747 * in which case it must be used to generate a pkcs5 748 * key to address security concerns with RC4 keys. 749 */ 750 if (kflag && keyfile != NULL && keytype != CKK_RC4) { 751 CK_OBJECT_CLASS objclass = CKO_SECRET_KEY; 752 CK_ATTRIBUTE template[5]; 753 int nattr = 0; 754 755 template[nattr].type = CKA_CLASS; 756 template[nattr].pValue = &objclass; 757 template[nattr].ulValueLen = sizeof (objclass); 758 nattr++; 759 760 template[nattr].type = CKA_KEY_TYPE; 761 template[nattr].pValue = &keytype; 762 template[nattr].ulValueLen = sizeof (keytype); 763 nattr++; 764 765 template[nattr].type = cmd->type; 766 template[nattr].pValue = &truevalue; 767 template[nattr].ulValueLen = sizeof (truevalue); 768 nattr++; 769 770 template[nattr].type = CKA_TOKEN; 771 template[nattr].pValue = &falsevalue; 772 template[nattr].ulValueLen = sizeof (falsevalue); 773 nattr++; 774 775 template[nattr].type = CKA_VALUE; 776 template[nattr].pValue = pkeydata; 777 template[nattr].ulValueLen = keysize; 778 nattr++; 779 780 rv = C_CreateObject(hSession, template, 781 nattr, &key); 782 } else { 783 /* 784 * If the encryption type has a fixed key length, 785 * then its not necessary to set the key length 786 * parameter when generating the key. 787 */ 788 if (keytype == CKK_DES || keytype == CKK_DES3) 789 keylen = 0; 790 else 791 keylen = 16; 792 793 /* 794 * Generate a cryptographically secure key using 795 * the key read from the file given (-k keyfile) or 796 * the passphrase entered by the user. 797 */ 798 rv = generate_pkcs5_key(hSession, 799 salt, sizeof (salt), 800 iterations, 801 pkeydata, keytype, keysize, 802 keylen, cmd->type, &key); 803 } 804 805 if (rv != CKR_OK) { 806 cryptoerror(LOG_STDERR, gettext( 807 "failed to generate a key: %s"), 808 pkcs11_strerror(rv)); 809 goto cleanup; 810 } 811 812 /* Setup up mechanism */ 813 mech.mechanism = mech_type; 814 mech.pParameter = (CK_VOID_PTR)pivbuf; 815 mech.ulParameterLen = ivlen; 816 817 if ((rv = cmd->Init(hSession, &mech, key)) != CKR_OK) { 818 cryptoerror(LOG_STDERR, gettext( 819 "failed to initialize crypto operation: %s"), 820 pkcs11_strerror(rv)); 821 goto cleanup; 822 } 823 824 /* Write the version header encrypt command */ 825 if (cmd->type == CKA_ENCRYPT) { 826 /* convert to network order for storage */ 827 int netversion = htonl(version); 828 CK_ULONG netiter; 829 830 if (write(outfd, &netversion, sizeof (netversion)) 831 != sizeof (netversion)) { 832 cryptoerror(LOG_STDERR, gettext( 833 "failed to write version number " 834 "to output file.")); 835 goto cleanup; 836 } 837 /* 838 * Write the iteration and salt data, even if they 839 * were not used to generate a key. 840 */ 841 netiter = htonl(iterations); 842 if (write(outfd, &netiter, 843 sizeof (netiter)) != sizeof (netiter)) { 844 cryptoerror(LOG_STDERR, gettext( 845 "failed to write iterations to output")); 846 goto cleanup; 847 } 848 if (ivlen > 0 && 849 write(outfd, pivbuf, ivlen) != ivlen) { 850 cryptoerror(LOG_STDERR, gettext( 851 "failed to write initialization vector " 852 "to output")); 853 goto cleanup; 854 } 855 if (write(outfd, salt, sizeof (salt)) != sizeof (salt)) { 856 cryptoerror(LOG_STDERR, gettext( 857 "failed to write salt data to output")); 858 goto cleanup; 859 } 860 } 861 862 if (crypt_multipart(cmd, hSession, infd, outfd, insbuf) == -1) { 863 goto cleanup; 864 } 865 866 errflag = B_FALSE; 867 868 /* 869 * Clean up 870 */ 871 cleanup: 872 /* Clear the key data, so others cannot snoop */ 873 if (pkeydata != NULL) { 874 bzero(pkeydata, keysize); 875 free(pkeydata); 876 pkeydata = NULL; 877 } 878 879 /* Destroy key object */ 880 if (key != (CK_OBJECT_HANDLE) 0) { 881 (void) C_DestroyObject(hSession, key); 882 } 883 884 /* free allocated memory */ 885 if (pSlotList != NULL) 886 free(pSlotList); 887 if (pivbuf != NULL) 888 free(pivbuf); 889 890 /* close all the files */ 891 if (infd != -1) 892 (void) close(infd); 893 if (outfd != -1) 894 (void) close(outfd); 895 896 /* rename tmp output to input file */ 897 if (inoutsame) { 898 if (rename(outfilename, inputfile) == -1) { 899 (void) unlink(outfilename); 900 cryptoerror(LOG_STDERR, gettext("rename failed.")); 901 } 902 } 903 904 /* If error occurred, remove the output file */ 905 if (errflag && outfilename != NULL) { 906 (void) unlink(outfilename); 907 } 908 909 /* close pkcs11 session */ 910 if (hSession != CK_INVALID_HANDLE) 911 (void) C_CloseSession(hSession); 912 913 (void) C_Finalize(NULL); 914 915 return (errflag); 916 } 917 918 /* 919 * Function for printing progress bar when the verbose flag 920 * is set. 921 * 922 * The vertical bar is printed at 25, 50, and 75% complete. 923 * 924 * The function is passed the number of positions on the screen it needs to 925 * advance and loops. 926 */ 927 928 static void 929 print_status(int pos_to_advance) 930 { 931 932 while (pos_to_advance > 0) { 933 switch (status_pos) { 934 case 0: 935 (void) fprintf(stderr, gettext("[")); 936 break; 937 case 19: 938 case 39: 939 case 59: 940 (void) fprintf(stderr, gettext("|")); 941 break; 942 default: 943 (void) fprintf(stderr, gettext(".")); 944 } 945 pos_to_advance--; 946 status_pos++; 947 } 948 } 949 950 /* 951 * Encrypt/Decrypt in multi part. 952 * 953 * This function reads the input file (infd) and writes the 954 * encrypted/decrypted output to file (outfd). 955 * 956 * cmd - pointing to commandinfo 957 * hSession - pkcs session 958 * infd - input file descriptor 959 * outfd - output file descriptor 960 * 961 */ 962 963 static int 964 crypt_multipart(struct CommandInfo *cmd, CK_SESSION_HANDLE hSession, 965 int infd, int outfd, struct stat in) 966 { 967 CK_RV rv; 968 CK_ULONG resultlen; 969 CK_ULONG resultbuflen; 970 CK_BYTE_PTR resultbuf; 971 CK_ULONG datalen; 972 CK_BYTE databuf[BUFFERSIZE]; 973 CK_BYTE outbuf[BUFFERSIZE+BLOCKSIZE]; 974 CK_ULONG status_index = 0; /* current total file size read */ 975 float status_last = 0.0; /* file size of last element used */ 976 float status_incr = 0.0; /* file size element increments */ 977 int pos; /* # of progress bar elements to be print */ 978 ssize_t nread; 979 boolean_t errflag = B_FALSE; 980 981 datalen = sizeof (databuf); 982 resultbuflen = sizeof (outbuf); 983 resultbuf = outbuf; 984 985 /* Divide into 79 increments for progress bar element spacing */ 986 if (vflag && iflag) 987 status_incr = (in.st_size / 79.0); 988 989 while ((nread = read(infd, databuf, datalen)) > 0) { 990 991 /* Start with the initial buffer */ 992 resultlen = resultbuflen; 993 rv = cmd->Update(hSession, databuf, (CK_ULONG)nread, 994 resultbuf, &resultlen); 995 996 /* Need a bigger buffer? */ 997 if (rv == CKR_BUFFER_TOO_SMALL) { 998 999 /* free the old buffer */ 1000 if (resultbuf != NULL && resultbuf != outbuf) { 1001 bzero(resultbuf, resultbuflen); 1002 free(resultbuf); 1003 } 1004 1005 /* allocate a new big buffer */ 1006 if ((resultbuf = malloc((size_t)resultlen)) == NULL) { 1007 int err = errno; 1008 cryptoerror(LOG_STDERR, gettext("malloc: %s"), 1009 strerror(err)); 1010 return (-1); 1011 } 1012 resultbuflen = resultlen; 1013 1014 /* Try again with bigger buffer */ 1015 rv = cmd->Update(hSession, databuf, (CK_ULONG)nread, 1016 resultbuf, &resultlen); 1017 } 1018 1019 if (rv != CKR_OK) { 1020 errflag = B_TRUE; 1021 cryptoerror(LOG_STDERR, gettext( 1022 "crypto operation failed: %s"), 1023 pkcs11_strerror(rv)); 1024 break; 1025 } 1026 1027 /* write the output */ 1028 if (write(outfd, resultbuf, resultlen) != resultlen) { 1029 cryptoerror(LOG_STDERR, gettext( 1030 "failed to write result to output file.")); 1031 errflag = B_TRUE; 1032 break; 1033 } 1034 1035 if (vflag) { 1036 status_index += resultlen; 1037 1038 /* 1039 * If input is from stdin, do a our own progress bar 1040 * by printing periods at a pre-defined increment 1041 * until the file is done. 1042 */ 1043 if (!iflag) { 1044 1045 /* 1046 * Print at least 1 element in case the file 1047 * is small, it looks better than nothing. 1048 */ 1049 if (status_pos == 0) { 1050 (void) fprintf(stderr, gettext(".")); 1051 status_pos = 1; 1052 } 1053 1054 if ((status_index - status_last) > 1055 (PROGRESSSIZE)) { 1056 (void) fprintf(stderr, gettext(".")); 1057 status_last = status_index; 1058 } 1059 continue; 1060 } 1061 1062 /* Calculate the number of elements need to be print */ 1063 if (in.st_size <= BUFFERSIZE) 1064 pos = 78; 1065 else 1066 pos = (int)((status_index - status_last) / 1067 status_incr); 1068 1069 /* Add progress bar elements, if needed */ 1070 if (pos > 0) { 1071 print_status(pos); 1072 status_last += (status_incr * pos); 1073 } 1074 } 1075 } 1076 1077 /* Print verbose completion */ 1078 if (vflag) { 1079 if (iflag) 1080 (void) fprintf(stderr, "]"); 1081 1082 (void) fprintf(stderr, "\n%s\n", gettext("Done.")); 1083 } 1084 1085 /* Error in reading */ 1086 if (nread == -1) { 1087 cryptoerror(LOG_STDERR, gettext( 1088 "error reading from input file")); 1089 errflag = B_TRUE; 1090 } 1091 1092 if (!errflag) { 1093 1094 /* Do the final part */ 1095 1096 rv = cmd->Final(hSession, resultbuf, &resultlen); 1097 1098 if (rv == CKR_OK) { 1099 /* write the output */ 1100 if (write(outfd, resultbuf, resultlen) != resultlen) { 1101 cryptoerror(LOG_STDERR, gettext( 1102 "failed to write result to output file.")); 1103 errflag = B_TRUE; 1104 } 1105 } else { 1106 cryptoerror(LOG_STDERR, gettext( 1107 "crypto operation failed: %s"), 1108 pkcs11_strerror(rv)); 1109 errflag = B_TRUE; 1110 } 1111 1112 } 1113 1114 if (resultbuf != NULL && resultbuf != outbuf) { 1115 bzero(resultbuf, resultbuflen); 1116 free(resultbuf); 1117 } 1118 1119 if (errflag) { 1120 return (-1); 1121 } else { 1122 return (0); 1123 } 1124 } 1125 1126 /* 1127 * cryptoreadfile - reads file into a buffer 1128 * This function can be used for reading files 1129 * containing key or initialization vector data. 1130 * 1131 * filename - name of file 1132 * pdata - entire file returned in this buffer 1133 * must be freed by caller using free() 1134 * pdatalen - length of data returned 1135 * 1136 * returns 0 if success, -1 if error 1137 */ 1138 static int 1139 cryptoreadfile(char *filename, CK_BYTE_PTR *pdata, CK_ULONG_PTR pdatalen) 1140 { 1141 struct stat statbuf; 1142 char *filebuf; 1143 int filesize; 1144 int fd; 1145 1146 if (filename == NULL) 1147 return (-1); 1148 1149 /* read the file into a buffer */ 1150 if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) { 1151 cryptoerror(LOG_STDERR, gettext( 1152 "cannot open %s"), filename); 1153 return (-1); 1154 1155 } 1156 1157 if (fstat(fd, &statbuf) == -1) { 1158 cryptoerror(LOG_STDERR, gettext( 1159 "cannot stat %s"), filename); 1160 (void) close(fd); 1161 return (-1); 1162 } 1163 1164 if (!(statbuf.st_mode & S_IFREG)) { 1165 cryptoerror(LOG_STDERR, gettext( 1166 "%s not a regular file"), filename); 1167 (void) close(fd); 1168 return (-1); 1169 } 1170 1171 filesize = (size_t)statbuf.st_size; 1172 1173 if (filesize == 0) { 1174 (void) close(fd); 1175 return (-1); 1176 } 1177 1178 /* allocate a buffer to hold the entire key */ 1179 if ((filebuf = malloc(filesize)) == NULL) { 1180 int err = errno; 1181 cryptoerror(LOG_STDERR, gettext("malloc: %s"), strerror(err)); 1182 (void) close(fd); 1183 return (-1); 1184 } 1185 1186 if (read(fd, filebuf, filesize) != filesize) { 1187 int err = errno; 1188 cryptoerror(LOG_STDERR, gettext("error reading file: %s"), 1189 strerror(err)); 1190 (void) close(fd); 1191 free(filebuf); 1192 return (-1); 1193 } 1194 1195 (void) close(fd); 1196 1197 *pdata = (CK_BYTE_PTR)filebuf; 1198 *pdatalen = (CK_ULONG)filesize; 1199 1200 return (0); 1201 } 1202 /* 1203 * cryptogetkey - prompt user for a key 1204 * 1205 * pkeydata - buffer for returning key data 1206 * must be freed by caller using free() 1207 * pkeysize - size of buffer returned 1208 * 1209 * returns 1210 * 0 for success, -1 for failure 1211 */ 1212 1213 static int 1214 cryptogetkey(CK_BYTE_PTR *pkeydata, CK_ULONG_PTR pkeysize) 1215 1216 { 1217 char *keybuf; 1218 char *tmpbuf; 1219 1220 1221 1222 tmpbuf = getpassphrase(gettext("Enter key:")); 1223 1224 if (tmpbuf == NULL) { 1225 return (-1); /* error */ 1226 } else { 1227 keybuf = strdup(tmpbuf); 1228 (void) memset(tmpbuf, 0, strlen(tmpbuf)); 1229 } 1230 1231 *pkeydata = (CK_BYTE_PTR)keybuf; 1232 *pkeysize = (CK_ULONG)strlen(keybuf); 1233 1234 1235 return (0); 1236 } 1237 1238 /* 1239 * get_random_data - generate initialization vector data 1240 * iv data is random bytes 1241 * hSession - a pkcs session 1242 * pivbuf - buffer where data is returned 1243 * ivlen - size of iv data 1244 */ 1245 static int 1246 get_random_data(CK_BYTE_PTR pivbuf, int ivlen) 1247 { 1248 int fd; 1249 1250 if (ivlen == 0) { 1251 /* nothing to generate */ 1252 return (0); 1253 } 1254 1255 /* Read random data directly from /dev/random */ 1256 if ((fd = open(RANDOM_DEVICE, O_RDONLY)) != -1) { 1257 if (read(fd, pivbuf, (size_t)ivlen) == ivlen) { 1258 (void) close(fd); 1259 return (0); 1260 } 1261 } 1262 (void) close(fd); 1263 return (-1); 1264 } 1265