/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Portions Copyright 2005 Richard Lowe */
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012 Milan Jurik. All rights reserved.
*/
/*
*
* Implements encrypt(1) and decrypt(1) commands
*
*
* Usage:
* -a algorithm mechanism name without CKM_ prefix. Case
* does not matter
* -k keyfile file containing key data. If not specified user is
* prompted to enter key. key length > 0 is required
* if infile & outfile are same, a temp file is used for
* output and infile is replaced with this file after
* operation is complete
* -l Display the list of algorithms
* -v Display verbose information
* -T tokenspec Specify a PKCS#11 token (optionally used with -K)
* -K keylabel Specify the symmetric PKCS#11 token key label
*
* Implementation notes:
* IV data - It is generated by random bytes equal to one block size.
*
* Encrypted output format -
* - Output format version number (1) - 4 bytes in network byte order.
* - Iterations used in key gen function, 4 bytes in network byte order.
* - IV ('ivlen' bytes). Length is algorithm-dependent (see mech_aliases)
* - Salt data used in key gen (16 bytes)
* - Cipher text data (remainder of the file)
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <strings.h>
#include <libintl.h>
#include <libgen.h>
#include <locale.h>
#include <limits.h>
#include <security/cryptoki.h>
#include <cryptoutil.h>
#include <kmfapi.h>
/*
* Buffer size for reading file. This is given a rather high value
* to get better performance when a hardware provider is present.
*/
/*
* Exit Status codes
*/
#ifndef EXIT_SUCCESS
#endif /* EXIT_SUCCESS */
/*
* command
*/
struct CommandInfo {
/* function pointers for various operations */
};
};
};
struct mech_alias {
char *alias;
int keysize_unit;
int ivlen;
};
};
/*
* function prototypes
*/
int
{
extern char *optarg;
extern int optind;
char *optstr;
char c; /* current getopts flag */
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
/*
* Based on command name, determine
* type of command.
*/
cmd = &encrypt_cmd;
cmd = &decrypt_cmd;
} else {
"command name must be either encrypt or decrypt"));
}
/* Parse command line arguments */
switch (c) {
case 'a':
break;
case 'k':
break;
case 'T':
break;
case 'K':
break;
case 'i':
break;
case 'o':
outputfile = optarg;
break;
case 'l':
break;
case 'v':
break;
default:
}
}
}
}
/*
* usage message
*/
static void
{
"[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] "
"[-i <infile>] [-o <outfile>]\n"));
} else {
"[-v] [-k <keyfile> | -K <keylabel> [-T <tokenspec>]] "
"[-i <infile>] [-o <outfile>]\n"));
}
}
/*
* Print out list of algorithms in default and verbose mode
*/
static void
{
int mech;
"------------------------------------------\n"));
continue;
(void) printf(" %5lu %5lu\n",
else
(void) printf("\n");
}
}
/*
* This function will login into the token with the provided password and
* find the token key object with the specified keytype and keylabel.
*/
static int
{
CK_BBOOL true = 1;
int i;
return (-1);
}
i = 0;
i++;
i++;
i++;
i++;
pTmpl[i].ulValueLen = sizeof (true);
i++;
goto out;
}
(void) C_FindObjectsFinal(hSession);
out:
"Cannot retrieve key object. error = %s\n",
return (-1);
}
if (key_obj_count == 0) {
return (-1);
}
return (0);
}
/*
* Execute the command.
* cmd - command pointing to type of operation.
* algo_str - alias of the algorithm passed.
*/
static int
{
int status;
int mech_match = 0;
if (aflag) {
/* Determine if algorithm is valid */
mech_match++) {
break;
}
}
if (mech_match == MECH_ALIASES_COUNT) {
return (EXIT_FAILURE);
}
/*
* Process keyfile or get the token pin if -K is specified.
*
* If a keyfile is provided, get the key data from
* the file. Otherwise, prompt for a passphrase. The
* passphrase is used as the key data.
*/
if (Kflag) {
/* get the pin of the token */
}
} else if (kflag) {
/* get the key file */
} else {
/* get the key from input */
}
gettext("invalid passphrase."));
return (EXIT_FAILURE);
}
}
/* Initialize pkcs */
goto cleanup;
}
/* Get slot count */
"failed to find any cryptographic provider,"
"please check with your system administrator: %s"),
goto cleanup;
}
/* Found at least one slot, allocate memory for slot list */
goto cleanup;
}
/* Get the list of slots */
"failed to find any cryptographic provider,"
"please check with your system administrator: %s"),
goto cleanup;
}
if (lflag) {
/* Iterate through slots */
/* Iterate through each mechanism */
continue;
/*
* the values available are not 0.
*/
}
}
goto cleanup;
}
/*
* Find a slot with matching mechanism
*
* If -K is specified, we find the slot id for the token first, then
* check if the slot supports the algorithm.
*/
i = 0;
if (Kflag) {
gettext("no matching PKCS#11 token"));
goto cleanup;
}
else
i = slotcount;
} else {
for (i = 0; i < slotcount; i++) {
continue; /* to the next slot */
} else {
/*
* If the slot support the crypto, also
* make sure it supports the correct
* key generation mech if needed.
*
* We need PKCS5 when RC4 is used or
* when the key is entered on cmd line.
*/
break;
break;
}
}
}
}
/* Show error if no matching mechanism found */
if (i == slotcount) {
gettext("no cryptographic provider was "
"found for this algorithm -- %s"), algo_str);
goto cleanup;
}
/* Open a session */
gettext("can not open PKCS #11 session: %s"),
goto cleanup;
}
/*
* Generate IV data for encrypt.
*/
goto cleanup;
}
if ((pkcs11_get_urandom((void *)pivbuf,
"Unable to generate random "
"data for initialization vector."));
goto cleanup;
}
}
/*
* Create the key object
*/
gettext("unable to find key type for algorithm."));
goto cleanup;
}
/* Open input file */
if (iflag) {
"can not open input file %s"), inputfile);
goto cleanup;
}
/* Get info on input file */
"can not stat input file %s"), inputfile);
goto cleanup;
}
}
/*
* Prepare output file
* If the input & output file are same,
* the output is written to a temp
* file first, then renamed to the original file
* after the crypt operation
*/
if (oflag) {
char *dir;
/* create temp file on same dir */
"%s/encrXXXXXX", dir);
"cannot create temp file"));
goto cleanup;
}
} else {
/* Create file for output */
"cannot open output file %s"),
/* Cannot open file, should leave it alone */
goto cleanup;
}
}
}
/*
* Read the version number from the head of the file
* to know how to interpret the data that follows.
*/
sizeof (version)) {
"failed to get format version from "
"input file."));
goto cleanup;
}
/* convert to host byte order */
switch (version) {
case 1:
/*
* Version 1 output format:
* - Output format version 1 (4 bytes)
* - Iterations used in key gen function (4 bytes)
* - IV ('ivlen' bytes). The length algorithm-dependent
* - Salt data used in key gen (16 bytes)
* - Cipher text data (remainder of the file)
*
* An encrypted file has IV as first block (0 or
* more bytes depending on mechanism) followed
* by cipher text. Get the IV from the encrypted
* file.
*/
/*
* Read iteration count and salt data.
*/
sizeof (iterations)) != sizeof (iterations)) {
"failed to get iterations from "
"input file."));
goto cleanup;
}
/* convert to host byte order */
if (ivlen > 0 &&
"failed to get initialization "
"vector from input file."));
goto cleanup;
}
!= sizeof (salt)) {
"failed to get salt data from "
"input file."));
goto cleanup;
}
break;
default:
"Unrecognized format version read from "
"input file - expected %d, got %d."),
goto cleanup;
}
}
/*
* If Kflag is set, let's find the token key now.
*
* If Kflag is not set and if encrypting, we need some random
* salt data to create the key. If decrypting,
* the salt should come from head of the file
* to be decrypted.
*/
if (Kflag) {
"Can not find the token key"));
goto cleanup;
} else {
goto do_crypto;
}
if (rv != 0) {
gettext("unable to generate random "
"data for key salt."));
goto cleanup;
}
}
/*
* If key input is read from a file, treat it as
* raw key data, unless it is to be used with RC4,
* in which case it must be used to generate a pkcs5
* key to address security concerns with RC4 keys.
*/
/* XXX : why wasn't SUNW_C_KeyToObject used here? */
int nattr = 0;
nattr++;
nattr++;
nattr++;
nattr++;
nattr++;
} else {
/*
* If the encryption type has a fixed key length,
* then its not necessary to set the key length
* parameter when generating the key.
*/
keylen = 0;
else
keylen = 16;
/*
* Generate a cryptographically secure key using
* the key read from the file given (-k keyfile) or
* the passphrase entered by the user.
*/
}
"failed to generate a key: %s"),
goto cleanup;
}
/* Setup up mechanism */
"failed to initialize crypto operation: %s"),
goto cleanup;
}
/* Write the version header encrypt command */
/* convert to network order for storage */
!= sizeof (netversion)) {
"failed to write version number "
"to output file."));
goto cleanup;
}
/*
* Write the iteration and salt data, even if they
* were not used to generate a key.
*/
"failed to write iterations to output"));
goto cleanup;
}
"failed to write initialization vector "
"to output"));
goto cleanup;
}
"failed to write salt data to output"));
goto cleanup;
}
}
goto cleanup;
}
/*
* Clean up
*/
/* Clear the key data, so others cannot snoop */
}
/* Destroy key object */
}
/* free allocated memory */
/* close all the files */
/* rename tmp output to input file */
if (inoutsame) {
(void) unlink(outfilename);
}
}
/* If error occurred and the file was new, remove the output file */
(void) unlink(outfilename);
}
/* close pkcs11 session */
if (hSession != CK_INVALID_HANDLE)
(void) C_CloseSession(hSession);
(void) C_Finalize(NULL);
return (errflag);
}
/*
* Function for printing progress bar when the verbose flag
* is set.
*
* The vertical bar is printed at 25, 50, and 75% complete.
*
* The function is passed the number of positions on the screen it needs to
* advance and loops.
*/
static void
{
while (pos_to_advance > 0) {
switch (status_pos) {
case 0:
break;
case 19:
case 39:
case 59:
break;
default:
}
status_pos++;
}
}
/*
*
* This function reads the input file (infd) and writes the
*
* cmd - pointing to commandinfo
* hSession - pkcs session
* infd - input file descriptor
* outfd - output file descriptor
*
*/
static int
{
resultbuflen = sizeof (outbuf);
/* Divide into 79 increments for progress bar element spacing */
/* Start with the initial buffer */
/* Need a bigger buffer? */
if (rv == CKR_BUFFER_TOO_SMALL) {
/* free the old buffer */
}
/* allocate a new big buffer */
return (-1);
}
/* Try again with bigger buffer */
}
"crypto operation failed: %s"),
break;
}
/* write the output */
"failed to write result to output file."));
break;
}
if (vflag) {
/*
* If input is from stdin, do a our own progress bar
* by printing periods at a pre-defined increment
* until the file is done.
*/
if (!iflag) {
/*
* Print at least 1 element in case the file
* is small, it looks better than nothing.
*/
if (status_pos == 0) {
status_pos = 1;
}
while ((status_index - status_last) >
(PROGRESSSIZE)) {
}
continue;
}
/* Calculate the number of elements need to be print */
if (insize <= BUFFERSIZE)
pos = 78;
else
/* Add progress bar elements, if needed */
if (pos > 0) {
}
}
}
/* Print verbose completion */
if (vflag) {
if (iflag)
}
/* Error in reading */
if (nread == -1) {
"error reading from input file"));
}
if (!errflag) {
/* Do the final part */
/* write the output */
"failed to write result to output file."));
}
} else {
"crypto operation failed: %s"),
}
}
}
if (errflag) {
return (-1);
} else {
return (0);
}
}