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.
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.
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]
21 /* Portions Copyright 2005 Richard Lowe */
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2012 Milan Jurik. All rights reserved.
31 * Implements encrypt(1) and decrypt(1) commands
33 * One binary performs both encrypt/decrypt operation.
36 * -a algorithm mechanism name without CKM_ prefix. Case
38 * -k keyfile file containing key data. If not specified user is
39 * prompted to enter key. key length > 0 is required
40 * -i infile input file to encrypt/decrypt. If omitted, stdin used.
41 * -o outfile output file to encrypt/decrypt. If omitted, stdout used.
42 * if infile & outfile are same, a temp file is used for
43 * output and infile is replaced with this file after
44 * operation is complete
45 * -l Display the list of algorithms
46 * -v Display verbose information
47 * -T tokenspec Specify a PKCS#11 token (optionally used with -K)
48 * -K keylabel Specify the symmetric PKCS#11 token key label
50 * Implementation notes:
51 * IV data - It is generated by random bytes equal to one block size.
53 * Encrypted output format -
54 * - Output format version number (1) - 4 bytes in network byte order.
55 * - Iterations used in key gen function, 4 bytes in network byte order.
56 * - IV ('ivlen' bytes). Length is algorithm-dependent (see mech_aliases)
57 * - Salt data used in key gen (16 bytes)
58 * - Cipher text data (remainder of the file)
72 #include <sys/types.h>
74 #include <netinet/in.h>
75 #include <security/cryptoki.h>
76 #include <cryptoutil.h>
80 * Buffer size for reading file. This is given a rather high value
81 * to get better performance when a hardware provider is present.
83 #define BUFFERSIZE (1024 * 64)
84 #define BLOCKSIZE (128) /* Largest guess for block size */
85 #define PROGRESSSIZE (1024 * 40) /* stdin progress indicator size */
87 #define SUNW_ENCRYPT_FILE_VERSION 1
93 #define EXIT_SUCCESS 0 /* No errors */
94 #define EXIT_FAILURE 1 /* All errors except usage */
95 #endif /* EXIT_SUCCESS */
97 #define EXIT_USAGE 2 /* usage/syntax error */
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 */
105 * Structure containing info for encrypt/decrypt
109 char *name
; /* name of the command */
110 char *options
; /* command line options */
112 CK_ATTRIBUTE_TYPE type
; /* type of command */
114 /* function pointers for various operations */
115 CK_RV (*Init
)(CK_SESSION_HANDLE
, CK_MECHANISM_PTR
, CK_OBJECT_HANDLE
);
116 CK_RV (*Update
)(CK_SESSION_HANDLE
, CK_BYTE_PTR
, CK_ULONG
, CK_BYTE_PTR
,
118 CK_RV (*Crypt
)(CK_SESSION_HANDLE
, CK_BYTE_PTR
, CK_ULONG
, CK_BYTE_PTR
,
120 CK_RV (*Final
)(CK_SESSION_HANDLE
, CK_BYTE_PTR
, CK_ULONG_PTR
);
123 static struct CommandInfo encrypt_cmd
= {
134 static struct CommandInfo decrypt_cmd
= {
146 CK_MECHANISM_TYPE type
;
148 CK_ULONG keysize_min
;
149 CK_ULONG keysize_max
;
155 #define MECH_ALIASES_COUNT 4
157 static struct mech_alias mech_aliases
[] = {
158 { CKM_AES_CBC_PAD
, "aes", ULONG_MAX
, 0L, 8, 16, B_FALSE
},
159 { CKM_RC4
, "arcfour", ULONG_MAX
, 0L, 1, 0, B_FALSE
},
160 { CKM_DES_CBC_PAD
, "des", 8, 8, 8, 8, B_FALSE
},
161 { CKM_DES3_CBC_PAD
, "3des", 24, 24, 8, 8, B_FALSE
},
164 static CK_BBOOL truevalue
= TRUE
;
165 static CK_BBOOL falsevalue
= FALSE
;
167 static boolean_t aflag
= B_FALSE
; /* -a <algorithm> flag, required */
168 static boolean_t kflag
= B_FALSE
; /* -k <keyfile> flag */
169 static boolean_t iflag
= B_FALSE
; /* -i <infile> flag, use stdin if absent */
170 static boolean_t oflag
= B_FALSE
; /* -o <outfile> flag, use stdout if absent */
171 static boolean_t lflag
= B_FALSE
; /* -l flag (list) */
172 static boolean_t vflag
= B_FALSE
; /* -v flag (verbose) */
173 static boolean_t Tflag
= B_FALSE
; /* -T flag (tokenspec) */
174 static boolean_t Kflag
= B_FALSE
; /* -K flag (keylabel) */
176 static char *keyfile
= NULL
; /* name of keyfile */
177 static char *inputfile
= NULL
; /* name of input file */
178 static char *outputfile
= NULL
; /* name of output file */
179 static char *token_label
= NULL
; /* name of PKCS#11 token */
180 static char *key_label
= NULL
; /* name of PKCS#11 token key label */
182 static int status_pos
= 0; /* current position of progress bar element */
185 * function prototypes
187 static void usage(struct CommandInfo
*cmd
);
188 static int execute_cmd(struct CommandInfo
*cmd
, char *algo_str
);
189 static int crypt_multipart(struct CommandInfo
*cmd
, CK_SESSION_HANDLE hSession
,
190 int infd
, int outfd
, off_t insize
);
193 main(int argc
, char **argv
)
199 char c
; /* current getopts flag */
200 char *algo_str
= NULL
; /* algorithm string */
201 struct CommandInfo
*cmd
;
202 char *cmdname
; /* name of command */
203 boolean_t errflag
= B_FALSE
;
205 (void) setlocale(LC_ALL
, "");
206 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
207 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
209 (void) textdomain(TEXT_DOMAIN
);
212 * Based on command name, determine
215 cmdname
= basename(argv
[0]);
217 cryptodebug_init(cmdname
);
219 if (strcmp(cmdname
, encrypt_cmd
.name
) == 0) {
221 } else if (strcmp(cmdname
, decrypt_cmd
.name
) == 0) {
224 cryptoerror(LOG_STDERR
, gettext(
225 "command name must be either encrypt or decrypt"));
229 optstr
= cmd
->options
;
231 /* Parse command line arguments */
232 while (!errflag
&& (c
= getopt(argc
, argv
, optstr
)) != -1) {
245 token_label
= optarg
;
270 if (errflag
|| (!aflag
&& !lflag
) || (lflag
&& argc
> 2) ||
271 (kflag
&& Kflag
) || (Tflag
&& !Kflag
) ||
277 return (execute_cmd(cmd
, algo_str
));
284 usage(struct CommandInfo
*cmd
)
286 (void) fprintf(stderr
, gettext("Usage:\n"));
287 if (cmd
->type
== CKA_ENCRYPT
) {
288 (void) fprintf(stderr
, gettext(" encrypt -l\n"));
289 (void) fprintf(stderr
, gettext(" encrypt -a <algorithm> "
290 "[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] "
291 "[-i <infile>] [-o <outfile>]\n"));
294 (void) fprintf(stderr
, gettext(" decrypt -l\n"));
295 (void) fprintf(stderr
, gettext(" decrypt -a <algorithm> "
296 "[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] "
297 "[-i <infile>] [-o <outfile>]\n"));
302 * Print out list of algorithms in default and verbose mode
309 (void) printf(gettext("Algorithm Keysize: Min Max (bits)\n"
310 "------------------------------------------\n"));
312 for (mech
= 0; mech
< MECH_ALIASES_COUNT
; mech
++) {
314 if (mech_aliases
[mech
].available
== B_FALSE
)
317 (void) printf("%-15s", mech_aliases
[mech
].alias
);
319 if (mech_aliases
[mech
].keysize_min
!= UINT_MAX
&&
320 mech_aliases
[mech
].keysize_max
!= 0)
321 (void) printf(" %5lu %5lu\n",
322 (mech_aliases
[mech
].keysize_min
*
323 mech_aliases
[mech
].keysize_unit
),
324 (mech_aliases
[mech
].keysize_max
*
325 mech_aliases
[mech
].keysize_unit
));
333 * This function will login into the token with the provided password and
334 * find the token key object with the specified keytype and keylabel.
337 get_token_key(CK_SESSION_HANDLE hSession
, CK_KEY_TYPE keytype
,
338 char *keylabel
, CK_BYTE
*password
, int password_len
,
339 CK_OBJECT_HANDLE
*keyobj
)
342 CK_ATTRIBUTE pTmpl
[10];
343 CK_OBJECT_CLASS
class = CKO_SECRET_KEY
;
345 CK_BBOOL is_token
= 1;
346 CK_ULONG key_obj_count
= 1;
348 CK_KEY_TYPE ckKeyType
= keytype
;
351 rv
= C_Login(hSession
, CKU_USER
, (CK_UTF8CHAR_PTR
)password
,
352 (CK_ULONG
)password_len
);
354 (void) fprintf(stderr
, "Cannot login to the token."
355 " error = %s\n", pkcs11_strerror(rv
));
360 pTmpl
[i
].type
= CKA_TOKEN
;
361 pTmpl
[i
].pValue
= &is_token
;
362 pTmpl
[i
].ulValueLen
= sizeof (CK_BBOOL
);
365 pTmpl
[i
].type
= CKA_CLASS
;
366 pTmpl
[i
].pValue
= &class;
367 pTmpl
[i
].ulValueLen
= sizeof (class);
370 pTmpl
[i
].type
= CKA_LABEL
;
371 pTmpl
[i
].pValue
= keylabel
;
372 pTmpl
[i
].ulValueLen
= strlen(keylabel
);
375 pTmpl
[i
].type
= CKA_KEY_TYPE
;
376 pTmpl
[i
].pValue
= &ckKeyType
;
377 pTmpl
[i
].ulValueLen
= sizeof (ckKeyType
);
380 pTmpl
[i
].type
= CKA_PRIVATE
;
381 pTmpl
[i
].pValue
= &true;
382 pTmpl
[i
].ulValueLen
= sizeof (true);
385 rv
= C_FindObjectsInit(hSession
, pTmpl
, i
);
390 rv
= C_FindObjects(hSession
, keyobj
, 1, &key_obj_count
);
392 (void) C_FindObjectsFinal(hSession
);
396 (void) fprintf(stderr
,
397 "Cannot retrieve key object. error = %s\n",
398 pkcs11_strerror(rv
));
402 if (key_obj_count
== 0) {
403 (void) fprintf(stderr
, "Cannot find the key object.\n");
412 * Execute the command.
413 * cmd - command pointing to type of operation.
414 * algo_str - alias of the algorithm passed.
417 execute_cmd(struct CommandInfo
*cmd
, char *algo_str
)
422 CK_SLOT_ID_PTR pSlotList
= NULL
;
423 CK_MECHANISM_TYPE mech_type
= 0;
424 CK_MECHANISM_INFO info
, kg_info
;
426 CK_SESSION_HANDLE hSession
= CK_INVALID_HANDLE
;
427 CK_BYTE_PTR pkeydata
= NULL
;
428 CK_BYTE salt
[CK_PKCS5_PBKD2_SALT_SIZE
];
429 CK_ULONG keysize
= 0;
430 int i
, slot
, mek
; /* index variables */
432 struct stat insbuf
; /* stat buf for infile */
433 struct stat outsbuf
; /* stat buf for outfile */
434 char tmpnam
[PATH_MAX
]; /* tmp file name */
435 CK_OBJECT_HANDLE key
= (CK_OBJECT_HANDLE
) 0;
436 int infd
= 0; /* input file, stdin default */
437 int outfd
= 1; /* output file, stdout default */
438 char *outfilename
= NULL
;
439 boolean_t errflag
= B_TRUE
;
440 boolean_t inoutsame
= B_FALSE
; /* if both input & output are same */
441 boolean_t leavefilealone
= B_FALSE
;
442 CK_BYTE_PTR pivbuf
= NULL_PTR
;
445 uint32_t iterations
= CK_PKCS5_PBKD2_ITERATIONS
;
447 uint32_t version
= SUNW_ENCRYPT_FILE_VERSION
;
450 CK_SLOT_ID token_slot_id
;
453 /* Determine if algorithm is valid */
454 for (mech_match
= 0; mech_match
< MECH_ALIASES_COUNT
;
457 mech_aliases
[mech_match
].alias
) == 0) {
458 mech_type
= mech_aliases
[mech_match
].type
;
463 if (mech_match
== MECH_ALIASES_COUNT
) {
464 cryptoerror(LOG_STDERR
,
465 gettext("unknown algorithm -- %s"), algo_str
);
466 return (EXIT_FAILURE
);
470 * Process keyfile or get the token pin if -K is specified.
472 * If a keyfile is provided, get the key data from
473 * the file. Otherwise, prompt for a passphrase. The
474 * passphrase is used as the key data.
477 /* get the pin of the token */
478 if (token_label
== NULL
|| !strlen(token_label
)) {
479 token_label
= pkcs11_default_token();
482 status
= pkcs11_get_pass(token_label
,
483 (char **)&pkeydata
, (size_t *)&keysize
, 0, B_FALSE
);
485 /* get the key file */
486 status
= pkcs11_read_data(keyfile
, (void **)&pkeydata
,
489 /* get the key from input */
490 status
= pkcs11_get_pass(NULL
, (char **)&pkeydata
,
491 (size_t *)&keysize
, 0,
492 (cmd
->type
== CKA_ENCRYPT
) ? B_TRUE
: B_FALSE
);
495 if (status
!= 0 || keysize
== 0L) {
496 cryptoerror(LOG_STDERR
,
497 kflag
? gettext("invalid key.") :
498 gettext("invalid passphrase."));
499 return (EXIT_FAILURE
);
503 bzero(salt
, sizeof (salt
));
504 /* Initialize pkcs */
505 rv
= C_Initialize(NULL
);
506 if (rv
!= CKR_OK
&& rv
!= CKR_CRYPTOKI_ALREADY_INITIALIZED
) {
507 cryptoerror(LOG_STDERR
, gettext("failed to initialize "
508 "PKCS #11 framework: %s"), pkcs11_strerror(rv
));
513 rv
= C_GetSlotList(0, NULL_PTR
, &slotcount
);
514 if (rv
!= CKR_OK
|| slotcount
== 0) {
515 cryptoerror(LOG_STDERR
, gettext(
516 "failed to find any cryptographic provider,"
517 "please check with your system administrator: %s"),
518 pkcs11_strerror(rv
));
522 /* Found at least one slot, allocate memory for slot list */
523 pSlotList
= malloc(slotcount
* sizeof (CK_SLOT_ID
));
524 if (pSlotList
== NULL_PTR
) {
526 cryptoerror(LOG_STDERR
, gettext("malloc: %s"), strerror(err
));
530 /* Get the list of slots */
531 if ((rv
= C_GetSlotList(0, pSlotList
, &slotcount
)) != CKR_OK
) {
532 cryptoerror(LOG_STDERR
, gettext(
533 "failed to find any cryptographic provider,"
534 "please check with your system administrator: %s"),
535 pkcs11_strerror(rv
));
541 /* Iterate through slots */
542 for (slot
= 0; slot
< slotcount
; slot
++) {
544 /* Iterate through each mechanism */
545 for (mek
= 0; mek
< MECH_ALIASES_COUNT
; mek
++) {
546 rv
= C_GetMechanismInfo(pSlotList
[slot
],
547 mech_aliases
[mek
].type
, &info
);
553 * Set to minimum/maximum key sizes assuming
554 * the values available are not 0.
556 if (info
.ulMinKeySize
&& (info
.ulMinKeySize
<
557 mech_aliases
[mek
].keysize_min
))
558 mech_aliases
[mek
].keysize_min
=
561 if (info
.ulMaxKeySize
&& (info
.ulMaxKeySize
>
562 mech_aliases
[mek
].keysize_max
))
563 mech_aliases
[mek
].keysize_max
=
566 mech_aliases
[mek
].available
= B_TRUE
;
579 * Find a slot with matching mechanism
581 * If -K is specified, we find the slot id for the token first, then
582 * check if the slot supports the algorithm.
586 kmfrv
= kmf_pk11_token_lookup(NULL
, token_label
,
588 if (kmfrv
!= KMF_OK
) {
589 cryptoerror(LOG_STDERR
,
590 gettext("no matching PKCS#11 token"));
594 rv
= C_GetMechanismInfo(token_slot_id
, mech_type
, &info
);
595 if (rv
== CKR_OK
&& (info
.flags
& cmd
->flags
))
596 slotID
= token_slot_id
;
600 for (i
= 0; i
< slotcount
; i
++) {
601 slotID
= pSlotList
[i
];
602 rv
= C_GetMechanismInfo(slotID
, mech_type
, &info
);
604 continue; /* to the next slot */
607 * If the slot support the crypto, also
608 * make sure it supports the correct
609 * key generation mech if needed.
611 * We need PKCS5 when RC4 is used or
612 * when the key is entered on cmd line.
614 if ((info
.flags
& cmd
->flags
) &&
615 (mech_type
== CKM_RC4
) ||
617 rv
= C_GetMechanismInfo(slotID
,
618 CKM_PKCS5_PBKD2
, &kg_info
);
621 } else if (info
.flags
& cmd
->flags
) {
628 /* Show error if no matching mechanism found */
629 if (i
== slotcount
) {
630 cryptoerror(LOG_STDERR
,
631 gettext("no cryptographic provider was "
632 "found for this algorithm -- %s"), algo_str
);
637 rv
= C_OpenSession(slotID
, CKF_SERIAL_SESSION
,
638 NULL_PTR
, NULL
, &hSession
);
641 cryptoerror(LOG_STDERR
,
642 gettext("can not open PKCS #11 session: %s"),
643 pkcs11_strerror(rv
));
648 * Generate IV data for encrypt.
650 ivlen
= mech_aliases
[mech_match
].ivlen
;
651 if ((pivbuf
= malloc((size_t)ivlen
)) == NULL
) {
653 cryptoerror(LOG_STDERR
, gettext("malloc: %s"),
658 if (cmd
->type
== CKA_ENCRYPT
) {
659 if ((pkcs11_get_urandom((void *)pivbuf
,
660 mech_aliases
[mech_match
].ivlen
)) != 0) {
661 cryptoerror(LOG_STDERR
, gettext(
662 "Unable to generate random "
663 "data for initialization vector."));
669 * Create the key object
671 rv
= pkcs11_mech2keytype(mech_type
, &keytype
);
673 cryptoerror(LOG_STDERR
,
674 gettext("unable to find key type for algorithm."));
678 /* Open input file */
680 if ((infd
= open(inputfile
, O_RDONLY
| O_NONBLOCK
)) == -1) {
681 cryptoerror(LOG_STDERR
, gettext(
682 "can not open input file %s"), inputfile
);
686 /* Get info on input file */
687 if (fstat(infd
, &insbuf
) == -1) {
688 cryptoerror(LOG_STDERR
, gettext(
689 "can not stat input file %s"), inputfile
);
695 * Prepare output file
696 * If the input & output file are same,
697 * the output is written to a temp
698 * file first, then renamed to the original file
699 * after the crypt operation
703 outfilename
= outputfile
;
704 if ((stat(outputfile
, &outsbuf
) != -1) &&
705 (insbuf
.st_ino
== outsbuf
.st_ino
)) {
708 /* create temp file on same dir */
709 dir
= dirname(outputfile
);
710 (void) snprintf(tmpnam
, sizeof (tmpnam
),
711 "%s/encrXXXXXX", dir
);
712 outfilename
= tmpnam
;
713 if ((outfd
= mkstemp(tmpnam
)) == -1) {
714 cryptoerror(LOG_STDERR
, gettext(
715 "cannot create temp file"));
720 /* Create file for output */
721 if ((outfd
= open(outfilename
,
722 O_CREAT
|O_WRONLY
|O_TRUNC
, 0644)) == -1) {
723 cryptoerror(LOG_STDERR
, gettext(
724 "cannot open output file %s"),
726 /* Cannot open file, should leave it alone */
727 leavefilealone
= B_TRUE
;
734 * Read the version number from the head of the file
735 * to know how to interpret the data that follows.
737 if (cmd
->type
== CKA_DECRYPT
) {
738 if (read(infd
, &version
, sizeof (version
)) !=
740 cryptoerror(LOG_STDERR
, gettext(
741 "failed to get format version from "
745 /* convert to host byte order */
746 version
= ntohl(version
);
751 * Version 1 output format:
752 * - Output format version 1 (4 bytes)
753 * - Iterations used in key gen function (4 bytes)
754 * - IV ('ivlen' bytes). The length algorithm-dependent
755 * - Salt data used in key gen (16 bytes)
756 * - Cipher text data (remainder of the file)
758 * An encrypted file has IV as first block (0 or
759 * more bytes depending on mechanism) followed
760 * by cipher text. Get the IV from the encrypted
764 * Read iteration count and salt data.
766 if (read(infd
, &iterations
,
767 sizeof (iterations
)) != sizeof (iterations
)) {
768 cryptoerror(LOG_STDERR
, gettext(
769 "failed to get iterations from "
773 /* convert to host byte order */
774 iterations
= ntohl(iterations
);
776 read(infd
, pivbuf
, ivlen
) != ivlen
) {
777 cryptoerror(LOG_STDERR
, gettext(
778 "failed to get initialization "
779 "vector from input file."));
782 if (read(infd
, salt
, sizeof (salt
))
784 cryptoerror(LOG_STDERR
, gettext(
785 "failed to get salt data from "
791 cryptoerror(LOG_STDERR
, gettext(
792 "Unrecognized format version read from "
793 "input file - expected %d, got %d."),
794 SUNW_ENCRYPT_FILE_VERSION
, version
);
800 * If Kflag is set, let's find the token key now.
802 * If Kflag is not set and if encrypting, we need some random
803 * salt data to create the key. If decrypting,
804 * the salt should come from head of the file
808 rv
= get_token_key(hSession
, keytype
, key_label
, pkeydata
,
811 cryptoerror(LOG_STDERR
, gettext(
812 "Can not find the token key"));
817 } else if (cmd
->type
== CKA_ENCRYPT
) {
818 rv
= pkcs11_get_urandom((void *)salt
, sizeof (salt
));
820 cryptoerror(LOG_STDERR
,
821 gettext("unable to generate random "
822 "data for key salt."));
829 * If key input is read from a file, treat it as
830 * raw key data, unless it is to be used with RC4,
831 * in which case it must be used to generate a pkcs5
832 * key to address security concerns with RC4 keys.
834 if (kflag
&& keyfile
!= NULL
&& keytype
!= CKK_RC4
) {
835 /* XXX : why wasn't SUNW_C_KeyToObject used here? */
836 CK_OBJECT_CLASS objclass
= CKO_SECRET_KEY
;
837 CK_ATTRIBUTE
template[5];
840 template[nattr
].type
= CKA_CLASS
;
841 template[nattr
].pValue
= &objclass
;
842 template[nattr
].ulValueLen
= sizeof (objclass
);
845 template[nattr
].type
= CKA_KEY_TYPE
;
846 template[nattr
].pValue
= &keytype
;
847 template[nattr
].ulValueLen
= sizeof (keytype
);
850 template[nattr
].type
= cmd
->type
;
851 template[nattr
].pValue
= &truevalue
;
852 template[nattr
].ulValueLen
= sizeof (truevalue
);
855 template[nattr
].type
= CKA_TOKEN
;
856 template[nattr
].pValue
= &falsevalue
;
857 template[nattr
].ulValueLen
= sizeof (falsevalue
);
860 template[nattr
].type
= CKA_VALUE
;
861 template[nattr
].pValue
= pkeydata
;
862 template[nattr
].ulValueLen
= keysize
;
865 rv
= C_CreateObject(hSession
, template, nattr
, &key
);
868 * If the encryption type has a fixed key length,
869 * then its not necessary to set the key length
870 * parameter when generating the key.
872 if (keytype
== CKK_DES
|| keytype
== CKK_DES3
)
878 * Generate a cryptographically secure key using
879 * the key read from the file given (-k keyfile) or
880 * the passphrase entered by the user.
882 rv
= pkcs11_PasswdToPBKD2Object(hSession
, (char *)pkeydata
,
883 (size_t)keysize
, (void *)salt
, sizeof (salt
), iterations
,
884 keytype
, keylen
, cmd
->flags
, &key
);
888 cryptoerror(LOG_STDERR
, gettext(
889 "failed to generate a key: %s"),
890 pkcs11_strerror(rv
));
896 /* Setup up mechanism */
897 mech
.mechanism
= mech_type
;
898 mech
.pParameter
= (CK_VOID_PTR
)pivbuf
;
899 mech
.ulParameterLen
= ivlen
;
901 if ((rv
= cmd
->Init(hSession
, &mech
, key
)) != CKR_OK
) {
902 cryptoerror(LOG_STDERR
, gettext(
903 "failed to initialize crypto operation: %s"),
904 pkcs11_strerror(rv
));
908 /* Write the version header encrypt command */
909 if (cmd
->type
== CKA_ENCRYPT
) {
910 /* convert to network order for storage */
911 uint32_t netversion
= htonl(version
);
914 if (write(outfd
, &netversion
, sizeof (netversion
))
915 != sizeof (netversion
)) {
916 cryptoerror(LOG_STDERR
, gettext(
917 "failed to write version number "
922 * Write the iteration and salt data, even if they
923 * were not used to generate a key.
925 netiter
= htonl(iterations
);
926 if (write(outfd
, &netiter
,
927 sizeof (netiter
)) != sizeof (netiter
)) {
928 cryptoerror(LOG_STDERR
, gettext(
929 "failed to write iterations to output"));
932 if (ivlen
> 0 && write(outfd
, pivbuf
, ivlen
) != ivlen
) {
933 cryptoerror(LOG_STDERR
, gettext(
934 "failed to write initialization vector "
938 if (write(outfd
, salt
, sizeof (salt
)) != sizeof (salt
)) {
939 cryptoerror(LOG_STDERR
, gettext(
940 "failed to write salt data to output"));
945 if (crypt_multipart(cmd
, hSession
, infd
, outfd
, insbuf
.st_size
) == -1) {
955 /* Clear the key data, so others cannot snoop */
956 if (pkeydata
!= NULL
) {
957 bzero(pkeydata
, keysize
);
962 /* Destroy key object */
963 if (Kflag
!= B_FALSE
&& key
!= (CK_OBJECT_HANDLE
) 0) {
964 (void) C_DestroyObject(hSession
, key
);
967 /* free allocated memory */
968 if (pSlotList
!= NULL
)
973 /* close all the files */
974 if (iflag
&& (infd
!= -1))
976 if (oflag
&& (outfd
!= -1))
979 /* rename tmp output to input file */
981 if (rename(outfilename
, inputfile
) == -1) {
982 (void) unlink(outfilename
);
983 cryptoerror(LOG_STDERR
, gettext("rename failed."));
987 /* If error occurred and the file was new, remove the output file */
988 if (errflag
&& (outfilename
!= NULL
) && !leavefilealone
) {
989 (void) unlink(outfilename
);
992 /* close pkcs11 session */
993 if (hSession
!= CK_INVALID_HANDLE
)
994 (void) C_CloseSession(hSession
);
996 (void) C_Finalize(NULL
);
1002 * Function for printing progress bar when the verbose flag
1005 * The vertical bar is printed at 25, 50, and 75% complete.
1007 * The function is passed the number of positions on the screen it needs to
1008 * advance and loops.
1012 print_status(int pos_to_advance
)
1015 while (pos_to_advance
> 0) {
1016 switch (status_pos
) {
1018 (void) fprintf(stderr
, gettext("["));
1023 (void) fprintf(stderr
, gettext("|"));
1026 (void) fprintf(stderr
, gettext("."));
1034 * Encrypt/Decrypt in multi part.
1036 * This function reads the input file (infd) and writes the
1037 * encrypted/decrypted output to file (outfd).
1039 * cmd - pointing to commandinfo
1040 * hSession - pkcs session
1041 * infd - input file descriptor
1042 * outfd - output file descriptor
1047 crypt_multipart(struct CommandInfo
*cmd
, CK_SESSION_HANDLE hSession
,
1048 int infd
, int outfd
, off_t insize
)
1052 CK_ULONG resultbuflen
;
1053 CK_BYTE_PTR resultbuf
;
1055 CK_BYTE databuf
[BUFFERSIZE
];
1056 CK_BYTE outbuf
[BUFFERSIZE
+BLOCKSIZE
];
1057 CK_ULONG status_index
= 0; /* current total file size read */
1058 float status_last
= 0.0; /* file size of last element used */
1059 float status_incr
= 0.0; /* file size element increments */
1060 int pos
; /* # of progress bar elements to be print */
1062 boolean_t errflag
= B_FALSE
;
1064 datalen
= sizeof (databuf
);
1065 resultbuflen
= sizeof (outbuf
);
1068 /* Divide into 79 increments for progress bar element spacing */
1070 status_incr
= (insize
/ 79.0);
1072 while ((nread
= read(infd
, databuf
, datalen
)) > 0) {
1074 /* Start with the initial buffer */
1075 resultlen
= resultbuflen
;
1076 rv
= cmd
->Update(hSession
, databuf
, (CK_ULONG
)nread
,
1077 resultbuf
, &resultlen
);
1079 /* Need a bigger buffer? */
1080 if (rv
== CKR_BUFFER_TOO_SMALL
) {
1082 /* free the old buffer */
1083 if (resultbuf
!= NULL
&& resultbuf
!= outbuf
) {
1084 bzero(resultbuf
, resultbuflen
);
1088 /* allocate a new big buffer */
1089 if ((resultbuf
= malloc((size_t)resultlen
)) == NULL
) {
1091 cryptoerror(LOG_STDERR
, gettext("malloc: %s"),
1095 resultbuflen
= resultlen
;
1097 /* Try again with bigger buffer */
1098 rv
= cmd
->Update(hSession
, databuf
, (CK_ULONG
)nread
,
1099 resultbuf
, &resultlen
);
1104 cryptoerror(LOG_STDERR
, gettext(
1105 "crypto operation failed: %s"),
1106 pkcs11_strerror(rv
));
1110 /* write the output */
1111 if (write(outfd
, resultbuf
, resultlen
) != resultlen
) {
1112 cryptoerror(LOG_STDERR
, gettext(
1113 "failed to write result to output file."));
1119 status_index
+= resultlen
;
1122 * If input is from stdin, do a our own progress bar
1123 * by printing periods at a pre-defined increment
1124 * until the file is done.
1129 * Print at least 1 element in case the file
1130 * is small, it looks better than nothing.
1132 if (status_pos
== 0) {
1133 (void) fprintf(stderr
, gettext("."));
1137 while ((status_index
- status_last
) >
1139 (void) fprintf(stderr
, gettext("."));
1140 status_last
+= PROGRESSSIZE
;
1145 /* Calculate the number of elements need to be print */
1146 if (insize
<= BUFFERSIZE
)
1149 pos
= (int)((status_index
- status_last
) /
1152 /* Add progress bar elements, if needed */
1155 status_last
+= (status_incr
* pos
);
1160 /* Print verbose completion */
1163 (void) fprintf(stderr
, "]");
1165 (void) fprintf(stderr
, "\n%s\n", gettext("Done."));
1168 /* Error in reading */
1170 cryptoerror(LOG_STDERR
, gettext(
1171 "error reading from input file"));
1177 /* Do the final part */
1179 rv
= cmd
->Final(hSession
, resultbuf
, &resultlen
);
1182 /* write the output */
1183 if (write(outfd
, resultbuf
, resultlen
) != resultlen
) {
1184 cryptoerror(LOG_STDERR
, gettext(
1185 "failed to write result to output file."));
1189 cryptoerror(LOG_STDERR
, gettext(
1190 "crypto operation failed: %s"),
1191 pkcs11_strerror(rv
));
1197 if (resultbuf
!= NULL
&& resultbuf
!= outbuf
) {
1198 bzero(resultbuf
, resultbuflen
);