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