/*
* 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
*/
/*
*/
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <security/cryptoki.h>
#include <des_impl.h>
#include "softSession.h"
#include "softObject.h"
#include "softCrypt.h"
#include "softOps.h"
/*
* Allocate context for the active encryption or decryption operation, and
* generate DES or DES3 key schedule to speed up the operation.
*/
{
if (soft_des_ctx == NULL) {
return (CKR_HOST_MEMORY);
}
/* Allocate key schedule for DES or DES3 based on key type. */
else
return (CKR_HOST_MEMORY);
}
if (encrypt) {
/* Called by C_EncryptInit. */
} else {
/* Called by C_DecryptInit. */
}
/*
* If this is a non-sensitive key and it does NOT have
* a key schedule yet, then allocate one and expand it.
* Otherwise, if its a non-sensitive key, and it DOES have
* a key schedule already attached to it, just copy the
* pre-expanded schedule to the context and avoid the
* extra key schedule expansion operation.
*/
void *ks;
else
(void) pthread_mutex_unlock(
&key_p->object_mutex);
return (CKR_HOST_MEMORY);
}
/* Initialize key schedule for DES or DES3. */
/*
* DES3 encryption/decryption needs to
* support a DES2 key.
*/
else
}
}
/* Copy the pre-expanded key schedule from the key object */
} else {
/* for sensitive keys, we cannot cache the key schedule */
/*
* DES3 encryption/decryption needs to
* support a DES2 key.
*/
else
}
return (CKR_OK);
}
/*
* soft_des_encrypt_common()
*
* Arguments:
* session_p: pointer to soft_session_t struct
* pData: pointer to the input data to be encrypted
* ulDataLen: length of the input data
* pEncrypted: pointer to the output data after encryption
* pulEncryptedLen: pointer to the length of the output data
* update: boolean flag indicates caller is soft_encrypt
* or soft_encrypt_update
*
* Description:
* This function calls the corresponding encrypt routine based
* on the mechanism.
*
* Returns:
* CKR_OK: success
* CKR_BUFFER_TOO_SMALL: the output buffer provided by application
* is too small
* CKR_FUNCTION_FAILED: encrypt function failed
* CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
*/
{
int rc = 0;
/*
* DES only takes input length that is a multiple of blocksize
* for C_Encrypt function with the mechanism CKM_DES<n>_ECB or
* CKM_DES<n>_CBC.
*
* DES allows any input length for C_Encrypt function with the
* mechanism CKM_DES<n>_CBC_PAD and for C_EncryptUpdate function.
*/
if (!update && !pad_mechanism) {
if ((ulDataLen % DES_BLOCK_LEN) != 0) {
goto cleanup;
}
}
if (!update) {
/*
* Called by C_Encrypt
*/
if (pad_mechanism) {
/*
* For CKM_DES<n>_CBC_PAD, compute output length to
* count for the padding. If the length of input
* data is a multiple of blocksize, then make output
* length to be the sum of the input length and
* one blocksize. Otherwise, output length will
* be rounded up to the next multiple of blocksize.
*/
out_len = DES_BLOCK_LEN *
} else {
/*
* For non-padding mode, the output length will
* be same as the input length.
*/
}
/*
* If application asks for the length of the output buffer
* to hold the ciphertext?
*/
if (pEncrypted == NULL) {
return (CKR_OK);
}
/* Is the application-supplied buffer large enough? */
if (*pulEncryptedLen < out_len) {
return (CKR_BUFFER_TOO_SMALL);
}
/* Encrypt pad bytes in a separate operation */
if (pad_mechanism) {
out_len -= DES_BLOCK_LEN;
}
} else {
/*
* Called by C_EncryptUpdate
*
* Add the lengths of last remaining data and current
* plaintext together to get the total input length.
*/
/*
* If the total input length is less than one blocksize,
* or if the total input length is just one blocksize and
* the mechanism is CKM_DES<n>_CBC_PAD, we will need to delay
* encryption until when more data comes in next
* C_EncryptUpdate or when C_EncryptFinal is called.
*/
if ((total_len < DES_BLOCK_LEN) ||
/*
* Save input data and its length in
* the remaining buffer of DES context.
*/
}
/* Set encrypted data length to 0. */
*pulEncryptedLen = 0;
return (CKR_OK);
}
/* Compute the length of remaing data. */
/*
* Make sure that the output length is a multiple of
* blocksize.
*/
/*
* If application asks for the length of the output buffer
* to hold the ciphertext?
*/
if (pEncrypted == NULL) {
return (CKR_OK);
}
/* Is the application-supplied buffer large enough? */
if (*pulEncryptedLen < out_len) {
return (CKR_BUFFER_TOO_SMALL);
}
if (soft_des_ctx->remain_len != 0) {
/*
* Copy last remaining data and current input data
* to the output buffer.
*/
in_buf = pEncrypted;
} else {
}
}
/*
* Begin Encryption now.
*/
switch (mechanism) {
case CKM_DES_ECB:
case CKM_DES3_ECB:
{
ulong_t i;
for (i = 0; i < out_len; i += DES_BLOCK_LEN) {
tmp_outbuf = &out_buf[i];
/* Crunch one block of data for DES. */
(void) des_crunch_block(
else
(void) des3_crunch_block(
}
if (update) {
/*
* For encrypt update, if there is remaining
* data, save it and its length in the context.
*/
if (remain != 0)
}
break;
}
case CKM_DES_CBC:
case CKM_DES_CBC_PAD:
case CKM_DES3_CBC:
case CKM_DES3_CBC_PAD:
{
/* Encrypt multiple blocks of data. */
if (rc != 0)
goto encrypt_failed;
if (update) {
/*
* For encrypt update, if there is remaining data,
* save it and its length in the context.
*/
if (remain != 0)
} else if (pad_mechanism) {
/*
* Save the remainder of the input
* block in a temporary block because
* we don't want to overrun the input buffer
* by tacking on pad bytes.
*/
/* Encrypt last block containing pad bytes. */
out_len += DES_BLOCK_LEN;
}
if (rc == 0) {
break;
}
*pulEncryptedLen = 0;
goto cleanup;
}
} /* end switch */
if (update)
return (CKR_OK);
/*
* The following code will be executed if the caller is
* soft_encrypt() or an error occurred. The encryption
* operation will be terminated so we need to do some cleanup.
*/
}
return (rv);
}
/*
* soft_des_decrypt_common()
*
* Arguments:
* session_p: pointer to soft_session_t struct
* pEncrypted: pointer to the input data to be decrypted
* ulEncryptedLen: length of the input data
* pData: pointer to the output data
* pulDataLen: pointer to the length of the output data
* Update: boolean flag indicates caller is soft_decrypt
* or soft_decrypt_update
*
* Description:
* This function calls the corresponding decrypt routine based
* on the mechanism.
*
* Returns:
* CKR_OK: success
* CKR_BUFFER_TOO_SMALL: the output buffer provided by application
* is too small
* CKR_ENCRYPTED_DATA_LEN_RANGE: the input data is not a multiple
* of blocksize
* CKR_FUNCTION_FAILED: decrypt function failed
*/
{
int rc = 0;
/*
* DES only takes input length that is a multiple of 8 bytes
* for C_Decrypt function with the mechanism CKM_DES<n>_ECB,
* CKM_DES<n>_CBC or CKM_DES<n>_CBC_PAD.
*
* DES allows any input length for C_DecryptUpdate function.
*/
if (!update) {
/*
* Called by C_Decrypt
*/
if ((ulEncryptedLen % DES_BLOCK_LEN) != 0) {
goto cleanup;
}
/*
* If application asks for the length of the output buffer
* to hold the plaintext?
*/
return (CKR_OK);
}
/* Is the application-supplied buffer large enough? */
if (!pad_mechanism) {
if (*pulDataLen < ulEncryptedLen) {
return (CKR_BUFFER_TOO_SMALL);
}
/* Set output length same as input length. */
} else {
/*
* For CKM_DES<n>_CBC_PAD, we don't know how
* many bytes for padding at this time, so
* we'd assume one block was padded.
*/
return (CKR_BUFFER_TOO_SMALL);
}
}
in_buf = pEncrypted;
} else {
/*
* Called by C_DecryptUpdate
*
* Add the lengths of last remaining data and current
* input data together to get the total input length.
*/
/*
* If the total input length is less than one blocksize,
* or if the total input length is just one blocksize and
* the mechanism is CKM_DES<n>_CBC_PAD, we will need to delay
* decryption until when more data comes in next
* C_DecryptUpdate or when C_DecryptFinal is called.
*/
if ((total_len < DES_BLOCK_LEN) ||
if (pEncrypted != NULL) {
/*
* Save input data and its length in
* the remaining buffer of DES context.
*/
}
/* Set output data length to 0. */
*pulDataLen = 0;
return (CKR_OK);
}
/* Compute the length of remaing data. */
/*
* Make sure that the output length is a multiple of
* blocksize.
*/
if (pad_mechanism) {
/*
* If the input data length is a multiple of
* blocksize, then save the last block of input
* data in the remaining buffer. C_DecryptFinal
* will handle this last block of data.
*/
if (remain == 0) {
out_len -= DES_BLOCK_LEN;
}
}
/*
* If application asks for the length of the output buffer
* to hold the plaintext?
*/
*pulDataLen = out_len;
return (CKR_OK);
}
/*
* Is the application-supplied buffer large enough?
*/
if (*pulDataLen < out_len) {
*pulDataLen = out_len;
return (CKR_BUFFER_TOO_SMALL);
}
if (soft_des_ctx->remain_len != 0) {
/*
* Copy last remaining data and current input data
* to the output buffer.
*/
} else {
in_buf = pEncrypted;
}
}
/*
* Begin Decryption.
*/
switch (mechanism) {
case CKM_DES_ECB:
case CKM_DES3_ECB:
{
ulong_t i;
for (i = 0; i < out_len; i += DES_BLOCK_LEN) {
tmp_outbuf = &out_buf[i];
/* Crunch one block of data for DES. */
(void) des_crunch_block(
else
(void) des3_crunch_block(
}
if (update) {
/*
* For decrypt update, if there is remaining
* data, save it and its length in the context.
*/
if (remain != 0)
}
*pulDataLen = out_len;
break;
}
case CKM_DES_CBC:
case CKM_DES_CBC_PAD:
case CKM_DES3_CBC:
case CKM_DES3_CBC_PAD:
{
/* Decrypt multiple blocks of data. */
if (rc != 0)
goto decrypt_failed;
if (pad_mechanism && !update) {
/* Decrypt last block containing pad bytes. */
/* Decrypt last block containing pad bytes. */
if (rc != 0)
goto decrypt_failed;
/*
* Remove padding bytes after decryption of
* ciphertext block to produce the original
* plaintext.
*/
DES_BLOCK_LEN, &rem_len);
if (rem_len != 0)
} else {
*pulDataLen = 0;
goto cleanup;
}
} else {
*pulDataLen = out_len;
}
if (update) {
/*
* For decrypt update, if there is remaining data,
* save it and its length in the context.
*/
if (remain != 0)
}
if (rc == 0)
break;
*pulDataLen = 0;
goto cleanup;
}
} /* end switch */
if (update)
return (CKR_OK);
/*
* The following code will be executed if the caller is
* soft_decrypt() or an error occurred. The decryption
* operation will be terminated so we need to do some cleanup.
*/
}
return (rv);
}
/*
* Allocate and initialize a context for DES CBC mode of operation.
*/
void *
{
return (NULL);
else
return (cbc_ctx);
}
/*
* Allocate and initialize DES contexts for both signing and encrypting,
* saving both context pointers in the session struct. For general-length DES
* MAC, check the length in the parameter to see if it is in the right range.
*/
{
return (CKR_KEY_TYPE_INCONSISTENT);
}
if (soft_des_ctx == NULL) {
return (CKR_HOST_MEMORY);
}
/* initialization vector is zero for DES MAC */
switch (pMechanism->mechanism) {
case CKM_DES_MAC_GENERAL:
if (pMechanism->ulParameterLen !=
sizeof (CK_MAC_GENERAL_PARAMS)) {
return (CKR_MECHANISM_PARAM_INVALID);
}
return (CKR_MECHANISM_PARAM_INVALID);
}
/*FALLTHRU*/
case CKM_DES_MAC:
/*
* For non-general DES MAC, output is always half as
* large as block size
*/
}
/* allocate a context for DES encryption */
key_p);
return (rv);
}
if (sign_op) {
} else {
}
break;
}
return (CKR_OK);
}
/*
* Called by soft_sign(), soft_sign_final(), soft_verify() or
* soft_verify_final().
*/
{
if (sign_op) {
if (soft_des_ctx_sign_verify->mac_len == 0) {
*pulSignedLen = 0;
goto clean_exit;
}
/* Application asks for the length of the output buffer. */
return (CKR_OK);
}
/* Is the application-supplied buffer large enough? */
return (CKR_BUFFER_TOO_SMALL);
}
} else {
}
if (Final) {
/*
* If there is data left in the buffer from a previous
* SignUpdate() call, pass enough zeroed data to a
* soft_sign_update call to pad the remainder
*/
if (soft_des_ctx_encrypt->remain_len != 0) {
/*
* By passing a buffer to soft_encrypt_final,
* we force it to pad the remaining block
* and encrypt it.
*/
goto clean_exit;
}
} else {
/*
* The last block of enciphered data is stored in:
* soft_des_ctx_encrypt->des_cbc->des_ctx->dc_lastp
* Copy that data to last_block
*/
/*
* Passing a NULL output buffer here
* forces the routine to just return.
*/
}
} else {
/*
* If the input length is not multiple of block size, then
* determine the correct encrypted data length by rounding
*/
/*
* Because we always use DES_CBC_PAD mechanism
* be padded to the next 8 byte boundary.
* Adjust the length fields here accordingly.
*/
if (pEncrypted == NULL) {
goto clean_exit;
}
/*
* Pad the last block with zeros by copying pData into a zeroed
* pEncrypted. Then pass pEncrypted into soft_encrypt as input
*/
(void) memcpy(last_block,
}
/* the leftmost mac_len bytes of last_block is our MAC */
}
/* soft_encrypt_common() has freed the encrypt context */
if (sign_op) {
} else {
}
if (pEncrypted) {
}
return (rv);
}
/*
* Called by soft_sign_update()
*/
{
/*
* The DES MAC is calculated by taking the specified number of
* left-most bytes within the last block of
* encrypted data, while the context of the multi-part
* encryption stores the block necessary for XORing with the
* input as per cipher block chaining . Therefore, none of the
* intermediary encrypted blocks of data are necessary for
* the DES MAC, and we can create a placeholder local buffer
* for the encrypted data, which is immediately throw away.
*/
/* Avoid the malloc if we won't be encrypting any data */
if (total_len < DES_BLOCK_LEN) {
} else {
/* round up to the nearest multiple of block size */
if (pEncrypted != NULL) {
} else {
}
}
return (rv);
}