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