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