2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <pthread.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <sys/types.h>
2N/A#include <security/cryptoki.h>
2N/A#include <aes_impl.h>
2N/A
2N/A#include "kmsSession.h"
2N/A#include "kmsObject.h"
2N/A#include "kmsCrypt.h"
2N/A
2N/A/*
2N/A * Add padding bytes with the value of length of padding.
2N/A */
2N/Astatic void
2N/Akms_add_pkcs7_padding(CK_BYTE *buf, int block_size, CK_ULONG data_len)
2N/A{
2N/A
2N/A ulong_t i, pad_len;
2N/A CK_BYTE pad_value;
2N/A
2N/A pad_len = block_size - (data_len % block_size);
2N/A pad_value = (CK_BYTE)pad_len;
2N/A
2N/A for (i = 0; i < pad_len; i++)
2N/A buf[i] = pad_value;
2N/A}
2N/A
2N/A/*
2N/A * Remove padding bytes.
2N/A */
2N/Astatic CK_RV
2N/Akms_remove_pkcs7_padding(CK_BYTE *pData, CK_ULONG padded_len,
2N/A CK_ULONG *pulDataLen, int block_size)
2N/A{
2N/A
2N/A CK_BYTE pad_value;
2N/A ulong_t i;
2N/A
2N/A pad_value = pData[padded_len - 1];
2N/A
2N/A
2N/A /* Make sure there is a valid padding value. */
2N/A if ((pad_value == 0) || (pad_value > block_size))
2N/A return (CKR_ENCRYPTED_DATA_INVALID);
2N/A
2N/A for (i = padded_len - pad_value; i < padded_len; i++)
2N/A if (pad_value != pData[i])
2N/A return (CKR_ENCRYPTED_DATA_INVALID);
2N/A
2N/A *pulDataLen = padded_len - pad_value;
2N/A return (CKR_OK);
2N/A}
2N/A
2N/A/*
2N/A * Allocate context for the active encryption or decryption operation, and
2N/A * generate AES key schedule to speed up the operation.
2N/A */
2N/ACK_RV
2N/Akms_aes_crypt_init_common(kms_session_t *session_p,
2N/A CK_MECHANISM_PTR pMechanism, kms_object_t *key_p,
2N/A boolean_t encrypt)
2N/A{
2N/A size_t size;
2N/A kms_aes_ctx_t *kms_aes_ctx;
2N/A
2N/A kms_aes_ctx = calloc(1, sizeof (kms_aes_ctx_t));
2N/A if (kms_aes_ctx == NULL) {
2N/A return (CKR_HOST_MEMORY);
2N/A }
2N/A
2N/A kms_aes_ctx->key_sched = aes_alloc_keysched(&size, 0);
2N/A
2N/A if (kms_aes_ctx->key_sched == NULL) {
2N/A free(kms_aes_ctx);
2N/A return (CKR_HOST_MEMORY);
2N/A }
2N/A
2N/A kms_aes_ctx->keysched_len = size;
2N/A
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A if (encrypt) {
2N/A /* Called by C_EncryptInit. */
2N/A session_p->encrypt.context = kms_aes_ctx;
2N/A session_p->encrypt.mech.mechanism = pMechanism->mechanism;
2N/A } else {
2N/A /* Called by C_DecryptInit. */
2N/A session_p->decrypt.context = kms_aes_ctx;
2N/A session_p->decrypt.mech.mechanism = pMechanism->mechanism;
2N/A }
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A
2N/A /*
2N/A * If this is a non-sensitive key and it does NOT have
2N/A * a key schedule yet, then allocate one and expand it.
2N/A * Otherwise, if it's a non-sensitive key, and it DOES have
2N/A * a key schedule already attached to it, just copy the
2N/A * pre-expanded schedule to the context and avoid the
2N/A * extra key schedule expansion operation.
2N/A */
2N/A if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
2N/A if (OBJ_KEY_SCHED(key_p) == NULL) {
2N/A void *ks;
2N/A
2N/A (void) pthread_mutex_lock(&key_p->object_mutex);
2N/A if (OBJ_KEY_SCHED(key_p) == NULL) {
2N/A ks = aes_alloc_keysched(&size, 0);
2N/A if (ks == NULL) {
2N/A (void) pthread_mutex_unlock(
2N/A &key_p->object_mutex);
2N/A free(kms_aes_ctx);
2N/A return (CKR_HOST_MEMORY);
2N/A }
2N/A#ifdef __sparcv9
2N/A /* LINTED */
2N/A aes_init_keysched(OBJ_SEC_VALUE(key_p), (uint_t)
2N/A (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
2N/A#else /* !__sparcv9 */
2N/A aes_init_keysched(OBJ_SEC_VALUE(key_p),
2N/A (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
2N/A#endif /* __sparcv9 */
2N/A OBJ_KEY_SCHED_LEN(key_p) = size;
2N/A OBJ_KEY_SCHED(key_p) = ks;
2N/A }
2N/A (void) pthread_mutex_unlock(&key_p->object_mutex);
2N/A }
2N/A (void) memcpy(kms_aes_ctx->key_sched, OBJ_KEY_SCHED(key_p),
2N/A OBJ_KEY_SCHED_LEN(key_p));
2N/A kms_aes_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
2N/A } else {
2N/A /*
2N/A * Initialize key schedule for AES. aes_init_keysched()
2N/A * requires key length in bits.
2N/A */
2N/A#ifdef __sparcv9
2N/A /* LINTED */
2N/A aes_init_keysched(OBJ_SEC_VALUE(key_p), (uint_t)
2N/A (OBJ_SEC_VALUE_LEN(key_p) * 8), kms_aes_ctx->key_sched);
2N/A#else /* !__sparcv9 */
2N/A aes_init_keysched(OBJ_SEC_VALUE(key_p),
2N/A (OBJ_SEC_VALUE_LEN(key_p) * 8), kms_aes_ctx->key_sched);
2N/A#endif /* __sparcv9 */
2N/A }
2N/A return (CKR_OK);
2N/A}
2N/A
2N/A/*
2N/A * kms_aes_encrypt_common()
2N/A *
2N/A * Arguments:
2N/A * session_p: pointer to kms_session_t struct
2N/A * pData: pointer to the input data to be encrypted
2N/A * ulDataLen: length of the input data
2N/A * pEncrypted: pointer to the output data after encryption
2N/A * pulEncryptedLen: pointer to the length of the output data
2N/A * update: boolean flag indicates caller is kms_encrypt
2N/A * or kms_encrypt_update
2N/A *
2N/A * Description:
2N/A * This function calls the corresponding encrypt routine based
2N/A * on the mechanism.
2N/A *
2N/A * Returns:
2N/A * CKR_OK: success
2N/A * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
2N/A * is too small
2N/A * CKR_FUNCTION_FAILED: encrypt function failed
2N/A * CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
2N/A */
2N/ACK_RV
2N/Akms_aes_encrypt_common(kms_session_t *session_p, CK_BYTE_PTR pData,
2N/A CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted,
2N/A CK_ULONG_PTR pulEncryptedLen, boolean_t update)
2N/A{
2N/A
2N/A int rc = 0;
2N/A CK_RV rv = CKR_OK;
2N/A kms_aes_ctx_t *kms_aes_ctx =
2N/A (kms_aes_ctx_t *)session_p->encrypt.context;
2N/A aes_ctx_t *aes_ctx;
2N/A CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
2N/A CK_BYTE *in_buf = NULL;
2N/A CK_BYTE *out_buf = NULL;
2N/A CK_ULONG out_len;
2N/A CK_ULONG total_len;
2N/A CK_ULONG remain;
2N/A
2N/A if (mechanism == CKM_AES_CTR)
2N/A goto do_encryption;
2N/A
2N/A /*
2N/A * AES only takes input length that is a multiple of blocksize
2N/A * for C_Encrypt function with the mechanism CKM_AES_ECB or
2N/A * CKM_AES_CBC.
2N/A *
2N/A * AES allows any input length for C_Encrypt function with the
2N/A * mechanism CKM_AES_CBC_PAD and for C_EncryptUpdate function.
2N/A */
2N/A if ((!update) && (mechanism != CKM_AES_CBC_PAD)) {
2N/A if ((ulDataLen % AES_BLOCK_LEN) != 0) {
2N/A rv = CKR_DATA_LEN_RANGE;
2N/A goto cleanup;
2N/A }
2N/A }
2N/A
2N/A if (!update) {
2N/A /*
2N/A * Called by C_Encrypt
2N/A */
2N/A if (mechanism == CKM_AES_CBC_PAD) {
2N/A /*
2N/A * For CKM_AES_CBC_PAD, compute output length to
2N/A * count for the padding. If the length of input
2N/A * data is a multiple of blocksize, then make output
2N/A * length to be the sum of the input length and
2N/A * one blocksize. Otherwise, output length will
2N/A * be rounded up to the next multiple of blocksize.
2N/A */
2N/A out_len = AES_BLOCK_LEN *
2N/A (ulDataLen / AES_BLOCK_LEN + 1);
2N/A } else {
2N/A /*
2N/A * For non-padding mode, the output length will
2N/A * be same as the input length.
2N/A */
2N/A out_len = ulDataLen;
2N/A }
2N/A
2N/A /*
2N/A * If application asks for the length of the output buffer
2N/A * to hold the ciphertext?
2N/A */
2N/A if (pEncrypted == NULL) {
2N/A *pulEncryptedLen = out_len;
2N/A return (CKR_OK);
2N/A }
2N/A
2N/A /* Is the application-supplied buffer large enough? */
2N/A if (*pulEncryptedLen < out_len) {
2N/A *pulEncryptedLen = out_len;
2N/A return (CKR_BUFFER_TOO_SMALL);
2N/A }
2N/A
2N/A /* Encrypt pad bytes in a separate operation */
2N/A if (mechanism == CKM_AES_CBC_PAD) {
2N/A out_len -= AES_BLOCK_LEN;
2N/A }
2N/A
2N/A in_buf = pData;
2N/A out_buf = pEncrypted;
2N/A } else {
2N/A /*
2N/A * Called by C_EncryptUpdate
2N/A *
2N/A * Add the lengths of last remaining data and current
2N/A * plaintext together to get the total input length.
2N/A */
2N/A total_len = kms_aes_ctx->remain_len + ulDataLen;
2N/A
2N/A /*
2N/A * If the total input length is less than one blocksize,
2N/A * or if the total input length is just one blocksize and
2N/A * the mechanism is CKM_AES_CBC_PAD, we will need to delay
2N/A * encryption until when more data comes in next
2N/A * C_EncryptUpdate or when C_EncryptFinal is called.
2N/A */
2N/A if ((total_len < AES_BLOCK_LEN) ||
2N/A ((mechanism == CKM_AES_CBC_PAD) &&
2N/A (total_len == AES_BLOCK_LEN))) {
2N/A if (pEncrypted != NULL) {
2N/A /*
2N/A * Save input data and its length in
2N/A * the remaining buffer of AES context.
2N/A */
2N/A (void) memcpy(kms_aes_ctx->data +
2N/A kms_aes_ctx->remain_len, pData, ulDataLen);
2N/A kms_aes_ctx->remain_len += ulDataLen;
2N/A }
2N/A
2N/A /* Set encrypted data length to 0. */
2N/A *pulEncryptedLen = 0;
2N/A return (CKR_OK);
2N/A }
2N/A
2N/A /* Compute the length of remaining data. */
2N/A remain = total_len % AES_BLOCK_LEN;
2N/A
2N/A /*
2N/A * Make sure that the output length is a multiple of
2N/A * blocksize.
2N/A */
2N/A out_len = total_len - remain;
2N/A
2N/A /*
2N/A * If application asks for the length of the output buffer
2N/A * to hold the ciphertext?
2N/A */
2N/A if (pEncrypted == NULL) {
2N/A *pulEncryptedLen = out_len;
2N/A return (CKR_OK);
2N/A }
2N/A
2N/A /* Is the application-supplied buffer large enough? */
2N/A if (*pulEncryptedLen < out_len) {
2N/A *pulEncryptedLen = out_len;
2N/A return (CKR_BUFFER_TOO_SMALL);
2N/A }
2N/A
2N/A if (kms_aes_ctx->remain_len != 0) {
2N/A /*
2N/A * Copy last remaining data and current input data
2N/A * to the output buffer.
2N/A */
2N/A (void) memmove(pEncrypted + kms_aes_ctx->remain_len,
2N/A pData, out_len - kms_aes_ctx->remain_len);
2N/A (void) memcpy(pEncrypted, kms_aes_ctx->data,
2N/A kms_aes_ctx->remain_len);
2N/A bzero(kms_aes_ctx->data, kms_aes_ctx->remain_len);
2N/A
2N/A in_buf = pEncrypted;
2N/A } else {
2N/A in_buf = pData;
2N/A }
2N/A out_buf = pEncrypted;
2N/A }
2N/A
2N/Ado_encryption:
2N/A /*
2N/A * Begin Encryption now.
2N/A */
2N/A switch (mechanism) {
2N/A
2N/A case CKM_AES_CBC:
2N/A case CKM_AES_CBC_PAD:
2N/A {
2N/A crypto_data_t out;
2N/A
2N/A out.cd_format = CRYPTO_DATA_RAW;
2N/A out.cd_offset = 0;
2N/A out.cd_length = out_len;
2N/A out.cd_raw.iov_base = (char *)out_buf;
2N/A out.cd_raw.iov_len = out_len;
2N/A
2N/A /* Encrypt multiple blocks of data. */
2N/A rc = aes_encrypt_contiguous_blocks(
2N/A (aes_ctx_t *)kms_aes_ctx->aes_cbc,
2N/A (char *)in_buf, out_len, &out);
2N/A
2N/A if (rc != 0)
2N/A goto encrypt_failed;
2N/A
2N/A if (update) {
2N/A /*
2N/A * For encrypt update, if there is remaining data,
2N/A * save it and its length in the context.
2N/A */
2N/A if (remain != 0)
2N/A (void) memcpy(kms_aes_ctx->data, pData +
2N/A (ulDataLen - remain), remain);
2N/A kms_aes_ctx->remain_len = remain;
2N/A } else if (mechanism == CKM_AES_CBC_PAD) {
2N/A /*
2N/A * Save the remainder of the input
2N/A * block in a temporary block because
2N/A * we dont want to overrun the buffer
2N/A * by tacking on pad bytes.
2N/A */
2N/A CK_BYTE tmpblock[AES_BLOCK_LEN];
2N/A (void) memcpy(tmpblock, in_buf + out_len,
2N/A ulDataLen - out_len);
2N/A kms_add_pkcs7_padding(tmpblock +
2N/A (ulDataLen - out_len),
2N/A AES_BLOCK_LEN, ulDataLen - out_len);
2N/A
2N/A out.cd_offset = out_len;
2N/A out.cd_length = AES_BLOCK_LEN;
2N/A out.cd_raw.iov_base = (char *)out_buf;
2N/A out.cd_raw.iov_len = out_len + AES_BLOCK_LEN;
2N/A
2N/A /* Encrypt last block containing pad bytes. */
2N/A rc = aes_encrypt_contiguous_blocks(
2N/A (aes_ctx_t *)kms_aes_ctx->aes_cbc,
2N/A (char *)tmpblock, AES_BLOCK_LEN, &out);
2N/A
2N/A out_len += AES_BLOCK_LEN;
2N/A }
2N/A
2N/A if (rc == 0) {
2N/A *pulEncryptedLen = out_len;
2N/A break;
2N/A }
2N/Aencrypt_failed:
2N/A *pulEncryptedLen = 0;
2N/A rv = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
2N/A }
2N/A default:
2N/A rv = CKR_MECHANISM_INVALID;
2N/A goto cleanup;
2N/A } /* end switch */
2N/A
2N/A if (update)
2N/A return (CKR_OK);
2N/A
2N/A /*
2N/A * The following code will be executed if the caller is
2N/A * kms_encrypt() or an error occurred. The encryption
2N/A * operation will be terminated so we need to do some cleanup.
2N/A */
2N/Acleanup:
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A aes_ctx = (aes_ctx_t *)kms_aes_ctx->aes_cbc;
2N/A if (aes_ctx != NULL) {
2N/A bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len);
2N/A free(kms_aes_ctx->aes_cbc);
2N/A }
2N/A
2N/A bzero(kms_aes_ctx->key_sched, kms_aes_ctx->keysched_len);
2N/A free(kms_aes_ctx->key_sched);
2N/A free(session_p->encrypt.context);
2N/A session_p->encrypt.context = NULL;
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * kms_aes_decrypt_common()
2N/A *
2N/A * Arguments:
2N/A * session_p: pointer to kms_session_t struct
2N/A * pEncrypted: pointer to the input data to be decrypted
2N/A * ulEncryptedLen: length of the input data
2N/A * pData: pointer to the output data
2N/A * pulDataLen: pointer to the length of the output data
2N/A * Update: boolean flag indicates caller is kms_decrypt
2N/A * or kms_decrypt_update
2N/A *
2N/A * Description:
2N/A * This function calls the corresponding decrypt routine based
2N/A * on the mechanism.
2N/A *
2N/A * Returns:
2N/A * CKR_OK: success
2N/A * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
2N/A * is too small
2N/A * CKR_ENCRYPTED_DATA_LEN_RANGE: the input data is not a multiple
2N/A * of blocksize
2N/A * CKR_FUNCTION_FAILED: decrypt function failed
2N/A */
2N/ACK_RV
2N/Akms_aes_decrypt_common(kms_session_t *session_p, CK_BYTE_PTR pEncrypted,
2N/A CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData,
2N/A CK_ULONG_PTR pulDataLen, boolean_t update)
2N/A{
2N/A
2N/A int rc = 0;
2N/A CK_RV rv = CKR_OK;
2N/A kms_aes_ctx_t *kms_aes_ctx =
2N/A (kms_aes_ctx_t *)session_p->decrypt.context;
2N/A aes_ctx_t *aes_ctx;
2N/A CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
2N/A CK_BYTE *in_buf = NULL;
2N/A CK_BYTE *out_buf = NULL;
2N/A CK_ULONG out_len;
2N/A CK_ULONG total_len;
2N/A CK_ULONG remain;
2N/A
2N/A if (mechanism == CKM_AES_CTR)
2N/A goto do_decryption;
2N/A
2N/A /*
2N/A * AES only takes input length that is a multiple of 16 bytes
2N/A * for C_Decrypt function with the mechanism CKM_AES_ECB,
2N/A * CKM_AES_CBC or CKM_AES_CBC_PAD.
2N/A *
2N/A * AES allows any input length for C_DecryptUpdate function.
2N/A */
2N/A if (!update) {
2N/A /*
2N/A * Called by C_Decrypt
2N/A */
2N/A if ((ulEncryptedLen % AES_BLOCK_LEN) != 0) {
2N/A rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
2N/A goto cleanup;
2N/A }
2N/A
2N/A /*
2N/A * If application asks for the length of the output buffer
2N/A * to hold the plaintext?
2N/A */
2N/A if (pData == NULL) {
2N/A *pulDataLen = ulEncryptedLen;
2N/A return (CKR_OK);
2N/A }
2N/A
2N/A /* Is the application-supplied buffer large enough? */
2N/A if (mechanism != CKM_AES_CBC_PAD) {
2N/A if (*pulDataLen < ulEncryptedLen) {
2N/A *pulDataLen = ulEncryptedLen;
2N/A return (CKR_BUFFER_TOO_SMALL);
2N/A }
2N/A out_len = ulEncryptedLen;
2N/A } else {
2N/A /*
2N/A * For CKM_AES_CBC_PAD, we don't know how
2N/A * many bytes for padding at this time, so
2N/A * we'd assume one block was padded.
2N/A */
2N/A if (*pulDataLen < (ulEncryptedLen - AES_BLOCK_LEN)) {
2N/A *pulDataLen = ulEncryptedLen - AES_BLOCK_LEN;
2N/A return (CKR_BUFFER_TOO_SMALL);
2N/A }
2N/A out_len = ulEncryptedLen - AES_BLOCK_LEN;
2N/A }
2N/A in_buf = pEncrypted;
2N/A out_buf = pData;
2N/A } else {
2N/A /*
2N/A * Called by C_DecryptUpdate
2N/A *
2N/A * Add the lengths of last remaining data and current
2N/A * input data together to get the total input length.
2N/A */
2N/A total_len = kms_aes_ctx->remain_len + ulEncryptedLen;
2N/A
2N/A /*
2N/A * If the total input length is less than one blocksize,
2N/A * or if the total input length is just one blocksize and
2N/A * the mechanism is CKM_AES_CBC_PAD, we will need to delay
2N/A * decryption until when more data comes in next
2N/A * C_DecryptUpdate or when C_DecryptFinal is called.
2N/A */
2N/A if ((total_len < AES_BLOCK_LEN) ||
2N/A ((mechanism == CKM_AES_CBC_PAD) &&
2N/A (total_len == AES_BLOCK_LEN))) {
2N/A if (pData != NULL) {
2N/A /*
2N/A * Save input data and its length in
2N/A * the remaining buffer of AES context.
2N/A */
2N/A (void) memcpy(kms_aes_ctx->data +
2N/A kms_aes_ctx->remain_len,
2N/A pEncrypted, ulEncryptedLen);
2N/A kms_aes_ctx->remain_len += ulEncryptedLen;
2N/A }
2N/A
2N/A /* Set output data length to 0. */
2N/A *pulDataLen = 0;
2N/A return (CKR_OK);
2N/A }
2N/A
2N/A /* Compute the length of remaining data. */
2N/A remain = total_len % AES_BLOCK_LEN;
2N/A
2N/A /*
2N/A * Make sure that the output length is a multiple of
2N/A * blocksize.
2N/A */
2N/A out_len = total_len - remain;
2N/A
2N/A if (mechanism == CKM_AES_CBC_PAD) {
2N/A /*
2N/A * If the input data length is a multiple of
2N/A * blocksize, then save the last block of input
2N/A * data in the remaining buffer. C_DecryptFinal
2N/A * will handle this last block of data.
2N/A */
2N/A if (remain == 0) {
2N/A remain = AES_BLOCK_LEN;
2N/A out_len -= AES_BLOCK_LEN;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * If application asks for the length of the output buffer
2N/A * to hold the plaintext?
2N/A */
2N/A if (pData == NULL) {
2N/A *pulDataLen = out_len;
2N/A return (CKR_OK);
2N/A }
2N/A
2N/A /*
2N/A * Is the application-supplied buffer large enough?
2N/A */
2N/A if (*pulDataLen < out_len) {
2N/A *pulDataLen = out_len;
2N/A return (CKR_BUFFER_TOO_SMALL);
2N/A }
2N/A
2N/A if (kms_aes_ctx->remain_len != 0) {
2N/A /*
2N/A * Copy last remaining data and current input data
2N/A * to the output buffer.
2N/A */
2N/A (void) memmove(pData + kms_aes_ctx->remain_len,
2N/A pEncrypted, out_len - kms_aes_ctx->remain_len);
2N/A (void) memcpy(pData, kms_aes_ctx->data,
2N/A kms_aes_ctx->remain_len);
2N/A bzero(kms_aes_ctx->data, kms_aes_ctx->remain_len);
2N/A
2N/A in_buf = pData;
2N/A } else {
2N/A in_buf = pEncrypted;
2N/A }
2N/A out_buf = pData;
2N/A }
2N/A
2N/Ado_decryption:
2N/A /*
2N/A * Begin Decryption.
2N/A */
2N/A switch (mechanism) {
2N/A case CKM_AES_CBC:
2N/A case CKM_AES_CBC_PAD:
2N/A {
2N/A crypto_data_t out;
2N/A CK_ULONG rem_len;
2N/A uint8_t last_block[AES_BLOCK_LEN];
2N/A
2N/A out.cd_format = CRYPTO_DATA_RAW;
2N/A out.cd_offset = 0;
2N/A out.cd_length = out_len;
2N/A out.cd_raw.iov_base = (char *)out_buf;
2N/A out.cd_raw.iov_len = out_len;
2N/A
2N/A /* Decrypt multiple blocks of data. */
2N/A rc = aes_decrypt_contiguous_blocks(
2N/A (aes_ctx_t *)kms_aes_ctx->aes_cbc,
2N/A (char *)in_buf, out_len, &out);
2N/A
2N/A if (rc != 0)
2N/A goto decrypt_failed;
2N/A
2N/A if ((mechanism == CKM_AES_CBC_PAD) && (!update)) {
2N/A /* Decrypt last block containing pad bytes. */
2N/A out.cd_offset = 0;
2N/A out.cd_length = AES_BLOCK_LEN;
2N/A out.cd_raw.iov_base = (char *)last_block;
2N/A out.cd_raw.iov_len = AES_BLOCK_LEN;
2N/A
2N/A /* Decrypt last block containing pad bytes. */
2N/A rc = aes_decrypt_contiguous_blocks(
2N/A (aes_ctx_t *)kms_aes_ctx->aes_cbc,
2N/A (char *)in_buf + out_len, AES_BLOCK_LEN, &out);
2N/A
2N/A if (rc != 0)
2N/A goto decrypt_failed;
2N/A
2N/A /*
2N/A * Remove padding bytes after decryption of
2N/A * ciphertext block to produce the original
2N/A * plaintext.
2N/A */
2N/A rv = kms_remove_pkcs7_padding(last_block,
2N/A AES_BLOCK_LEN, &rem_len, AES_BLOCK_LEN);
2N/A if (rv == CKR_OK) {
2N/A if (rem_len != 0)
2N/A (void) memcpy(out_buf + out_len,
2N/A last_block, rem_len);
2N/A *pulDataLen = out_len + rem_len;
2N/A } else {
2N/A *pulDataLen = 0;
2N/A goto cleanup;
2N/A }
2N/A } else {
2N/A *pulDataLen = out_len;
2N/A }
2N/A
2N/A if (update) {
2N/A /*
2N/A * For decrypt update, if there is remaining data,
2N/A * save it and its length in the context.
2N/A */
2N/A if (remain != 0)
2N/A (void) memcpy(kms_aes_ctx->data, pEncrypted +
2N/A (ulEncryptedLen - remain), remain);
2N/A kms_aes_ctx->remain_len = remain;
2N/A }
2N/A
2N/A if (rc == 0)
2N/A break;
2N/Adecrypt_failed:
2N/A *pulDataLen = 0;
2N/A rv = CKR_FUNCTION_FAILED;
2N/A goto cleanup;
2N/A }
2N/A default:
2N/A rv = CKR_MECHANISM_INVALID;
2N/A goto cleanup;
2N/A } /* end switch */
2N/A
2N/A if (update)
2N/A return (CKR_OK);
2N/A
2N/A /*
2N/A * The following code will be executed if the caller is
2N/A * kms_decrypt() or an error occurred. The decryption
2N/A * operation will be terminated so we need to do some cleanup.
2N/A */
2N/Acleanup:
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A aes_ctx = (aes_ctx_t *)kms_aes_ctx->aes_cbc;
2N/A if (aes_ctx != NULL) {
2N/A bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len);
2N/A free(kms_aes_ctx->aes_cbc);
2N/A }
2N/A
2N/A bzero(kms_aes_ctx->key_sched, kms_aes_ctx->keysched_len);
2N/A free(kms_aes_ctx->key_sched);
2N/A free(session_p->decrypt.context);
2N/A session_p->decrypt.context = NULL;
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Allocate and initialize a context for AES CBC mode of operation.
2N/A */
2N/Avoid *
2N/Aaes_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec)
2N/A{
2N/A aes_ctx_t *aes_ctx;
2N/A
2N/A if ((aes_ctx = calloc(1, sizeof (aes_ctx_t))) == NULL)
2N/A return (NULL);
2N/A
2N/A aes_ctx->ac_keysched = key_sched;
2N/A
2N/A (void) memcpy(&aes_ctx->ac_iv[0], ivec, AES_BLOCK_LEN);
2N/A
2N/A aes_ctx->ac_lastp = (uint8_t *)aes_ctx->ac_iv;
2N/A aes_ctx->ac_keysched_len = size;
2N/A aes_ctx->ac_flags |= CBC_MODE;
2N/A
2N/A return ((void *)aes_ctx);
2N/A}
2N/A
2N/A/*
2N/A * kms_encrypt_final()
2N/A *
2N/A * Arguments:
2N/A * session_p: pointer to kms_session_t struct
2N/A * pLastEncryptedPart: pointer to the last encrypted data part
2N/A * pulLastEncryptedPartLen: pointer to the length of the last
2N/A * encrypted data part
2N/A *
2N/A * Description:
2N/A * called by C_EncryptFinal().
2N/A *
2N/A * Returns:
2N/A * CKR_OK: success
2N/A * CKR_FUNCTION_FAILED: encrypt final function failed
2N/A * CKR_DATA_LEN_RANGE: remaining buffer contains bad length
2N/A */
2N/ACK_RV
2N/Akms_aes_encrypt_final(kms_session_t *session_p, CK_BYTE_PTR pLastEncryptedPart,
2N/A CK_ULONG_PTR pulLastEncryptedPartLen)
2N/A{
2N/A
2N/A CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
2N/A CK_ULONG out_len;
2N/A CK_RV rv = CKR_OK;
2N/A int rc;
2N/A
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A
2N/A if (session_p->encrypt.context == NULL) {
2N/A rv = CKR_OPERATION_NOT_INITIALIZED;
2N/A *pulLastEncryptedPartLen = 0;
2N/A
2N/A }
2N/A if (mechanism == CKM_AES_CBC_PAD) {
2N/A kms_aes_ctx_t *aes_ctx;
2N/A
2N/A aes_ctx = (kms_aes_ctx_t *)session_p->encrypt.context;
2N/A /*
2N/A * For CKM_AES_CBC_PAD, compute output length with
2N/A * padding. If the remaining buffer has one block
2N/A * of data, then output length will be two blocksize of
2N/A * ciphertext. If the remaining buffer has less than
2N/A * one block of data, then output length will be
2N/A * one blocksize.
2N/A */
2N/A if (aes_ctx->remain_len == AES_BLOCK_LEN)
2N/A out_len = 2 * AES_BLOCK_LEN;
2N/A else
2N/A out_len = AES_BLOCK_LEN;
2N/A
2N/A if (pLastEncryptedPart == NULL) {
2N/A /*
2N/A * Application asks for the length of the output
2N/A * buffer to hold the ciphertext.
2N/A */
2N/A *pulLastEncryptedPartLen = out_len;
2N/A goto clean1;
2N/A } else {
2N/A crypto_data_t out;
2N/A
2N/A /* Copy remaining data to the output buffer. */
2N/A (void) memcpy(pLastEncryptedPart, aes_ctx->data,
2N/A aes_ctx->remain_len);
2N/A
2N/A /*
2N/A * Add padding bytes prior to encrypt final.
2N/A */
2N/A kms_add_pkcs7_padding(pLastEncryptedPart +
2N/A aes_ctx->remain_len, AES_BLOCK_LEN,
2N/A aes_ctx->remain_len);
2N/A
2N/A out.cd_format = CRYPTO_DATA_RAW;
2N/A out.cd_offset = 0;
2N/A out.cd_length = out_len;
2N/A out.cd_raw.iov_base = (char *)pLastEncryptedPart;
2N/A out.cd_raw.iov_len = out_len;
2N/A
2N/A /* Encrypt multiple blocks of data. */
2N/A rc = aes_encrypt_contiguous_blocks(
2N/A (aes_ctx_t *)aes_ctx->aes_cbc,
2N/A (char *)pLastEncryptedPart, out_len, &out);
2N/A
2N/A if (rc == 0) {
2N/A *pulLastEncryptedPartLen = out_len;
2N/A } else {
2N/A *pulLastEncryptedPartLen = 0;
2N/A rv = CKR_FUNCTION_FAILED;
2N/A }
2N/A
2N/A /* Cleanup memory space. */
2N/A free(aes_ctx->aes_cbc);
2N/A bzero(aes_ctx->key_sched,
2N/A aes_ctx->keysched_len);
2N/A free(aes_ctx->key_sched);
2N/A }
2N/A } else if (mechanism == CKM_AES_CBC) {
2N/A kms_aes_ctx_t *aes_ctx;
2N/A
2N/A aes_ctx = (kms_aes_ctx_t *)session_p->encrypt.context;
2N/A /*
2N/A * CKM_AES_CBC and CKM_AES_ECB does not do any padding,
2N/A * so when the final is called, the remaining buffer
2N/A * should not contain any more data.
2N/A */
2N/A *pulLastEncryptedPartLen = 0;
2N/A if (aes_ctx->remain_len != 0) {
2N/A rv = CKR_DATA_LEN_RANGE;
2N/A } else {
2N/A if (pLastEncryptedPart == NULL)
2N/A goto clean1;
2N/A }
2N/A
2N/A /* Cleanup memory space. */
2N/A free(aes_ctx->aes_cbc);
2N/A bzero(aes_ctx->key_sched, aes_ctx->keysched_len);
2N/A free(aes_ctx->key_sched);
2N/A } else {
2N/A rv = CKR_MECHANISM_INVALID;
2N/A }
2N/A
2N/A free(session_p->encrypt.context);
2N/A session_p->encrypt.context = NULL;
2N/Aclean1:
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * kms_decrypt_final()
2N/A *
2N/A * Arguments:
2N/A * session_p: pointer to kms_session_t struct
2N/A * pLastPart: pointer to the last recovered data part
2N/A * pulLastPartLen: pointer to the length of the last recovered data part
2N/A *
2N/A * Description:
2N/A * called by C_DecryptFinal().
2N/A *
2N/A * Returns:
2N/A * CKR_OK: success
2N/A * CKR_FUNCTION_FAILED: decrypt final function failed
2N/A * CKR_ENCRYPTED_DATA_LEN_RANGE: remaining buffer contains bad length
2N/A */
2N/ACK_RV
2N/Akms_aes_decrypt_final(kms_session_t *session_p, CK_BYTE_PTR pLastPart,
2N/A CK_ULONG_PTR pulLastPartLen)
2N/A{
2N/A
2N/A CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
2N/A CK_ULONG out_len;
2N/A CK_RV rv = CKR_OK;
2N/A int rc;
2N/A
2N/A (void) pthread_mutex_lock(&session_p->session_mutex);
2N/A
2N/A if (session_p->decrypt.context == NULL) {
2N/A rv = CKR_OPERATION_NOT_INITIALIZED;
2N/A *pulLastPartLen = 0;
2N/A goto clean2;
2N/A }
2N/A switch (mechanism) {
2N/A
2N/A case CKM_AES_CBC_PAD:
2N/A {
2N/A kms_aes_ctx_t *kms_aes_ctx;
2N/A kms_aes_ctx = (kms_aes_ctx_t *)session_p->decrypt.context;
2N/A
2N/A /*
2N/A * We should have only one block of data left in the
2N/A * remaining buffer.
2N/A */
2N/A if (kms_aes_ctx->remain_len != AES_BLOCK_LEN) {
2N/A *pulLastPartLen = 0;
2N/A rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
2N/A /* Cleanup memory space. */
2N/A free(kms_aes_ctx->aes_cbc);
2N/A bzero(kms_aes_ctx->key_sched,
2N/A kms_aes_ctx->keysched_len);
2N/A free(kms_aes_ctx->key_sched);
2N/A
2N/A goto clean1;
2N/A }
2N/A
2N/A out_len = AES_BLOCK_LEN;
2N/A
2N/A /*
2N/A * If application asks for the length of the output buffer
2N/A * to hold the plaintext?
2N/A */
2N/A if (pLastPart == NULL) {
2N/A *pulLastPartLen = out_len;
2N/A rv = CKR_OK;
2N/A goto clean2;
2N/A } else {
2N/A crypto_data_t out;
2N/A
2N/A /* Copy remaining data to the output buffer. */
2N/A (void) memcpy(pLastPart, kms_aes_ctx->data,
2N/A AES_BLOCK_LEN);
2N/A
2N/A out.cd_format = CRYPTO_DATA_RAW;
2N/A out.cd_offset = 0;
2N/A out.cd_length = AES_BLOCK_LEN;
2N/A out.cd_raw.iov_base = (char *)pLastPart;
2N/A out.cd_raw.iov_len = AES_BLOCK_LEN;
2N/A
2N/A /* Decrypt final block of data. */
2N/A rc = aes_decrypt_contiguous_blocks(
2N/A (aes_ctx_t *)kms_aes_ctx->aes_cbc,
2N/A (char *)pLastPart, AES_BLOCK_LEN, &out);
2N/A
2N/A if (rc == 0) {
2N/A /*
2N/A * Remove padding bytes after decryption of
2N/A * ciphertext block to produce the original
2N/A * plaintext.
2N/A */
2N/A rv = kms_remove_pkcs7_padding(pLastPart,
2N/A AES_BLOCK_LEN, &out_len, AES_BLOCK_LEN);
2N/A if (rv != CKR_OK)
2N/A *pulLastPartLen = 0;
2N/A else
2N/A *pulLastPartLen = out_len;
2N/A } else {
2N/A *pulLastPartLen = 0;
2N/A rv = CKR_FUNCTION_FAILED;
2N/A }
2N/A
2N/A /* Cleanup memory space. */
2N/A free(kms_aes_ctx->aes_cbc);
2N/A bzero(kms_aes_ctx->key_sched,
2N/A kms_aes_ctx->keysched_len);
2N/A free(kms_aes_ctx->key_sched);
2N/A
2N/A }
2N/A
2N/A break;
2N/A }
2N/A
2N/A case CKM_AES_CBC:
2N/A {
2N/A kms_aes_ctx_t *kms_aes_ctx;
2N/A
2N/A kms_aes_ctx = (kms_aes_ctx_t *)session_p->decrypt.context;
2N/A /*
2N/A * CKM_AES_CBC and CKM_AES_ECB does not do any padding,
2N/A * so when the final is called, the remaining buffer
2N/A * should not contain any more data.
2N/A */
2N/A *pulLastPartLen = 0;
2N/A if (kms_aes_ctx->remain_len != 0) {
2N/A rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
2N/A } else {
2N/A if (pLastPart == NULL)
2N/A goto clean2;
2N/A }
2N/A
2N/A /* Cleanup memory space. */
2N/A free(kms_aes_ctx->aes_cbc);
2N/A bzero(kms_aes_ctx->key_sched, kms_aes_ctx->keysched_len);
2N/A free(kms_aes_ctx->key_sched);
2N/A
2N/A break;
2N/A }
2N/A default:
2N/A /* PKCS11: The mechanism only supports single-part operation. */
2N/A rv = CKR_MECHANISM_INVALID;
2N/A break;
2N/A }
2N/A
2N/Aclean1:
2N/A free(session_p->decrypt.context);
2N/A session_p->decrypt.context = NULL;
2N/A
2N/Aclean2:
2N/A (void) pthread_mutex_unlock(&session_p->session_mutex);
2N/A
2N/A return (rv);
2N/A
2N/A}