#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <modes/modes.h>
#include <arcfour.h>
#include "softSession.h"
#include "softObject.h"
#include "softOps.h"
#include "softCrypt.h"
#include "softRSA.h"
CK_RV
soft_remove_pkcs7_padding(CK_BYTE *pData, CK_ULONG padded_len,
CK_ULONG *pulDataLen)
{
CK_RV rv;
#ifdef __sparcv9
if ((rv = pkcs7_decode(pData, (&padded_len))) != CKR_OK)
#else
if ((rv = pkcs7_decode(pData, (size_t *)(&padded_len))) != CKR_OK)
#endif
return (rv);
*pulDataLen = padded_len;
return (CKR_OK);
}
CK_RV
soft_decrypt_init(soft_session_t *session_p, CK_MECHANISM_PTR pMechanism,
soft_object_t *key_p)
{
CK_RV rv;
switch (pMechanism->mechanism) {
case CKM_DES_ECB:
if (key_p->key_type != CKK_DES) {
return (CKR_KEY_TYPE_INCONSISTENT);
}
goto ecb_common;
case CKM_DES3_ECB:
if ((key_p->key_type != CKK_DES2) &&
(key_p->key_type != CKK_DES3)) {
return (CKR_KEY_TYPE_INCONSISTENT);
}
ecb_common:
return (soft_des_crypt_init_common(session_p, pMechanism,
key_p, B_FALSE));
case CKM_DES_CBC:
case CKM_DES_CBC_PAD:
if (key_p->key_type != CKK_DES) {
return (CKR_KEY_TYPE_INCONSISTENT);
}
goto cbc_common;
case CKM_DES3_CBC:
case CKM_DES3_CBC_PAD:
{
soft_des_ctx_t *soft_des_ctx;
if ((key_p->key_type != CKK_DES2) &&
(key_p->key_type != CKK_DES3)) {
return (CKR_KEY_TYPE_INCONSISTENT);
}
cbc_common:
if ((pMechanism->pParameter == NULL) ||
(pMechanism->ulParameterLen != DES_BLOCK_LEN)) {
return (CKR_MECHANISM_PARAM_INVALID);
}
rv = soft_des_crypt_init_common(session_p, pMechanism,
key_p, B_FALSE);
if (rv != CKR_OK)
return (rv);
(void) pthread_mutex_lock(&session_p->session_mutex);
soft_des_ctx = (soft_des_ctx_t *)session_p->decrypt.context;
(void) memcpy(soft_des_ctx->ivec, pMechanism->pParameter,
DES_BLOCK_LEN);
soft_des_ctx->des_cbc = (void *)des_cbc_ctx_init(
soft_des_ctx->key_sched, soft_des_ctx->keysched_len,
soft_des_ctx->ivec, key_p->key_type);
if (soft_des_ctx->des_cbc == NULL) {
freezero(soft_des_ctx->key_sched,
soft_des_ctx->keysched_len);
freezero(session_p->decrypt.context,
sizeof (soft_des_ctx_t));
session_p->decrypt.context = NULL;
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (CKR_HOST_MEMORY);
}
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (rv);
}
case CKM_AES_ECB:
case CKM_AES_CBC:
case CKM_AES_CBC_PAD:
case CKM_AES_CTR:
case CKM_AES_CCM:
case CKM_AES_GCM:
case CKM_AES_GMAC:
return (soft_aes_crypt_init_common(session_p, pMechanism,
key_p, B_FALSE));
case CKM_BLOWFISH_CBC:
{
soft_blowfish_ctx_t *soft_blowfish_ctx;
if (key_p->key_type != CKK_BLOWFISH)
return (CKR_KEY_TYPE_INCONSISTENT);
if ((pMechanism->pParameter == NULL) ||
(pMechanism->ulParameterLen != BLOWFISH_BLOCK_LEN))
return (CKR_MECHANISM_PARAM_INVALID);
rv = soft_blowfish_crypt_init_common(session_p, pMechanism,
key_p, B_FALSE);
if (rv != CKR_OK)
return (rv);
(void) pthread_mutex_lock(&session_p->session_mutex);
soft_blowfish_ctx =
(soft_blowfish_ctx_t *)session_p->decrypt.context;
(void) memcpy(soft_blowfish_ctx->ivec, pMechanism->pParameter,
BLOWFISH_BLOCK_LEN);
soft_blowfish_ctx->blowfish_cbc =
(void *)blowfish_cbc_ctx_init(soft_blowfish_ctx->key_sched,
soft_blowfish_ctx->keysched_len,
soft_blowfish_ctx->ivec);
if (soft_blowfish_ctx->blowfish_cbc == NULL) {
freezero(soft_blowfish_ctx->key_sched,
soft_blowfish_ctx->keysched_len);
freezero(session_p->decrypt.context,
sizeof (soft_blowfish_ctx_t));
session_p->decrypt.context = NULL;
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (CKR_HOST_MEMORY);
}
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (rv);
}
case CKM_RC4:
if (key_p->key_type != CKK_RC4) {
return (CKR_KEY_TYPE_INCONSISTENT);
}
return (soft_arcfour_crypt_init(session_p, pMechanism, key_p,
B_FALSE));
case CKM_RSA_X_509:
case CKM_RSA_PKCS:
if (key_p->key_type != CKK_RSA) {
return (CKR_KEY_TYPE_INCONSISTENT);
}
return (soft_rsa_crypt_init_common(session_p, pMechanism,
key_p, B_FALSE));
default:
return (CKR_MECHANISM_INVALID);
}
}
CK_RV
soft_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted,
CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData,
CK_ULONG_PTR pulDataLen, boolean_t Update)
{
CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
switch (mechanism) {
case CKM_DES_ECB:
case CKM_DES_CBC:
case CKM_DES3_ECB:
case CKM_DES3_CBC:
if (ulEncryptedLen == 0) {
*pulDataLen = 0;
return (CKR_OK);
}
case CKM_DES_CBC_PAD:
case CKM_DES3_CBC_PAD:
return (soft_des_decrypt_common(session_p, pEncrypted,
ulEncryptedLen, pData, pulDataLen, Update));
case CKM_AES_ECB:
case CKM_AES_CBC:
case CKM_AES_CBC_PAD:
case CKM_AES_CTR:
case CKM_AES_CCM:
case CKM_AES_GCM:
case CKM_AES_GMAC:
if (Update) {
return (soft_aes_decrypt_update(session_p, pEncrypted,
ulEncryptedLen, pData, pulDataLen));
} else {
return (soft_aes_decrypt(session_p, pEncrypted,
ulEncryptedLen, pData, pulDataLen));
}
case CKM_BLOWFISH_CBC:
if (ulEncryptedLen == 0) {
*pulDataLen = 0;
return (CKR_OK);
}
return (soft_blowfish_decrypt_common(session_p, pEncrypted,
ulEncryptedLen, pData, pulDataLen, Update));
case CKM_RC4:
if (ulEncryptedLen == 0) {
*pulDataLen = 0;
return (CKR_OK);
}
return (soft_arcfour_crypt(&(session_p->decrypt), pEncrypted,
ulEncryptedLen, pData, pulDataLen));
case CKM_RSA_X_509:
case CKM_RSA_PKCS:
return (soft_rsa_decrypt_common(session_p, pEncrypted,
ulEncryptedLen, pData, pulDataLen, mechanism));
default:
return (CKR_MECHANISM_INVALID);
}
}
CK_RV
soft_decrypt(soft_session_t *session_p, CK_BYTE_PTR pEncryptedData,
CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData,
CK_ULONG_PTR pulDataLen)
{
return (soft_decrypt_common(session_p, pEncryptedData,
ulEncryptedDataLen, pData, pulDataLen, B_FALSE));
}
CK_RV
soft_decrypt_update(soft_session_t *session_p, CK_BYTE_PTR pEncryptedPart,
CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen)
{
CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
switch (mechanism) {
case CKM_DES_ECB:
case CKM_DES_CBC:
case CKM_DES_CBC_PAD:
case CKM_DES3_ECB:
case CKM_DES3_CBC:
case CKM_DES3_CBC_PAD:
case CKM_AES_ECB:
case CKM_AES_CBC:
case CKM_AES_CBC_PAD:
case CKM_AES_CTR:
case CKM_AES_CCM:
case CKM_AES_GCM:
case CKM_AES_GMAC:
case CKM_BLOWFISH_CBC:
case CKM_RC4:
return (soft_decrypt_common(session_p, pEncryptedPart,
ulEncryptedPartLen, pPart, pulPartLen, B_TRUE));
default:
return (CKR_MECHANISM_INVALID);
}
}
CK_RV
soft_decrypt_final(soft_session_t *session_p, CK_BYTE_PTR pLastPart,
CK_ULONG_PTR pulLastPartLen)
{
CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
CK_ULONG out_len;
CK_RV rv = CKR_OK;
int rc;
(void) pthread_mutex_lock(&session_p->session_mutex);
if (session_p->decrypt.context == NULL) {
rv = CKR_OPERATION_NOT_INITIALIZED;
*pulLastPartLen = 0;
goto clean2;
}
switch (mechanism) {
case CKM_DES_CBC_PAD:
case CKM_DES3_CBC_PAD:
{
soft_des_ctx_t *soft_des_ctx;
soft_des_ctx = (soft_des_ctx_t *)session_p->decrypt.context;
if (soft_des_ctx->remain_len != DES_BLOCK_LEN) {
*pulLastPartLen = 0;
rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
free(soft_des_ctx->des_cbc);
freezero(soft_des_ctx->key_sched,
soft_des_ctx->keysched_len);
goto clean1;
}
out_len = DES_BLOCK_LEN;
if (pLastPart == NULL) {
*pulLastPartLen = out_len;
rv = CKR_OK;
goto clean2;
} else {
crypto_data_t out;
(void) memcpy(pLastPart, soft_des_ctx->data,
DES_BLOCK_LEN);
out.cd_format = CRYPTO_DATA_RAW;
out.cd_offset = 0;
out.cd_length = DES_BLOCK_LEN;
out.cd_raw.iov_base = (char *)pLastPart;
out.cd_raw.iov_len = DES_BLOCK_LEN;
rc = des_decrypt_contiguous_blocks(
(des_ctx_t *)soft_des_ctx->des_cbc,
(char *)pLastPart, DES_BLOCK_LEN, &out);
if (rc == 0) {
rv = soft_remove_pkcs7_padding(pLastPart,
DES_BLOCK_LEN, &out_len);
if (rv != CKR_OK)
*pulLastPartLen = 0;
else
*pulLastPartLen = out_len;
} else {
*pulLastPartLen = 0;
rv = CKR_FUNCTION_FAILED;
}
free(soft_des_ctx->des_cbc);
freezero(soft_des_ctx->key_sched,
soft_des_ctx->keysched_len);
}
break;
}
case CKM_DES_CBC:
case CKM_DES_ECB:
case CKM_DES3_CBC:
case CKM_DES3_ECB:
{
soft_des_ctx_t *soft_des_ctx;
soft_des_ctx = (soft_des_ctx_t *)session_p->decrypt.context;
*pulLastPartLen = 0;
if (soft_des_ctx->remain_len != 0) {
rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
} else {
if (pLastPart == NULL)
goto clean2;
}
free(soft_des_ctx->des_cbc);
freezero(soft_des_ctx->key_sched,
soft_des_ctx->keysched_len);
break;
}
case CKM_AES_CBC_PAD:
case CKM_AES_CBC:
case CKM_AES_ECB:
case CKM_AES_CTR:
case CKM_AES_CCM:
case CKM_AES_GCM:
case CKM_AES_GMAC:
rv = soft_aes_decrypt_final(session_p, pLastPart,
pulLastPartLen);
break;
case CKM_BLOWFISH_CBC:
{
soft_blowfish_ctx_t *soft_blowfish_ctx;
soft_blowfish_ctx =
(soft_blowfish_ctx_t *)session_p->decrypt.context;
*pulLastPartLen = 0;
if (soft_blowfish_ctx->remain_len != 0)
rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
else {
if (pLastPart == NULL)
goto clean2;
}
free(soft_blowfish_ctx->blowfish_cbc);
freezero(soft_blowfish_ctx->key_sched,
soft_blowfish_ctx->keysched_len);
break;
}
case CKM_RC4:
{
ARCFour_key *key = (ARCFour_key *)session_p->decrypt.context;
explicit_bzero(key, sizeof (*key));
*pulLastPartLen = 0;
break;
}
default:
rv = CKR_MECHANISM_INVALID;
break;
}
clean1:
free(session_p->decrypt.context);
session_p->decrypt.context = NULL;
clean2:
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (rv);
}