blob: 0f52eb895ef5760b025f6dec109294a902e1cfef [file] [log] [blame]
/*
* Licensed materials, Property of IBM Corp.
*
* openCryptoki CCA token
*
* (C) COPYRIGHT International Business Machines Corp. 2001, 2002, 2006
*
*/
// File: mech_des3.c
//
// Mechanisms for DES3
//
#include <string.h> // for memcmp() et al
#include <stdlib.h>
#include "cca_stdll.h"
#include "pkcs11types.h"
#include "defs.h"
#include "host_defs.h"
#include "h_extern.h"
#include "tok_spec_struct.h"
//
//
#ifndef NOECB
CK_RV
des3_ecb_encrypt( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
OBJECT *key = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE key_value[3*DES_KEY_SIZE];
CK_KEY_TYPE keytype;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// CKM_DES3_ECB requires the input data to be an integral
// multiple of the block size
//
if (in_data_len % DES_BLOCK_SIZE != 0){
st_err_log(11, __FILE__, __LINE__);
return CKR_DATA_LEN_RANGE;
}
rc = object_mgr_find_in_map1( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_VALUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
if (keytype == CKK_DES2) {
memcpy( key_value, attr->pValue, 2*DES_KEY_SIZE );
memcpy( key_value + (2*DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE );
}
else
memcpy( key_value, attr->pValue, 3*DES_KEY_SIZE );
if (length_only == TRUE) {
*out_data_len = in_data_len;
return CKR_OK;
}
if (*out_data_len < in_data_len) {
*out_data_len = in_data_len;
st_err_log(111, __FILE__, __LINE__);
return CKR_BUFFER_TOO_SMALL;
}
return ckm_des3_ecb_encrypt( in_data, in_data_len,
out_data, out_data_len,
key_value );
}
//
//
CK_RV
des3_ecb_decrypt( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len)
{
OBJECT *key = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE key_value[3*DES_KEY_SIZE];
CK_KEY_TYPE keytype;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// CKM_DES3_ECB requires the input data to be an integral
// multiple of the block size
//
if (in_data_len % DES_BLOCK_SIZE != 0){
st_err_log(112, __FILE__, __LINE__);
return CKR_ENCRYPTED_DATA_LEN_RANGE;
}
rc = object_mgr_find_in_map1( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_VALUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
if (keytype == CKK_DES2) {
memcpy( key_value, attr->pValue, 2*DES_KEY_SIZE );
memcpy( key_value + (2*DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE );
}
else
memcpy( key_value, attr->pValue, 3*DES_KEY_SIZE );
if (length_only == TRUE) {
*out_data_len = in_data_len;
return CKR_OK;
}
if (*out_data_len < in_data_len) {
*out_data_len = in_data_len;
st_err_log(111, __FILE__, __LINE__);
return CKR_BUFFER_TOO_SMALL;
}
return ckm_des3_ecb_decrypt( in_data, in_data_len,
out_data, out_data_len,
key_value );
}
#endif
//
//
CK_RV
des3_cbc_encrypt( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len)
{
OBJECT *key = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// CKM_DES3_CBC requires the input data to be an integral
// multiple of the block size
//
if (in_data_len % DES_BLOCK_SIZE != 0){
st_err_log(11, __FILE__, __LINE__);
return CKR_DATA_LEN_RANGE;
}
rc = object_mgr_find_in_map1( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
if (length_only == TRUE) {
*out_data_len = in_data_len;
return CKR_OK;
}
if (*out_data_len < in_data_len) {
*out_data_len = in_data_len;
st_err_log(111, __FILE__, __LINE__);
return CKR_BUFFER_TOO_SMALL;
}
return ckm_des3_cbc_encrypt( in_data, in_data_len,
out_data, out_data_len,
ctx->mech.pParameter,
key_value );
}
//
//
CK_RV
des3_cbc_decrypt( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len)
{
OBJECT *key = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// CKM_DES3_CBC requires the input data to be an integral
// multiple of the block size
//
if (in_data_len % DES_BLOCK_SIZE != 0){
st_err_log(112, __FILE__, __LINE__);
return CKR_ENCRYPTED_DATA_LEN_RANGE;
}
rc = object_mgr_find_in_map1( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
if (length_only == TRUE) {
*out_data_len = in_data_len;
return CKR_OK;
}
if (*out_data_len < in_data_len) {
*out_data_len = in_data_len;
st_err_log(111, __FILE__, __LINE__);
return CKR_BUFFER_TOO_SMALL;
}
return ckm_des3_cbc_decrypt( in_data, in_data_len,
out_data, out_data_len,
ctx->mech.pParameter,
key_value );
}
//
//
CK_RV
des3_cbc_pad_encrypt( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len)
{
OBJECT *key = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE *clear = NULL;
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG padded_len;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// DES3-CBC-PAD has no input length requirements
//
rc = object_mgr_find_in_map1( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
// compute the output length, accounting for padding
//
padded_len = DES_BLOCK_SIZE * (in_data_len / DES_BLOCK_SIZE + 1);
if (length_only == TRUE) {
*out_data_len = padded_len;
return CKR_OK;
}
if (*out_data_len < padded_len) {
*out_data_len = padded_len;
st_err_log(111, __FILE__, __LINE__);
return CKR_BUFFER_TOO_SMALL;
}
clear = (CK_BYTE *)malloc( padded_len );
if (!clear){
st_err_log(0, __FILE__, __LINE__);
return CKR_HOST_MEMORY;
}
memcpy( clear, in_data, in_data_len );
add_pkcs_padding( clear + in_data_len,
DES_BLOCK_SIZE,
in_data_len,
padded_len );
rc = ckm_des3_cbc_encrypt( clear, padded_len,
out_data, out_data_len,
ctx->mech.pParameter,
key_value );
if (rc != CKR_OK)
st_err_log(105, __FILE__, __LINE__);
free( clear );
return rc;
}
//
//
CK_RV
des3_cbc_pad_decrypt( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len)
{
OBJECT *key = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE *clear = NULL;
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG padded_len;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
//
// no need to validate the input length since we'll pad as necessary
//
rc = object_mgr_find_in_map1( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
// we're decrypting so even with CBC-PAD, we should have an integral
// number of block to decrypt
//
if (in_data_len % DES_BLOCK_SIZE != 0){
st_err_log(112, __FILE__, __LINE__);
return CKR_ENCRYPTED_DATA_LEN_RANGE;
}
// the amount of cleartext after stripping the padding will actually be less
// than the input bytes...
//
padded_len = in_data_len;
if (length_only == TRUE) {
*out_data_len = padded_len;
return CKR_OK;
}
clear = (CK_BYTE *)malloc( padded_len );
if (!clear){
st_err_log(0, __FILE__, __LINE__);
return CKR_HOST_MEMORY;
}
rc = ckm_des3_cbc_decrypt( in_data, in_data_len,
clear, &padded_len,
ctx->mech.pParameter,
key_value );
if (rc == CKR_OK) {
strip_pkcs_padding( clear, padded_len, out_data_len );
memcpy( out_data, clear, *out_data_len );
}
else
st_err_log(106, __FILE__, __LINE__);
free( clear );
return rc;
}
#ifndef NOECB
//
//
CK_RV
des3_ecb_encrypt_update( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT * context = NULL;
CK_ATTRIBUTE * attr = NULL;
OBJECT * key = NULL;
CK_BYTE * clear = NULL;
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG total, remain, out_len;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
context = (DES_CONTEXT *)ctx->context;
total = (context->len + in_data_len);
if (total < DES_BLOCK_SIZE) {
if (length_only == FALSE) {
memcpy( context->data + context->len, in_data, in_data_len );
context->len += in_data_len;
}
*out_data_len = 0;
return CKR_OK;
}
else {
// we have at least 1 block
//
remain = (total % DES_BLOCK_SIZE);
out_len = (total - remain); // should always be at least 1 block
if (length_only == TRUE) {
*out_data_len = out_len;
return CKR_OK;
}
rc = object_mgr_find_in_map_nocache( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
clear = (CK_BYTE *)malloc( out_len );
if (!clear){
st_err_log(0, __FILE__, __LINE__);
return CKR_HOST_MEMORY;
}
// copy any data left over from the previous encryption operation first
//
memcpy( clear, context->data, context->len );
memcpy( clear + context->len, in_data, out_len - context->len );
rc = ckm_des3_ecb_encrypt( clear, out_len,
out_data, out_data_len, key_value );
if (rc == CKR_OK) {
*out_data_len = out_len;
// update the context buffer. we already used the buffer's current
// contents so we completely overwrite it
//
if (remain != 0)
memcpy( context->data, in_data + (in_data_len - remain), remain );
context->len = remain;
}
free( clear );
return rc;
}
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED; // shouldn't reach this
}
//
//
CK_RV
des3_ecb_decrypt_update( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT * context = NULL;
CK_ATTRIBUTE * attr = NULL;
OBJECT * key = NULL;
CK_BYTE * cipher = NULL;
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG total, remain, out_len;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
context = (DES_CONTEXT *)ctx->context;
total = (context->len + in_data_len);
if (total < DES_BLOCK_SIZE) {
if (length_only == FALSE) {
memcpy( context->data + context->len, in_data, in_data_len );
context->len += in_data_len;
}
*out_data_len = 0;
return CKR_OK;
}
else {
// we have at least 1 block
//
remain = (total % DES_BLOCK_SIZE);
out_len = total - remain;
if (length_only == TRUE) {
*out_data_len = out_len;
return CKR_OK;
}
rc = object_mgr_find_in_map1( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
cipher = (CK_BYTE *)malloc( out_len );
if (!cipher){
st_err_log(0, __FILE__, __LINE__);
return CKR_HOST_MEMORY;
}
// copy any data left over from the previous decryption operation first
//
memcpy( cipher, context->data, context->len );
memcpy( cipher + context->len, in_data, out_len - context->len );
rc = ckm_des3_ecb_decrypt( cipher, out_len,
out_data, out_data_len, key_value );
if (rc == CKR_OK) {
*out_data_len = out_len;
// copy the remaining 'new' input data to the context buffer
//
if (remain != 0)
memcpy( context->data, in_data + (in_data_len - remain), remain );
context->len = remain;
}
else
st_err_log(105, __FILE__, __LINE__);
free( cipher );
return rc;
}
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED; // shouldn't reach this
}
#endif
//
//
CK_RV
des3_cbc_encrypt_update( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT * context = NULL;
CK_ATTRIBUTE * attr = NULL;
OBJECT * key = NULL;
CK_BYTE * clear = NULL;
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG total, remain, out_len;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
context = (DES_CONTEXT *)ctx->context;
total = (context->len + in_data_len);
if (total < DES_BLOCK_SIZE) {
if (length_only == FALSE) {
memcpy( context->data + context->len, in_data, in_data_len );
context->len += in_data_len;
}
*out_data_len = 0;
return CKR_OK;
}
else {
// we have at least 1 block
//
remain = (total % DES_BLOCK_SIZE);
out_len = total - remain;
if (length_only == TRUE) {
*out_data_len = out_len;
return CKR_OK;
}
rc = object_mgr_find_in_map_nocache( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
// these buffers need to be longword aligned
//
clear = (CK_BYTE *)malloc( out_len );
if (!clear){
st_err_log(0, __FILE__, __LINE__);
return CKR_HOST_MEMORY;
}
// copy any data left over from the previous encryption operation first
//
memcpy( clear, context->data, context->len );
memcpy( clear + context->len, in_data, out_len - context->len );
rc = ckm_des3_cbc_encrypt( clear, out_len,
out_data, out_data_len,
ctx->mech.pParameter,
key_value );
if (rc == CKR_OK) {
*out_data_len = out_len;
// the new init_v is the last encrypted data block
//
memcpy( ctx->mech.pParameter, out_data + (*out_data_len - DES_BLOCK_SIZE), DES_BLOCK_SIZE );
// copy the remaining 'new' input data to the context buffer
//
if (remain != 0)
memcpy( context->data, in_data + (in_data_len - remain), remain );
context->len = remain;
}
else
st_err_log(105, __FILE__, __LINE__);
free( clear );
return rc;
}
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
//
//
CK_RV
des3_cbc_decrypt_update( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT * context = NULL;
CK_ATTRIBUTE * attr = NULL;
OBJECT * key = NULL;
CK_BYTE * cipher = NULL;
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG total, remain, out_len;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
context = (DES_CONTEXT *)ctx->context;
total = context->len + in_data_len;
if (total < DES_BLOCK_SIZE) {
if (length_only == FALSE) {
memcpy( context->data + context->len, in_data, in_data_len );
context->len += in_data_len;
}
*out_data_len = 0;
return CKR_OK;
}
else {
// we have at least 1 block
//
remain = total % DES_BLOCK_SIZE;
out_len = total - remain;
if (length_only == TRUE) {
*out_data_len = out_len;
return CKR_OK;
}
rc = object_mgr_find_in_map_nocache( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
// these buffers need to be longword aligned
//
cipher = (CK_BYTE *)malloc( out_len );
if (!cipher){
st_err_log(0, __FILE__, __LINE__);
return CKR_HOST_MEMORY;
}
// copy any data left over from the previous decryption operation first
//
memcpy( cipher, context->data, context->len );
memcpy( cipher + context->len, in_data, out_len - context->len );
rc = ckm_des3_cbc_decrypt( cipher, out_len,
out_data, out_data_len,
ctx->mech.pParameter,
key_value );
if (rc == CKR_OK) {
*out_data_len = out_len;
// the new init_v is the last input data block
//
memcpy( ctx->mech.pParameter, cipher + (out_len - DES_BLOCK_SIZE), DES_BLOCK_SIZE );
// copy the remaining 'new' input data to the context buffer
//
if (remain != 0)
memcpy( context->data, in_data + (in_data_len - remain), remain );
context->len = remain;
}
else
st_err_log(106, __FILE__, __LINE__);
free( cipher );
return rc;
}
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
//
//
CK_RV
des3_cbc_pad_encrypt_update( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT * context = NULL;
CK_ATTRIBUTE * attr = NULL;
OBJECT * key = NULL;
CK_BYTE * clear = NULL;
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG total, remain, out_len;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
context = (DES_CONTEXT *)ctx->context;
total = (context->len + in_data_len);
// note, this is subtly different from the other encrypt update routines
//
if (total <= DES_BLOCK_SIZE) {
if (length_only == FALSE) {
memcpy( context->data + context->len, in_data, in_data_len );
context->len += in_data_len;
}
*out_data_len = 0;
return CKR_OK;
}
else {
remain = (total % DES_BLOCK_SIZE);
out_len = total - remain; // out_len is a multiple of DES_BLOCK_SIZE
if (remain == 0) {
remain = DES_BLOCK_SIZE;
out_len -= DES_BLOCK_SIZE;
}
if (length_only == TRUE) {
*out_data_len = out_len;
return CKR_OK;
}
// at this point, we should have:
// 1) remain != 0
// 2) out_len != 0
//
rc = object_mgr_find_in_map_nocache( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
// these buffers need to be longword aligned
//
clear = (CK_BYTE *)malloc( out_len );
if (!clear){
st_err_log(0, __FILE__, __LINE__);
return CKR_HOST_MEMORY;
}
// copy any data left over from the previous encryption operation first
//
memcpy( clear, context->data, context->len );
memcpy( clear + context->len, in_data, out_len - context->len );
//
// we don't do padding during the update
//
rc = ckm_des3_cbc_encrypt( clear, out_len,
out_data, out_data_len,
ctx->mech.pParameter,
key_value );
if (rc == CKR_OK) {
// the new init_v is the last encrypted data block
//
memcpy( ctx->mech.pParameter, out_data + (*out_data_len - DES_BLOCK_SIZE), DES_BLOCK_SIZE );
// copy the remaining 'new' input data to the temporary space
//
if (remain != 0)
memcpy( context->data, in_data + (in_data_len - remain), remain );
context->len = remain;
}
free( clear );
return rc;
}
}
//
//
CK_RV
des3_cbc_pad_decrypt_update( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT * context = NULL;
CK_ATTRIBUTE * attr = NULL;
OBJECT * key = NULL;
CK_BYTE * cipher = NULL;
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG total, remain, out_len;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
context = (DES_CONTEXT *)ctx->context;
total = (context->len + in_data_len);
// note, this is subtly different from the other decrypt update routines
//
if (total <= DES_BLOCK_SIZE) {
if (length_only == FALSE) {
memcpy( context->data + context->len, in_data, in_data_len );
context->len += in_data_len;
}
*out_data_len = 0;
return CKR_OK;
}
else {
// we have at least 1 block + 1 byte
//
remain = total % DES_BLOCK_SIZE;
out_len = total - remain;
if (remain == 0) {
remain = DES_BLOCK_SIZE;
out_len -= DES_BLOCK_SIZE;
}
if (length_only == TRUE) {
*out_data_len = out_len;
return CKR_OK;
}
// at this point, we should have:
// 1) remain != 0
// 2) out_len != 0
//
rc = object_mgr_find_in_map_nocache( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
// these buffers need to be longword aligned
//
cipher = (CK_BYTE *)malloc( out_len );
if (!cipher){
st_err_log(0, __FILE__, __LINE__);
return CKR_HOST_MEMORY;
}
// copy any data left over from the previous decryption operation first
//
memcpy( cipher, context->data, context->len );
memcpy( cipher + context->len, in_data, out_len - context->len );
rc = ckm_des3_cbc_decrypt( cipher, out_len,
out_data, out_data_len,
ctx->mech.pParameter,
key_value );
if (rc == CKR_OK) {
// the new init_v is the last input data block
//
memcpy( ctx->mech.pParameter, cipher + (out_len - DES_BLOCK_SIZE), DES_BLOCK_SIZE );
// copy the remaining 'new' input data to the temporary space
//
if (remain != 0)
memcpy( context->data, in_data + (in_data_len - remain), remain );
context->len = remain;
}
free( cipher );
return rc;
}
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
#ifndef NOECB
//
//
CK_RV
des3_ecb_encrypt_final( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT *context = NULL;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// satisfy the compiler
//
if (length_only)
context = NULL;
context = (DES_CONTEXT *)ctx->context;
// DES3-ECB does no padding so there had better not be
// any data in the context buffer. if there is it means
// that the overall data length was not a multiple of the blocksize
//
if (context->len != 0){
st_err_log(11, __FILE__, __LINE__);
return CKR_DATA_LEN_RANGE;
}
*out_data_len = 0;
return CKR_OK;
}
//
//
CK_RV
des3_ecb_decrypt_final( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT *context = NULL;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// satisfy the compiler
//
if (length_only)
context = NULL;
context = (DES_CONTEXT *)ctx->context;
// DES3-ECB does no padding so there had better not be
// any data in the context buffer. if there is it means
// that the overall data length was not a multiple of the blocksize
//
if (context->len != 0){
st_err_log(11, __FILE__, __LINE__);
return CKR_DATA_LEN_RANGE;
}
*out_data_len = 0;
return CKR_OK;
}
#endif
//
//
CK_RV
des3_cbc_encrypt_final( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT *context = NULL;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// satisfy the compiler
//
if (length_only)
context = NULL;
context = (DES_CONTEXT *)ctx->context;
// DES3-CBC does no padding so there had better not be
// any data in the context buffer. if there is it means
// that the overall data length was not a multiple of the blocksize
//
if (context->len != 0){
st_err_log(11, __FILE__, __LINE__);
return CKR_DATA_LEN_RANGE;
}
*out_data_len = 0;
return CKR_OK;
}
//
//
CK_RV
des3_cbc_decrypt_final( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT *context = NULL;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
// satisfy the compiler
//
if (length_only)
context = NULL;
context = (DES_CONTEXT *)ctx->context;
// DES3-CBC does no padding so there had better not be
// any data in the context buffer. if there is it means
// that the overall data length was not a multiple of the blocksize
//
if (context->len != 0){
st_err_log(11, __FILE__, __LINE__);
return CKR_DATA_LEN_RANGE;
}
*out_data_len = 0;
return CKR_OK;
}
//
//
CK_RV
des3_cbc_pad_encrypt_final( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT *context = NULL;
OBJECT *key = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE clear[2*DES_BLOCK_SIZE];
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG out_len;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
rc = object_mgr_find_in_map1( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
context = (DES_CONTEXT *)ctx->context;
// there will never be more than one block in the context buffer
// so the amount of output is as follows:
// if less than 1 block stored, we generate one block of output
// if a full block is stored, we generate two blocks of output (one pad block)
//
if (context->len == DES_BLOCK_SIZE)
out_len = 2 * DES_BLOCK_SIZE;
else
out_len = DES_BLOCK_SIZE;
if (length_only == TRUE) {
*out_data_len = out_len;
return CKR_OK;
}
else {
memcpy( clear, context->data, context->len );
add_pkcs_padding( clear + context->len,
DES_BLOCK_SIZE,
context->len,
out_len );
rc = ckm_des3_cbc_encrypt( clear, out_len,
out_data, out_data_len,
ctx->mech.pParameter,
key_value );
if (rc != CKR_OK)
st_err_log(105, __FILE__, __LINE__);
return rc;
}
}
//
//
CK_RV
des3_cbc_pad_decrypt_final( SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *out_data,
CK_ULONG *out_data_len )
{
DES_CONTEXT *context = NULL;
OBJECT *key = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE clear[DES_BLOCK_SIZE];
CK_BYTE key_value[CCA_KEY_ID_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG out_len;
CK_RV rc;
if (!sess || !ctx || !out_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
rc = object_mgr_find_in_map1( ctx->key, &key );
if (rc != CKR_OK){
st_err_log(110, __FILE__, __LINE__);
return rc;
}
rc = template_attribute_find( key->template, CKA_KEY_TYPE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
rc = template_attribute_find( key->template, CKA_IBM_OPAQUE, &attr );
if (rc == FALSE){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
memcpy( key_value, attr->pValue, attr->ulValueLen );
context = (DES_CONTEXT *)ctx->context;
// there had better be a full block in the context buffer
//
if (context->len != DES_BLOCK_SIZE){
st_err_log(112, __FILE__, __LINE__);
return CKR_ENCRYPTED_DATA_LEN_RANGE;
}
// we don't know a priori how much data we'll be returning. we won't
// know until after we decrypt it and strip the padding. it's possible
// that we'll return nothing (the final block might be a padding block).
//
out_len = DES_BLOCK_SIZE; // upper bound on what we'll return
if (length_only == TRUE) {
*out_data_len = out_len;
return CKR_OK;
}
else {
rc = ckm_des3_cbc_decrypt( context->data, DES_BLOCK_SIZE,
clear, &out_len,
ctx->mech.pParameter,
key_value );
if (rc == CKR_OK) {
strip_pkcs_padding( clear, out_len, &out_len );
if (out_len != 0)
memcpy( out_data, clear, out_len );
*out_data_len = out_len;
}
else
st_err_log(106, __FILE__, __LINE__);
return rc;
}
}
//
// mechanisms
//
//
//
CK_RV
ckm_des3_key_gen( TEMPLATE *tmpl )
{
CK_ATTRIBUTE * value_attr = NULL;
CK_ATTRIBUTE * opaque_attr = NULL;
CK_ATTRIBUTE * key_type_attr = NULL;
CK_ATTRIBUTE * class_attr = NULL;
CK_ATTRIBUTE * local_attr = NULL;
CK_BYTE dummy_key[3 * DES_KEY_SIZE] = { 0, };
CK_BYTE des_key[CCA_KEY_ID_SIZE];
CK_ULONG rc;
rc = token_specific.t_des_key_gen(des_key, CCA_KEY_ID_SIZE, 3 * DES_KEY_SIZE);
if (rc != CKR_OK)
return rc;
value_attr = (CK_ATTRIBUTE *)malloc(sizeof(CK_ATTRIBUTE) + 3*DES_KEY_SIZE );
opaque_attr = (CK_ATTRIBUTE *)malloc(sizeof(CK_ATTRIBUTE) + CCA_KEY_ID_SIZE );
key_type_attr = (CK_ATTRIBUTE *)malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_KEY_TYPE) );
class_attr = (CK_ATTRIBUTE *)malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_OBJECT_CLASS) );
local_attr = (CK_ATTRIBUTE *)malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_BBOOL) );
if (!value_attr || !opaque_attr || !key_type_attr || !class_attr || !local_attr) {
if (value_attr) free( value_attr );
if (opaque_attr) free( opaque_attr );
if (key_type_attr) free( key_type_attr );
if (class_attr) free( class_attr );
if (local_attr) free( local_attr );
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
value_attr->type = CKA_VALUE;
value_attr->ulValueLen = 3 * DES_KEY_SIZE;
value_attr->pValue = (CK_BYTE *)value_attr + sizeof(CK_ATTRIBUTE);
memcpy( value_attr->pValue, dummy_key, 3 * DES_KEY_SIZE );
opaque_attr->type = CKA_IBM_OPAQUE;
opaque_attr->ulValueLen = CCA_KEY_ID_SIZE;
opaque_attr->pValue = (CK_BYTE *)opaque_attr + sizeof(CK_ATTRIBUTE);
memcpy( opaque_attr->pValue, des_key, CCA_KEY_ID_SIZE );
key_type_attr->type = CKA_KEY_TYPE;
key_type_attr->ulValueLen = sizeof(CK_KEY_TYPE);
key_type_attr->pValue = (CK_BYTE *)key_type_attr + sizeof(CK_ATTRIBUTE);
*(CK_KEY_TYPE *)key_type_attr->pValue = CKK_DES3;
class_attr->type = CKA_CLASS;
class_attr->ulValueLen = sizeof(CK_OBJECT_CLASS);
class_attr->pValue = (CK_BYTE *)class_attr + sizeof(CK_ATTRIBUTE);
*(CK_OBJECT_CLASS *)class_attr->pValue = CKO_SECRET_KEY;
local_attr->type = CKA_LOCAL;
local_attr->ulValueLen = sizeof(CK_BBOOL);
local_attr->pValue = (CK_BYTE *)local_attr + sizeof(CK_ATTRIBUTE);
*(CK_BBOOL *)local_attr->pValue = TRUE;
template_update_attribute( tmpl, value_attr );
template_update_attribute( tmpl, opaque_attr );
template_update_attribute( tmpl, key_type_attr );
template_update_attribute( tmpl, class_attr );
template_update_attribute( tmpl, local_attr );
return CKR_OK;
}
#ifndef NOECB
//
//
CK_RV
ckm_des3_ecb_encrypt( CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * out_data,
CK_ULONG * out_data_len,
CK_BYTE * key_value )
{
CK_ULONG rc;
if (!in_data || !out_data || !key_value){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
if (*out_data_len < in_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
rc = token_specific.t_tdes_ecb(in_data,in_data_len,out_data, out_data_len,
key_value, 1);
if (rc != CKR_OK)
st_err_log(120, __FILE__, __LINE__);
return rc;
}
//
//
CK_RV
ckm_des3_ecb_decrypt( CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * out_data,
CK_ULONG * out_data_len,
CK_BYTE * key_value )
{
CK_ULONG rc;
if (!in_data || !out_data || !key_value){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
if (*out_data_len < in_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
rc = token_specific.t_tdes_ecb(in_data,in_data_len,out_data, out_data_len,
key_value, 0);
if (rc != CKR_OK)
st_err_log(120, __FILE__, __LINE__);
return rc;
}
#endif
//
//
CK_RV
ckm_des3_cbc_encrypt( CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * out_data,
CK_ULONG * out_data_len,
CK_BYTE * init_v,
CK_BYTE * key_value )
{
CK_ULONG rc;
if (!in_data || !out_data || !init_v || !key_value){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
if (*out_data_len < in_data_len){
#if 0
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
#else
*out_data_len = in_data_len;
st_err_log(68, __FILE__, __FUNCTION__);
return CKR_BUFFER_TOO_SMALL;
#endif
}
rc = token_specific.t_tdes_cbc(in_data,in_data_len,out_data,out_data_len,
key_value,init_v,1);
if (rc != CKR_OK)
st_err_log(119, __FILE__, __LINE__);
return rc;
}
//
//
CK_RV
ckm_des3_cbc_decrypt( CK_BYTE * in_data,
CK_ULONG in_data_len,
CK_BYTE * out_data,
CK_ULONG * out_data_len,
CK_BYTE * init_v,
CK_BYTE * key_value )
{
CK_ULONG rc;
if (!in_data || !out_data || !init_v || !key_value){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
if (*out_data_len < in_data_len){
st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
return CKR_FUNCTION_FAILED;
}
rc = token_specific.t_tdes_cbc(in_data,in_data_len,out_data,out_data_len,
key_value,init_v,0);
if (rc != CKR_OK)
st_err_log(119, __FILE__, __LINE__);
return rc;
}