#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 <des_impl.h>
#include "softSession.h"
#include "softObject.h"
#include "softCrypt.h"
#include "softOps.h"
CK_RV
soft_des_crypt_init_common(soft_session_t *session_p,
CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
boolean_t encrypt)
{
size_t size;
soft_des_ctx_t *soft_des_ctx;
soft_des_ctx = calloc(1, sizeof (soft_des_ctx_t));
if (soft_des_ctx == NULL) {
return (CKR_HOST_MEMORY);
}
if (key_p->key_type == CKK_DES)
soft_des_ctx->key_sched = des_alloc_keysched(&size, DES, 0);
else
soft_des_ctx->key_sched = des_alloc_keysched(&size, DES3, 0);
if (soft_des_ctx->key_sched == NULL) {
free(soft_des_ctx);
return (CKR_HOST_MEMORY);
}
soft_des_ctx->keysched_len = size;
soft_des_ctx->key_type = key_p->key_type;
(void) pthread_mutex_lock(&session_p->session_mutex);
if (encrypt) {
session_p->encrypt.context = soft_des_ctx;
session_p->encrypt.mech.mechanism = pMechanism->mechanism;
} else {
session_p->decrypt.context = soft_des_ctx;
session_p->decrypt.mech.mechanism = pMechanism->mechanism;
}
(void) pthread_mutex_unlock(&session_p->session_mutex);
if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
if (OBJ_KEY_SCHED(key_p) == NULL) {
void *ks;
(void) pthread_mutex_lock(&key_p->object_mutex);
if (OBJ_KEY_SCHED(key_p) == NULL) {
if (key_p->key_type == CKK_DES)
ks = des_alloc_keysched(&size, DES, 0);
else
ks = des_alloc_keysched(&size, DES3, 0);
if (ks == NULL) {
(void) pthread_mutex_unlock(
&key_p->object_mutex);
free(soft_des_ctx);
return (CKR_HOST_MEMORY);
}
if (key_p->key_type == CKK_DES)
des_init_keysched(
OBJ_SEC(key_p)->sk_value, DES, ks);
else if (key_p->key_type == CKK_DES2)
des_init_keysched(
OBJ_SEC(key_p)->sk_value, DES2, ks);
else
des_init_keysched(
OBJ_SEC(key_p)->sk_value, DES3, ks);
OBJ_KEY_SCHED_LEN(key_p) = size;
OBJ_KEY_SCHED(key_p) = ks;
}
(void) pthread_mutex_unlock(&key_p->object_mutex);
}
(void) memcpy(soft_des_ctx->key_sched, OBJ_KEY_SCHED(key_p),
OBJ_KEY_SCHED_LEN(key_p));
soft_des_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
} else {
if (key_p->key_type == CKK_DES)
des_init_keysched(OBJ_SEC(key_p)->sk_value,
DES, soft_des_ctx->key_sched);
else if (key_p->key_type == CKK_DES2)
des_init_keysched(OBJ_SEC(key_p)->sk_value,
DES2, soft_des_ctx->key_sched);
else
des_init_keysched(OBJ_SEC(key_p)->sk_value,
DES3, soft_des_ctx->key_sched);
}
return (CKR_OK);
}
CK_RV
soft_des_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted,
CK_ULONG_PTR pulEncryptedLen, boolean_t update)
{
int rc = 0;
CK_RV rv = CKR_OK;
soft_des_ctx_t *soft_des_ctx =
(soft_des_ctx_t *)session_p->encrypt.context;
des_ctx_t *des_ctx;
CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
CK_BYTE *in_buf = NULL;
CK_BYTE *out_buf = NULL;
CK_ULONG out_len;
CK_ULONG total_len;
CK_ULONG remain;
boolean_t pad_mechanism = B_FALSE;
pad_mechanism = (mechanism == CKM_DES_CBC_PAD ||
mechanism == CKM_DES3_CBC_PAD);
if (!update && !pad_mechanism) {
if ((ulDataLen % DES_BLOCK_LEN) != 0) {
rv = CKR_DATA_LEN_RANGE;
goto cleanup;
}
}
if (!update) {
if (pad_mechanism) {
out_len = DES_BLOCK_LEN *
(ulDataLen / DES_BLOCK_LEN + 1);
} else {
out_len = ulDataLen;
}
if (pEncrypted == NULL) {
*pulEncryptedLen = out_len;
return (CKR_OK);
}
if (*pulEncryptedLen < out_len) {
*pulEncryptedLen = out_len;
return (CKR_BUFFER_TOO_SMALL);
}
if (pad_mechanism) {
out_len -= DES_BLOCK_LEN;
}
in_buf = pData;
out_buf = pEncrypted;
} else {
total_len = soft_des_ctx->remain_len + ulDataLen;
if ((total_len < DES_BLOCK_LEN) ||
(pad_mechanism && (total_len == DES_BLOCK_LEN))) {
if (pData != NULL) {
(void) memcpy(soft_des_ctx->data +
soft_des_ctx->remain_len, pData, ulDataLen);
soft_des_ctx->remain_len += ulDataLen;
}
*pulEncryptedLen = 0;
return (CKR_OK);
}
remain = total_len % DES_BLOCK_LEN;
out_len = total_len - remain;
if (pEncrypted == NULL) {
*pulEncryptedLen = out_len;
return (CKR_OK);
}
if (*pulEncryptedLen < out_len) {
*pulEncryptedLen = out_len;
return (CKR_BUFFER_TOO_SMALL);
}
if (soft_des_ctx->remain_len != 0) {
(void) memmove(pEncrypted + soft_des_ctx->remain_len,
pData, out_len - soft_des_ctx->remain_len);
(void) memcpy(pEncrypted, soft_des_ctx->data,
soft_des_ctx->remain_len);
bzero(soft_des_ctx->data, soft_des_ctx->remain_len);
in_buf = pEncrypted;
} else {
in_buf = pData;
}
out_buf = pEncrypted;
}
switch (mechanism) {
case CKM_DES_ECB:
case CKM_DES3_ECB:
{
ulong_t i;
uint8_t *tmp_inbuf;
uint8_t *tmp_outbuf;
for (i = 0; i < out_len; i += DES_BLOCK_LEN) {
tmp_inbuf = &in_buf[i];
tmp_outbuf = &out_buf[i];
if (soft_des_ctx->key_type == CKK_DES)
(void) des_crunch_block(
soft_des_ctx->key_sched,
tmp_inbuf, tmp_outbuf, B_FALSE);
else
(void) des3_crunch_block(
soft_des_ctx->key_sched,
tmp_inbuf, tmp_outbuf, B_FALSE);
}
if (update) {
if (remain != 0)
(void) memcpy(soft_des_ctx->data, pData +
(ulDataLen - remain), remain);
soft_des_ctx->remain_len = remain;
}
*pulEncryptedLen = out_len;
break;
}
case CKM_DES_CBC:
case CKM_DES_CBC_PAD:
case CKM_DES3_CBC:
case CKM_DES3_CBC_PAD:
{
crypto_data_t out;
out.cd_format = CRYPTO_DATA_RAW;
out.cd_offset = 0;
out.cd_length = out_len;
out.cd_raw.iov_base = (char *)out_buf;
out.cd_raw.iov_len = out_len;
rc = des_encrypt_contiguous_blocks(
(des_ctx_t *)soft_des_ctx->des_cbc,
(char *)in_buf, out_len, &out);
if (rc != 0)
goto encrypt_failed;
if (update) {
if (remain != 0)
(void) memcpy(soft_des_ctx->data, pData +
(ulDataLen - remain), remain);
soft_des_ctx->remain_len = remain;
} else if (pad_mechanism) {
CK_BYTE tmpblock[DES_BLOCK_LEN];
(void) memcpy(tmpblock, in_buf + out_len,
ulDataLen - out_len);
soft_add_pkcs7_padding(tmpblock +
(ulDataLen - out_len),
DES_BLOCK_LEN, ulDataLen - out_len);
out.cd_offset = out_len;
out.cd_length = DES_BLOCK_LEN;
out.cd_raw.iov_base = (char *)out_buf;
out.cd_raw.iov_len = out_len + DES_BLOCK_LEN;
rc = des_encrypt_contiguous_blocks(
(des_ctx_t *)soft_des_ctx->des_cbc,
(char *)tmpblock, DES_BLOCK_LEN, &out);
out_len += DES_BLOCK_LEN;
}
if (rc == 0) {
*pulEncryptedLen = out_len;
break;
}
encrypt_failed:
*pulEncryptedLen = 0;
rv = CKR_FUNCTION_FAILED;
goto cleanup;
}
}
if (update)
return (CKR_OK);
cleanup:
(void) pthread_mutex_lock(&session_p->session_mutex);
des_ctx = (des_ctx_t *)soft_des_ctx->des_cbc;
free(des_ctx);
freezero(soft_des_ctx->key_sched, soft_des_ctx->keysched_len);
freezero(session_p->encrypt.context, sizeof (soft_des_ctx_t));
session_p->encrypt.context = NULL;
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (rv);
}
CK_RV
soft_des_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)
{
int rc = 0;
CK_RV rv = CKR_OK;
soft_des_ctx_t *soft_des_ctx =
(soft_des_ctx_t *)session_p->decrypt.context;
des_ctx_t *des_ctx;
CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
CK_BYTE *in_buf = NULL;
CK_BYTE *out_buf = NULL;
CK_ULONG out_len;
CK_ULONG total_len;
CK_ULONG remain;
boolean_t pad_mechanism = B_FALSE;
pad_mechanism = (mechanism == CKM_DES_CBC_PAD ||
mechanism == CKM_DES3_CBC_PAD);
if (!update) {
if ((ulEncryptedLen % DES_BLOCK_LEN) != 0) {
rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
goto cleanup;
}
if (pData == NULL) {
*pulDataLen = ulEncryptedLen;
return (CKR_OK);
}
if (!pad_mechanism) {
if (*pulDataLen < ulEncryptedLen) {
*pulDataLen = ulEncryptedLen;
return (CKR_BUFFER_TOO_SMALL);
}
out_len = ulEncryptedLen;
} else {
if (*pulDataLen < (ulEncryptedLen - DES_BLOCK_LEN)) {
*pulDataLen = ulEncryptedLen - DES_BLOCK_LEN;
return (CKR_BUFFER_TOO_SMALL);
}
out_len = ulEncryptedLen - DES_BLOCK_LEN;
}
in_buf = pEncrypted;
out_buf = pData;
} else {
total_len = soft_des_ctx->remain_len + ulEncryptedLen;
if ((total_len < DES_BLOCK_LEN) ||
(pad_mechanism && (total_len == DES_BLOCK_LEN))) {
if (pEncrypted != NULL) {
(void) memcpy(soft_des_ctx->data +
soft_des_ctx->remain_len,
pEncrypted, ulEncryptedLen);
soft_des_ctx->remain_len += ulEncryptedLen;
}
*pulDataLen = 0;
return (CKR_OK);
}
remain = total_len % DES_BLOCK_LEN;
out_len = total_len - remain;
if (pad_mechanism) {
if (remain == 0) {
remain = DES_BLOCK_LEN;
out_len -= DES_BLOCK_LEN;
}
}
if (pData == NULL) {
*pulDataLen = out_len;
return (CKR_OK);
}
if (*pulDataLen < out_len) {
*pulDataLen = out_len;
return (CKR_BUFFER_TOO_SMALL);
}
if (soft_des_ctx->remain_len != 0) {
(void) memmove(pData + soft_des_ctx->remain_len,
pEncrypted, out_len - soft_des_ctx->remain_len);
(void) memcpy(pData, soft_des_ctx->data,
soft_des_ctx->remain_len);
bzero(soft_des_ctx->data, soft_des_ctx->remain_len);
in_buf = pData;
} else {
in_buf = pEncrypted;
}
out_buf = pData;
}
switch (mechanism) {
case CKM_DES_ECB:
case CKM_DES3_ECB:
{
uint8_t *tmp_inbuf;
uint8_t *tmp_outbuf;
ulong_t i;
for (i = 0; i < out_len; i += DES_BLOCK_LEN) {
tmp_inbuf = &in_buf[i];
tmp_outbuf = &out_buf[i];
if (soft_des_ctx->key_type == CKK_DES)
(void) des_crunch_block(
soft_des_ctx->key_sched,
tmp_inbuf, tmp_outbuf, B_TRUE);
else
(void) des3_crunch_block(
soft_des_ctx->key_sched,
tmp_inbuf, tmp_outbuf, B_TRUE);
}
if (update) {
if (remain != 0)
(void) memcpy(soft_des_ctx->data, pEncrypted +
(ulEncryptedLen - remain), remain);
soft_des_ctx->remain_len = remain;
}
*pulDataLen = out_len;
break;
}
case CKM_DES_CBC:
case CKM_DES_CBC_PAD:
case CKM_DES3_CBC:
case CKM_DES3_CBC_PAD:
{
crypto_data_t out;
CK_ULONG rem_len;
uint8_t last_block[DES_BLOCK_LEN];
out.cd_format = CRYPTO_DATA_RAW;
out.cd_offset = 0;
out.cd_length = out_len;
out.cd_raw.iov_base = (char *)out_buf;
out.cd_raw.iov_len = out_len;
rc = des_decrypt_contiguous_blocks(
(des_ctx_t *)soft_des_ctx->des_cbc,
(char *)in_buf, out_len, &out);
if (rc != 0)
goto decrypt_failed;
if (pad_mechanism && !update) {
out.cd_offset = 0;
out.cd_length = DES_BLOCK_LEN;
out.cd_raw.iov_base = (char *)last_block;
out.cd_raw.iov_len = DES_BLOCK_LEN;
rc = des_decrypt_contiguous_blocks(
(des_ctx_t *)soft_des_ctx->des_cbc,
(char *)in_buf + out_len, DES_BLOCK_LEN, &out);
if (rc != 0)
goto decrypt_failed;
rv = soft_remove_pkcs7_padding(last_block,
DES_BLOCK_LEN, &rem_len);
if (rv == CKR_OK) {
if (rem_len != 0)
(void) memcpy(out_buf + out_len,
last_block, rem_len);
*pulDataLen = out_len + rem_len;
} else {
*pulDataLen = 0;
goto cleanup;
}
} else {
*pulDataLen = out_len;
}
if (update) {
if (remain != 0)
(void) memcpy(soft_des_ctx->data, pEncrypted +
(ulEncryptedLen - remain), remain);
soft_des_ctx->remain_len = remain;
}
if (rc == 0)
break;
decrypt_failed:
*pulDataLen = 0;
rv = CKR_FUNCTION_FAILED;
goto cleanup;
}
}
if (update)
return (CKR_OK);
cleanup:
(void) pthread_mutex_lock(&session_p->session_mutex);
des_ctx = (des_ctx_t *)soft_des_ctx->des_cbc;
free(des_ctx);
freezero(soft_des_ctx->key_sched, soft_des_ctx->keysched_len);
freezero(session_p->decrypt.context, sizeof (soft_des_ctx_t));
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (rv);
}
void *
des_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec, CK_KEY_TYPE type)
{
cbc_ctx_t *cbc_ctx;
if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
return (NULL);
cbc_ctx->cbc_keysched = key_sched;
(void) memcpy(&cbc_ctx->cbc_iv[0], ivec, DES_BLOCK_LEN);
cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0];
cbc_ctx->cbc_keysched_len = size;
if (type == CKK_DES)
cbc_ctx->cbc_flags |= CBC_MODE;
else
cbc_ctx->cbc_flags |= CBC_MODE | DES3_STRENGTH;
return (cbc_ctx);
}
CK_RV
soft_des_sign_verify_init_common(soft_session_t *session_p,
CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t sign_op)
{
soft_des_ctx_t *soft_des_ctx;
CK_MECHANISM encrypt_mech;
CK_RV rv;
if ((key_p->class != CKO_SECRET_KEY) || (key_p->key_type != CKK_DES)) {
return (CKR_KEY_TYPE_INCONSISTENT);
}
soft_des_ctx = malloc(sizeof (soft_des_ctx_t));
if (soft_des_ctx == NULL) {
return (CKR_HOST_MEMORY);
}
soft_des_ctx->key_type = key_p->key_type;
bzero(soft_des_ctx->ivec, DES_BLOCK_LEN);
switch (pMechanism->mechanism) {
case CKM_DES_MAC_GENERAL:
if (pMechanism->ulParameterLen !=
sizeof (CK_MAC_GENERAL_PARAMS)) {
free(soft_des_ctx);
return (CKR_MECHANISM_PARAM_INVALID);
}
if (*(CK_MAC_GENERAL_PARAMS *)pMechanism->pParameter >
DES_BLOCK_LEN) {
free(soft_des_ctx);
return (CKR_MECHANISM_PARAM_INVALID);
}
soft_des_ctx->mac_len = *((CK_MAC_GENERAL_PARAMS_PTR)
pMechanism->pParameter);
case CKM_DES_MAC:
if (pMechanism->mechanism == CKM_DES_MAC) {
soft_des_ctx->mac_len = DES_MAC_LEN;
}
encrypt_mech.mechanism = CKM_DES_CBC_PAD;
encrypt_mech.pParameter = (void *)soft_des_ctx->ivec;
encrypt_mech.ulParameterLen = DES_BLOCK_LEN;
rv = soft_encrypt_init_internal(session_p, &encrypt_mech,
key_p);
if (rv != CKR_OK) {
free(soft_des_ctx);
return (rv);
}
(void) pthread_mutex_lock(&session_p->session_mutex);
if (sign_op) {
session_p->sign.context = soft_des_ctx;
session_p->sign.mech.mechanism = pMechanism->mechanism;
} else {
session_p->verify.context = soft_des_ctx;
session_p->verify.mech.mechanism =
pMechanism->mechanism;
}
(void) pthread_mutex_unlock(&session_p->session_mutex);
break;
}
return (CKR_OK);
}
CK_RV
soft_des_sign_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
CK_ULONG ulDataLen, CK_BYTE_PTR pSigned, CK_ULONG_PTR pulSignedLen,
boolean_t sign_op, boolean_t Final)
{
soft_des_ctx_t *soft_des_ctx_sign_verify;
soft_des_ctx_t *soft_des_ctx_encrypt;
CK_RV rv;
CK_BYTE *pEncrypted = NULL;
CK_ULONG ulEncryptedLen = 0;
uint8_t remainder;
CK_BYTE last_block[DES_BLOCK_LEN];
des_ctx_t *des_ctx = NULL;
if (sign_op) {
soft_des_ctx_sign_verify =
(soft_des_ctx_t *)session_p->sign.context;
if (soft_des_ctx_sign_verify->mac_len == 0) {
*pulSignedLen = 0;
goto clean_exit;
}
if (pSigned == NULL) {
*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
return (CKR_OK);
}
if (*pulSignedLen < soft_des_ctx_sign_verify->mac_len) {
*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
return (CKR_BUFFER_TOO_SMALL);
}
} else {
soft_des_ctx_sign_verify =
(soft_des_ctx_t *)session_p->verify.context;
}
if (Final) {
soft_des_ctx_encrypt =
(soft_des_ctx_t *)session_p->encrypt.context;
if (soft_des_ctx_encrypt->remain_len != 0) {
bzero(last_block, DES_BLOCK_LEN);
ulEncryptedLen = DES_BLOCK_LEN;
rv = soft_encrypt_final(session_p, last_block,
&ulEncryptedLen);
if (rv != CKR_OK) {
goto clean_exit;
}
} else {
soft_des_ctx_encrypt =
(soft_des_ctx_t *)session_p->encrypt.context;
des_ctx = (des_ctx_t *)soft_des_ctx_encrypt->des_cbc;
(void) memcpy(last_block, des_ctx->dc_lastp,
DES_BLOCK_LEN);
rv = soft_encrypt_final(session_p, NULL,
&ulEncryptedLen);
}
} else {
remainder = ulDataLen % DES_BLOCK_LEN;
ulEncryptedLen = ulDataLen + (DES_BLOCK_LEN - remainder);
pEncrypted = malloc(sizeof (CK_BYTE) * ulEncryptedLen);
if (pEncrypted == NULL) {
rv = CKR_HOST_MEMORY;
goto clean_exit;
}
bzero(pEncrypted, ulEncryptedLen);
(void) memcpy(pEncrypted, pData, ulDataLen);
rv = soft_encrypt(session_p, pEncrypted, ulDataLen,
pEncrypted, &ulEncryptedLen);
(void) memcpy(last_block,
&pEncrypted[ulEncryptedLen - DES_BLOCK_LEN], DES_BLOCK_LEN);
}
if (rv == CKR_OK) {
*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
(void) memcpy(pSigned, last_block, *pulSignedLen);
}
clean_exit:
(void) pthread_mutex_lock(&session_p->session_mutex);
if (sign_op) {
free(session_p->sign.context);
session_p->sign.context = NULL;
} else {
free(session_p->verify.context);
session_p->verify.context = NULL;
}
session_p->encrypt.flags = 0;
(void) pthread_mutex_unlock(&session_p->session_mutex);
if (pEncrypted) {
free(pEncrypted);
}
return (rv);
}
CK_RV
soft_des_mac_sign_verify_update(soft_session_t *session_p, CK_BYTE_PTR pPart,
CK_ULONG ulPartLen)
{
soft_des_ctx_t *soft_des_ctx_encrypt;
CK_BYTE *pEncrypted = NULL;
CK_ULONG ulEncryptedLen;
CK_ULONG total_len;
uint8_t remainder;
CK_RV rv;
soft_des_ctx_encrypt = (soft_des_ctx_t *)session_p->encrypt.context;
total_len = soft_des_ctx_encrypt->remain_len + ulPartLen;
if (total_len < DES_BLOCK_LEN) {
rv = soft_encrypt_update(session_p, pPart, ulPartLen, NULL,
&ulEncryptedLen);
} else {
remainder = ulPartLen % DES_BLOCK_LEN;
ulEncryptedLen = ulPartLen + (DES_BLOCK_LEN - remainder);
pEncrypted = malloc(sizeof (CK_BYTE) * ulEncryptedLen);
if (pEncrypted != NULL) {
rv = soft_encrypt_update(session_p, pPart, ulPartLen,
pEncrypted, &ulEncryptedLen);
free(pEncrypted);
} else {
rv = CKR_HOST_MEMORY;
}
}
return (rv);
}