#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include "softSession.h"
#include "softObject.h"
#include "softCrypt.h"
#include <blowfish_impl.h>
CK_RV
soft_blowfish_crypt_init_common(soft_session_t *session_p,
CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t encrypt)
{
size_t size;
soft_blowfish_ctx_t *soft_blowfish_ctx;
soft_blowfish_ctx = calloc(1, sizeof (soft_blowfish_ctx_t));
if (soft_blowfish_ctx == NULL) {
return (CKR_HOST_MEMORY);
}
soft_blowfish_ctx->key_sched = blowfish_alloc_keysched(&size, 0);
if (soft_blowfish_ctx->key_sched == NULL) {
free(soft_blowfish_ctx);
return (CKR_HOST_MEMORY);
}
soft_blowfish_ctx->keysched_len = size;
(void) pthread_mutex_lock(&session_p->session_mutex);
if (encrypt) {
session_p->encrypt.context = soft_blowfish_ctx;
session_p->encrypt.mech.mechanism = pMechanism->mechanism;
} else {
session_p->decrypt.context = soft_blowfish_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) {
ks = blowfish_alloc_keysched(&size, 0);
if (ks == NULL) {
(void) pthread_mutex_unlock(
&key_p->object_mutex);
free(soft_blowfish_ctx);
return (CKR_HOST_MEMORY);
}
blowfish_init_keysched(OBJ_SEC_VALUE(key_p),
(OBJ_SEC_VALUE_LEN(key_p) * 8), 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_blowfish_ctx->key_sched,
OBJ_KEY_SCHED(key_p), OBJ_KEY_SCHED_LEN(key_p));
soft_blowfish_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
} else {
blowfish_init_keysched(OBJ_SEC_VALUE(key_p),
(OBJ_SEC_VALUE_LEN(key_p) * 8),
soft_blowfish_ctx->key_sched);
}
return (CKR_OK);
}
CK_RV
soft_blowfish_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_blowfish_ctx_t *soft_blowfish_ctx =
(soft_blowfish_ctx_t *)session_p->encrypt.context;
blowfish_ctx_t *blowfish_ctx;
CK_BYTE *in_buf = NULL;
CK_BYTE *out_buf = NULL;
CK_ULONG out_len;
CK_ULONG total_len;
CK_ULONG remain;
crypto_data_t out;
if (!update) {
if ((ulDataLen % BLOWFISH_BLOCK_LEN) != 0) {
rv = CKR_DATA_LEN_RANGE;
goto cleanup;
}
out_len = ulDataLen;
if (pEncrypted == NULL) {
*pulEncryptedLen = out_len;
return (CKR_OK);
}
if (*pulEncryptedLen < out_len) {
*pulEncryptedLen = out_len;
return (CKR_BUFFER_TOO_SMALL);
}
in_buf = pData;
out_buf = pEncrypted;
} else {
total_len = soft_blowfish_ctx->remain_len + ulDataLen;
if (total_len < BLOWFISH_BLOCK_LEN) {
if (pEncrypted != NULL) {
(void) memcpy(soft_blowfish_ctx->data +
soft_blowfish_ctx->remain_len, pData,
ulDataLen);
soft_blowfish_ctx->remain_len += ulDataLen;
}
*pulEncryptedLen = 0;
return (CKR_OK);
}
remain = total_len % BLOWFISH_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_blowfish_ctx->remain_len != 0) {
(void) memmove(pEncrypted +
soft_blowfish_ctx->remain_len,
pData, out_len - soft_blowfish_ctx->remain_len);
(void) memcpy(pEncrypted, soft_blowfish_ctx->data,
soft_blowfish_ctx->remain_len);
bzero(soft_blowfish_ctx->data,
soft_blowfish_ctx->remain_len);
in_buf = pEncrypted;
} else {
in_buf = pData;
}
out_buf = pEncrypted;
}
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 = blowfish_encrypt_contiguous_blocks(
(blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc,
(char *)in_buf, out_len, &out);
if (rc == 0) {
*pulEncryptedLen = out_len;
if (update) {
if (remain != 0)
(void) memcpy(soft_blowfish_ctx->data, pData +
(ulDataLen - remain), remain);
soft_blowfish_ctx->remain_len = remain;
return (CKR_OK);
}
} else {
*pulEncryptedLen = 0;
rv = CKR_FUNCTION_FAILED;
}
cleanup:
(void) pthread_mutex_lock(&session_p->session_mutex);
blowfish_ctx = (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc;
freezero(blowfish_ctx, sizeof (cbc_ctx_t));
freezero(soft_blowfish_ctx->key_sched,
soft_blowfish_ctx->keysched_len);
freezero(session_p->encrypt.context,
sizeof (soft_blowfish_ctx_t));
session_p->encrypt.context = NULL;
(void) pthread_mutex_unlock(&session_p->session_mutex);
return (rv);
}
CK_RV
soft_blowfish_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_blowfish_ctx_t *soft_blowfish_ctx =
(soft_blowfish_ctx_t *)session_p->decrypt.context;
blowfish_ctx_t *blowfish_ctx;
CK_BYTE *in_buf = NULL;
CK_BYTE *out_buf = NULL;
CK_ULONG out_len;
CK_ULONG total_len;
CK_ULONG remain;
crypto_data_t out;
if (!update) {
if ((ulEncryptedLen % BLOWFISH_BLOCK_LEN) != 0) {
rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
goto cleanup;
}
if (pData == NULL) {
*pulDataLen = ulEncryptedLen;
return (CKR_OK);
}
if (*pulDataLen < ulEncryptedLen) {
*pulDataLen = ulEncryptedLen;
return (CKR_BUFFER_TOO_SMALL);
}
out_len = ulEncryptedLen;
in_buf = pEncrypted;
out_buf = pData;
} else {
total_len = soft_blowfish_ctx->remain_len + ulEncryptedLen;
if (total_len < BLOWFISH_BLOCK_LEN) {
if (pData != NULL) {
(void) memcpy(soft_blowfish_ctx->data +
soft_blowfish_ctx->remain_len,
pEncrypted, ulEncryptedLen);
soft_blowfish_ctx->remain_len += ulEncryptedLen;
}
*pulDataLen = 0;
return (CKR_OK);
}
remain = total_len % BLOWFISH_BLOCK_LEN;
out_len = total_len - remain;
if (pData == NULL) {
*pulDataLen = out_len;
return (CKR_OK);
}
if (*pulDataLen < out_len) {
*pulDataLen = out_len;
return (CKR_BUFFER_TOO_SMALL);
}
if (soft_blowfish_ctx->remain_len != 0) {
(void) memmove(pData + soft_blowfish_ctx->remain_len,
pEncrypted,
out_len - soft_blowfish_ctx->remain_len);
(void) memcpy(pData, soft_blowfish_ctx->data,
soft_blowfish_ctx->remain_len);
bzero(soft_blowfish_ctx->data,
soft_blowfish_ctx->remain_len);
in_buf = pData;
} else {
in_buf = pEncrypted;
}
out_buf = pData;
}
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 = blowfish_decrypt_contiguous_blocks(
(blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc,
(char *)in_buf, out_len, &out);
if (rc == 0) {
*pulDataLen = out_len;
if (update) {
if (remain != 0)
(void) memcpy(soft_blowfish_ctx->data,
pEncrypted + (ulEncryptedLen - remain),
remain);
soft_blowfish_ctx->remain_len = remain;
return (CKR_OK);
}
} else {
*pulDataLen = 0;
rv = CKR_FUNCTION_FAILED;
}
cleanup:
(void) pthread_mutex_lock(&session_p->session_mutex);
blowfish_ctx = (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc;
free(blowfish_ctx);
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 (rv);
}
void *
blowfish_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec)
{
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, BLOWFISH_BLOCK_LEN);
cbc_ctx->cbc_lastp = (uint8_t *)&(cbc_ctx->cbc_iv);
cbc_ctx->cbc_keysched_len = size;
cbc_ctx->cbc_flags |= CBC_MODE;
return (cbc_ctx);
}