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