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