17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
59627968bSmcpowers * Common Development and Distribution License (the "License").
69627968bSmcpowers * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21*726fad2aSDina K Nimeh
227c478bd9Sstevel@tonic-gate /*
23*726fad2aSDina K Nimeh * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #include <pthread.h>
277c478bd9Sstevel@tonic-gate #include <stdlib.h>
287c478bd9Sstevel@tonic-gate #include <string.h>
297c478bd9Sstevel@tonic-gate #include <strings.h>
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
327c478bd9Sstevel@tonic-gate #include "softSession.h"
337c478bd9Sstevel@tonic-gate #include "softObject.h"
347c478bd9Sstevel@tonic-gate #include "softCrypt.h"
3523c57df7Smcpowers #include <aes_impl.h>
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate * Allocate context for the active encryption or decryption operation, and
397c478bd9Sstevel@tonic-gate * generate AES key schedule to speed up the operation.
407c478bd9Sstevel@tonic-gate */
417c478bd9Sstevel@tonic-gate CK_RV
soft_aes_crypt_init_common(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p,boolean_t encrypt)427c478bd9Sstevel@tonic-gate soft_aes_crypt_init_common(soft_session_t *session_p,
437c478bd9Sstevel@tonic-gate CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
447c478bd9Sstevel@tonic-gate boolean_t encrypt)
457c478bd9Sstevel@tonic-gate {
467c478bd9Sstevel@tonic-gate size_t size;
477c478bd9Sstevel@tonic-gate soft_aes_ctx_t *soft_aes_ctx;
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate soft_aes_ctx = calloc(1, sizeof (soft_aes_ctx_t));
507c478bd9Sstevel@tonic-gate if (soft_aes_ctx == NULL) {
517c478bd9Sstevel@tonic-gate return (CKR_HOST_MEMORY);
527c478bd9Sstevel@tonic-gate }
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate soft_aes_ctx->key_sched = aes_alloc_keysched(&size, 0);
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate if (soft_aes_ctx->key_sched == NULL) {
577c478bd9Sstevel@tonic-gate free(soft_aes_ctx);
587c478bd9Sstevel@tonic-gate return (CKR_HOST_MEMORY);
597c478bd9Sstevel@tonic-gate }
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate soft_aes_ctx->keysched_len = size;
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&session_p->session_mutex);
647c478bd9Sstevel@tonic-gate if (encrypt) {
657c478bd9Sstevel@tonic-gate /* Called by C_EncryptInit. */
667c478bd9Sstevel@tonic-gate session_p->encrypt.context = soft_aes_ctx;
677c478bd9Sstevel@tonic-gate session_p->encrypt.mech.mechanism = pMechanism->mechanism;
687c478bd9Sstevel@tonic-gate } else {
697c478bd9Sstevel@tonic-gate /* Called by C_DecryptInit. */
707c478bd9Sstevel@tonic-gate session_p->decrypt.context = soft_aes_ctx;
717c478bd9Sstevel@tonic-gate session_p->decrypt.mech.mechanism = pMechanism->mechanism;
727c478bd9Sstevel@tonic-gate }
737c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&session_p->session_mutex);
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate * If this is a non-sensitive key and it does NOT have
777c478bd9Sstevel@tonic-gate * a key schedule yet, then allocate one and expand it.
787c478bd9Sstevel@tonic-gate * Otherwise, if it's a non-sensitive key, and it DOES have
797c478bd9Sstevel@tonic-gate * a key schedule already attached to it, just copy the
807c478bd9Sstevel@tonic-gate * pre-expanded schedule to the context and avoid the
817c478bd9Sstevel@tonic-gate * extra key schedule expansion operation.
827c478bd9Sstevel@tonic-gate */
837c478bd9Sstevel@tonic-gate if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
849627968bSmcpowers if (OBJ_KEY_SCHED(key_p) == NULL) {
857c478bd9Sstevel@tonic-gate void *ks;
869627968bSmcpowers
879627968bSmcpowers (void) pthread_mutex_lock(&key_p->object_mutex);
889627968bSmcpowers if (OBJ_KEY_SCHED(key_p) == NULL) {
897c478bd9Sstevel@tonic-gate ks = aes_alloc_keysched(&size, 0);
909627968bSmcpowers if (ks == NULL) {
919627968bSmcpowers (void) pthread_mutex_unlock(
929627968bSmcpowers &key_p->object_mutex);
937c478bd9Sstevel@tonic-gate free(soft_aes_ctx);
947c478bd9Sstevel@tonic-gate return (CKR_HOST_MEMORY);
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate #ifdef __sparcv9
977c478bd9Sstevel@tonic-gate /* LINTED */
987c478bd9Sstevel@tonic-gate aes_init_keysched(OBJ_SEC_VALUE(key_p), (uint_t)
999627968bSmcpowers (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
1007c478bd9Sstevel@tonic-gate #else /* !__sparcv9 */
1017c478bd9Sstevel@tonic-gate aes_init_keysched(OBJ_SEC_VALUE(key_p),
1029627968bSmcpowers (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
1037c478bd9Sstevel@tonic-gate #endif /* __sparcv9 */
1049627968bSmcpowers OBJ_KEY_SCHED_LEN(key_p) = size;
1059627968bSmcpowers OBJ_KEY_SCHED(key_p) = ks;
1069627968bSmcpowers }
1079627968bSmcpowers (void) pthread_mutex_unlock(&key_p->object_mutex);
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate (void) memcpy(soft_aes_ctx->key_sched, OBJ_KEY_SCHED(key_p),
1107c478bd9Sstevel@tonic-gate OBJ_KEY_SCHED_LEN(key_p));
1117c478bd9Sstevel@tonic-gate soft_aes_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
1127c478bd9Sstevel@tonic-gate } else {
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate * Initialize key schedule for AES. aes_init_keysched()
1157c478bd9Sstevel@tonic-gate * requires key length in bits.
1167c478bd9Sstevel@tonic-gate */
1177c478bd9Sstevel@tonic-gate #ifdef __sparcv9
1187c478bd9Sstevel@tonic-gate /* LINTED */
1197c478bd9Sstevel@tonic-gate aes_init_keysched(OBJ_SEC_VALUE(key_p), (uint_t)
1209627968bSmcpowers (OBJ_SEC_VALUE_LEN(key_p) * 8), soft_aes_ctx->key_sched);
1217c478bd9Sstevel@tonic-gate #else /* !__sparcv9 */
1227c478bd9Sstevel@tonic-gate aes_init_keysched(OBJ_SEC_VALUE(key_p),
1239627968bSmcpowers (OBJ_SEC_VALUE_LEN(key_p) * 8), soft_aes_ctx->key_sched);
1247c478bd9Sstevel@tonic-gate #endif /* __sparcv9 */
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate return (CKR_OK);
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate * soft_aes_encrypt_common()
1327c478bd9Sstevel@tonic-gate *
1337c478bd9Sstevel@tonic-gate * Arguments:
1347c478bd9Sstevel@tonic-gate * session_p: pointer to soft_session_t struct
1357c478bd9Sstevel@tonic-gate * pData: pointer to the input data to be encrypted
1367c478bd9Sstevel@tonic-gate * ulDataLen: length of the input data
1377c478bd9Sstevel@tonic-gate * pEncrypted: pointer to the output data after encryption
1387c478bd9Sstevel@tonic-gate * pulEncryptedLen: pointer to the length of the output data
1397c478bd9Sstevel@tonic-gate * update: boolean flag indicates caller is soft_encrypt
1407c478bd9Sstevel@tonic-gate * or soft_encrypt_update
1417c478bd9Sstevel@tonic-gate *
1427c478bd9Sstevel@tonic-gate * Description:
1437c478bd9Sstevel@tonic-gate * This function calls the corresponding encrypt routine based
1447c478bd9Sstevel@tonic-gate * on the mechanism.
1457c478bd9Sstevel@tonic-gate *
1467c478bd9Sstevel@tonic-gate * Returns:
1477c478bd9Sstevel@tonic-gate * CKR_OK: success
1487c478bd9Sstevel@tonic-gate * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
1497c478bd9Sstevel@tonic-gate * is too small
1507c478bd9Sstevel@tonic-gate * CKR_FUNCTION_FAILED: encrypt function failed
1517c478bd9Sstevel@tonic-gate * CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
1527c478bd9Sstevel@tonic-gate */
1537c478bd9Sstevel@tonic-gate CK_RV
soft_aes_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)1547c478bd9Sstevel@tonic-gate soft_aes_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
1557c478bd9Sstevel@tonic-gate CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted,
1567c478bd9Sstevel@tonic-gate CK_ULONG_PTR pulEncryptedLen, boolean_t update)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate int rc = 0;
1607c478bd9Sstevel@tonic-gate CK_RV rv = CKR_OK;
1617c478bd9Sstevel@tonic-gate soft_aes_ctx_t *soft_aes_ctx =
1627c478bd9Sstevel@tonic-gate (soft_aes_ctx_t *)session_p->encrypt.context;
1637c478bd9Sstevel@tonic-gate aes_ctx_t *aes_ctx;
1647c478bd9Sstevel@tonic-gate CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
1657c478bd9Sstevel@tonic-gate CK_BYTE *in_buf = NULL;
1667c478bd9Sstevel@tonic-gate CK_BYTE *out_buf = NULL;
1677c478bd9Sstevel@tonic-gate CK_ULONG out_len;
1687c478bd9Sstevel@tonic-gate CK_ULONG total_len;
1697c478bd9Sstevel@tonic-gate CK_ULONG remain;
1707c478bd9Sstevel@tonic-gate
17123c57df7Smcpowers if (mechanism == CKM_AES_CTR)
17223c57df7Smcpowers goto do_encryption;
17323c57df7Smcpowers
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate * AES only takes input length that is a multiple of blocksize
1767c478bd9Sstevel@tonic-gate * for C_Encrypt function with the mechanism CKM_AES_ECB or
1777c478bd9Sstevel@tonic-gate * CKM_AES_CBC.
1787c478bd9Sstevel@tonic-gate *
1797c478bd9Sstevel@tonic-gate * AES allows any input length for C_Encrypt function with the
1807c478bd9Sstevel@tonic-gate * mechanism CKM_AES_CBC_PAD and for C_EncryptUpdate function.
1817c478bd9Sstevel@tonic-gate */
1827c478bd9Sstevel@tonic-gate if ((!update) && (mechanism != CKM_AES_CBC_PAD)) {
1837c478bd9Sstevel@tonic-gate if ((ulDataLen % AES_BLOCK_LEN) != 0) {
1847c478bd9Sstevel@tonic-gate rv = CKR_DATA_LEN_RANGE;
1857c478bd9Sstevel@tonic-gate goto cleanup;
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate if (!update) {
1907c478bd9Sstevel@tonic-gate /*
1917c478bd9Sstevel@tonic-gate * Called by C_Encrypt
1927c478bd9Sstevel@tonic-gate */
1937c478bd9Sstevel@tonic-gate if (mechanism == CKM_AES_CBC_PAD) {
1947c478bd9Sstevel@tonic-gate /*
1957c478bd9Sstevel@tonic-gate * For CKM_AES_CBC_PAD, compute output length to
1967c478bd9Sstevel@tonic-gate * count for the padding. If the length of input
1977c478bd9Sstevel@tonic-gate * data is a multiple of blocksize, then make output
1987c478bd9Sstevel@tonic-gate * length to be the sum of the input length and
1997c478bd9Sstevel@tonic-gate * one blocksize. Otherwise, output length will
2007c478bd9Sstevel@tonic-gate * be rounded up to the next multiple of blocksize.
2017c478bd9Sstevel@tonic-gate */
2027c478bd9Sstevel@tonic-gate out_len = AES_BLOCK_LEN *
2037c478bd9Sstevel@tonic-gate (ulDataLen / AES_BLOCK_LEN + 1);
2047c478bd9Sstevel@tonic-gate } else {
2057c478bd9Sstevel@tonic-gate /*
2067c478bd9Sstevel@tonic-gate * For non-padding mode, the output length will
2077c478bd9Sstevel@tonic-gate * be same as the input length.
2087c478bd9Sstevel@tonic-gate */
2097c478bd9Sstevel@tonic-gate out_len = ulDataLen;
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate * If application asks for the length of the output buffer
2147c478bd9Sstevel@tonic-gate * to hold the ciphertext?
2157c478bd9Sstevel@tonic-gate */
2167c478bd9Sstevel@tonic-gate if (pEncrypted == NULL) {
2177c478bd9Sstevel@tonic-gate *pulEncryptedLen = out_len;
2187c478bd9Sstevel@tonic-gate return (CKR_OK);
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate /* Is the application-supplied buffer large enough? */
2227c478bd9Sstevel@tonic-gate if (*pulEncryptedLen < out_len) {
2237c478bd9Sstevel@tonic-gate *pulEncryptedLen = out_len;
2247c478bd9Sstevel@tonic-gate return (CKR_BUFFER_TOO_SMALL);
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate /* Encrypt pad bytes in a separate operation */
2287c478bd9Sstevel@tonic-gate if (mechanism == CKM_AES_CBC_PAD) {
2297c478bd9Sstevel@tonic-gate out_len -= AES_BLOCK_LEN;
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate in_buf = pData;
2337c478bd9Sstevel@tonic-gate out_buf = pEncrypted;
2347c478bd9Sstevel@tonic-gate } else {
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate * Called by C_EncryptUpdate
2377c478bd9Sstevel@tonic-gate *
2387c478bd9Sstevel@tonic-gate * Add the lengths of last remaining data and current
2397c478bd9Sstevel@tonic-gate * plaintext together to get the total input length.
2407c478bd9Sstevel@tonic-gate */
2417c478bd9Sstevel@tonic-gate total_len = soft_aes_ctx->remain_len + ulDataLen;
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate /*
2447c478bd9Sstevel@tonic-gate * If the total input length is less than one blocksize,
2457c478bd9Sstevel@tonic-gate * or if the total input length is just one blocksize and
2467c478bd9Sstevel@tonic-gate * the mechanism is CKM_AES_CBC_PAD, we will need to delay
2477c478bd9Sstevel@tonic-gate * encryption until when more data comes in next
2487c478bd9Sstevel@tonic-gate * C_EncryptUpdate or when C_EncryptFinal is called.
2497c478bd9Sstevel@tonic-gate */
2507c478bd9Sstevel@tonic-gate if ((total_len < AES_BLOCK_LEN) ||
2517c478bd9Sstevel@tonic-gate ((mechanism == CKM_AES_CBC_PAD) &&
2527c478bd9Sstevel@tonic-gate (total_len == AES_BLOCK_LEN))) {
2537c478bd9Sstevel@tonic-gate if (pEncrypted != NULL) {
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate * Save input data and its length in
2567c478bd9Sstevel@tonic-gate * the remaining buffer of AES context.
2577c478bd9Sstevel@tonic-gate */
2587c478bd9Sstevel@tonic-gate (void) memcpy(soft_aes_ctx->data +
2597c478bd9Sstevel@tonic-gate soft_aes_ctx->remain_len, pData, ulDataLen);
2607c478bd9Sstevel@tonic-gate soft_aes_ctx->remain_len += ulDataLen;
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate /* Set encrypted data length to 0. */
2647c478bd9Sstevel@tonic-gate *pulEncryptedLen = 0;
2657c478bd9Sstevel@tonic-gate return (CKR_OK);
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate /* Compute the length of remaing data. */
2697c478bd9Sstevel@tonic-gate remain = total_len % AES_BLOCK_LEN;
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate * Make sure that the output length is a multiple of
2737c478bd9Sstevel@tonic-gate * blocksize.
2747c478bd9Sstevel@tonic-gate */
2757c478bd9Sstevel@tonic-gate out_len = total_len - remain;
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate /*
2787c478bd9Sstevel@tonic-gate * If application asks for the length of the output buffer
2797c478bd9Sstevel@tonic-gate * to hold the ciphertext?
2807c478bd9Sstevel@tonic-gate */
2817c478bd9Sstevel@tonic-gate if (pEncrypted == NULL) {
2827c478bd9Sstevel@tonic-gate *pulEncryptedLen = out_len;
2837c478bd9Sstevel@tonic-gate return (CKR_OK);
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate /* Is the application-supplied buffer large enough? */
2877c478bd9Sstevel@tonic-gate if (*pulEncryptedLen < out_len) {
2887c478bd9Sstevel@tonic-gate *pulEncryptedLen = out_len;
2897c478bd9Sstevel@tonic-gate return (CKR_BUFFER_TOO_SMALL);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate if (soft_aes_ctx->remain_len != 0) {
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate * Copy last remaining data and current input data
2957c478bd9Sstevel@tonic-gate * to the output buffer.
2967c478bd9Sstevel@tonic-gate */
2977c478bd9Sstevel@tonic-gate (void) memmove(pEncrypted + soft_aes_ctx->remain_len,
2987c478bd9Sstevel@tonic-gate pData, out_len - soft_aes_ctx->remain_len);
2997c478bd9Sstevel@tonic-gate (void) memcpy(pEncrypted, soft_aes_ctx->data,
3007c478bd9Sstevel@tonic-gate soft_aes_ctx->remain_len);
3017c478bd9Sstevel@tonic-gate bzero(soft_aes_ctx->data, soft_aes_ctx->remain_len);
3027c478bd9Sstevel@tonic-gate
3037c478bd9Sstevel@tonic-gate in_buf = pEncrypted;
3047c478bd9Sstevel@tonic-gate } else {
3057c478bd9Sstevel@tonic-gate in_buf = pData;
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate out_buf = pEncrypted;
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate
31023c57df7Smcpowers do_encryption:
3117c478bd9Sstevel@tonic-gate /*
3127c478bd9Sstevel@tonic-gate * Begin Encryption now.
3137c478bd9Sstevel@tonic-gate */
3147c478bd9Sstevel@tonic-gate switch (mechanism) {
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate case CKM_AES_ECB:
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate ulong_t i;
3207c478bd9Sstevel@tonic-gate uint8_t *tmp_inbuf;
3217c478bd9Sstevel@tonic-gate uint8_t *tmp_outbuf;
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate for (i = 0; i < out_len; i += AES_BLOCK_LEN) {
3247c478bd9Sstevel@tonic-gate tmp_inbuf = &in_buf[i];
3257c478bd9Sstevel@tonic-gate tmp_outbuf = &out_buf[i];
3267c478bd9Sstevel@tonic-gate /* Crunch one block of data for AES. */
32723c57df7Smcpowers (void) aes_encrypt_block(soft_aes_ctx->key_sched,
3287c478bd9Sstevel@tonic-gate tmp_inbuf, tmp_outbuf);
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate if (update) {
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate * For encrypt update, if there is a remaining
3347c478bd9Sstevel@tonic-gate * data, save it and its length in the context.
3357c478bd9Sstevel@tonic-gate */
3367c478bd9Sstevel@tonic-gate if (remain != 0)
3377c478bd9Sstevel@tonic-gate (void) memcpy(soft_aes_ctx->data, pData +
3387c478bd9Sstevel@tonic-gate (ulDataLen - remain), remain);
3397c478bd9Sstevel@tonic-gate soft_aes_ctx->remain_len = remain;
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate *pulEncryptedLen = out_len;
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate break;
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate case CKM_AES_CBC:
3487c478bd9Sstevel@tonic-gate case CKM_AES_CBC_PAD:
3497c478bd9Sstevel@tonic-gate {
3507c478bd9Sstevel@tonic-gate crypto_data_t out;
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate out.cd_format = CRYPTO_DATA_RAW;
3537c478bd9Sstevel@tonic-gate out.cd_offset = 0;
3547c478bd9Sstevel@tonic-gate out.cd_length = out_len;
3557c478bd9Sstevel@tonic-gate out.cd_raw.iov_base = (char *)out_buf;
3567c478bd9Sstevel@tonic-gate out.cd_raw.iov_len = out_len;
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate /* Encrypt multiple blocks of data. */
3597c478bd9Sstevel@tonic-gate rc = aes_encrypt_contiguous_blocks(
3607c478bd9Sstevel@tonic-gate (aes_ctx_t *)soft_aes_ctx->aes_cbc,
3617c478bd9Sstevel@tonic-gate (char *)in_buf, out_len, &out);
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate if (rc != 0)
3647c478bd9Sstevel@tonic-gate goto encrypt_failed;
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate if (update) {
3677c478bd9Sstevel@tonic-gate /*
3687c478bd9Sstevel@tonic-gate * For encrypt update, if there is remaining data,
3697c478bd9Sstevel@tonic-gate * save it and its length in the context.
3707c478bd9Sstevel@tonic-gate */
3717c478bd9Sstevel@tonic-gate if (remain != 0)
3727c478bd9Sstevel@tonic-gate (void) memcpy(soft_aes_ctx->data, pData +
3737c478bd9Sstevel@tonic-gate (ulDataLen - remain), remain);
3747c478bd9Sstevel@tonic-gate soft_aes_ctx->remain_len = remain;
3757c478bd9Sstevel@tonic-gate } else if (mechanism == CKM_AES_CBC_PAD) {
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate * Save the remainder of the input
3787c478bd9Sstevel@tonic-gate * block in a temporary block because
3797c478bd9Sstevel@tonic-gate * we dont want to overrun the buffer
3807c478bd9Sstevel@tonic-gate * by tacking on pad bytes.
3817c478bd9Sstevel@tonic-gate */
3827c478bd9Sstevel@tonic-gate CK_BYTE tmpblock[AES_BLOCK_LEN];
3837c478bd9Sstevel@tonic-gate (void) memcpy(tmpblock, in_buf + out_len,
3847c478bd9Sstevel@tonic-gate ulDataLen - out_len);
3857c478bd9Sstevel@tonic-gate soft_add_pkcs7_padding(tmpblock +
3867c478bd9Sstevel@tonic-gate (ulDataLen - out_len),
3877c478bd9Sstevel@tonic-gate AES_BLOCK_LEN, ulDataLen - out_len);
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate out.cd_offset = out_len;
3907c478bd9Sstevel@tonic-gate out.cd_length = AES_BLOCK_LEN;
3917c478bd9Sstevel@tonic-gate out.cd_raw.iov_base = (char *)out_buf;
3927c478bd9Sstevel@tonic-gate out.cd_raw.iov_len = out_len + AES_BLOCK_LEN;
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate /* Encrypt last block containing pad bytes. */
3957c478bd9Sstevel@tonic-gate rc = aes_encrypt_contiguous_blocks(
3967c478bd9Sstevel@tonic-gate (aes_ctx_t *)soft_aes_ctx->aes_cbc,
3977c478bd9Sstevel@tonic-gate (char *)tmpblock, AES_BLOCK_LEN, &out);
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate out_len += AES_BLOCK_LEN;
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate
4027c478bd9Sstevel@tonic-gate if (rc == 0) {
4037c478bd9Sstevel@tonic-gate *pulEncryptedLen = out_len;
4047c478bd9Sstevel@tonic-gate break;
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate encrypt_failed:
4077c478bd9Sstevel@tonic-gate *pulEncryptedLen = 0;
4087c478bd9Sstevel@tonic-gate rv = CKR_FUNCTION_FAILED;
4097c478bd9Sstevel@tonic-gate goto cleanup;
4107c478bd9Sstevel@tonic-gate }
41123c57df7Smcpowers case CKM_AES_CTR:
41223c57df7Smcpowers {
41323c57df7Smcpowers crypto_data_t out;
41423c57df7Smcpowers
41523c57df7Smcpowers out.cd_format = CRYPTO_DATA_RAW;
41623c57df7Smcpowers out.cd_offset = 0;
41723c57df7Smcpowers out.cd_length = *pulEncryptedLen;
41823c57df7Smcpowers out.cd_raw.iov_base = (char *)pEncrypted;
41923c57df7Smcpowers out.cd_raw.iov_len = *pulEncryptedLen;
42023c57df7Smcpowers
42123c57df7Smcpowers rc = aes_encrypt_contiguous_blocks(soft_aes_ctx->aes_cbc,
42223c57df7Smcpowers (char *)pData, ulDataLen, &out);
42323c57df7Smcpowers
42423c57df7Smcpowers if (rc != 0) {
42523c57df7Smcpowers *pulEncryptedLen = 0;
42623c57df7Smcpowers rv = CKR_FUNCTION_FAILED;
42723c57df7Smcpowers goto cleanup;
42823c57df7Smcpowers }
42923c57df7Smcpowers /*
43023c57df7Smcpowers * Since AES counter mode is a stream cipher, we call
43123c57df7Smcpowers * aes_counter_final() to pick up any remaining bytes.
43223c57df7Smcpowers * It is an internal function that does not destroy
43323c57df7Smcpowers * the context like *normal* final routines.
43423c57df7Smcpowers */
43523c57df7Smcpowers if (((aes_ctx_t *)soft_aes_ctx->aes_cbc)->ac_remainder_len > 0)
43623c57df7Smcpowers rc = ctr_mode_final(soft_aes_ctx->aes_cbc, &out,
43723c57df7Smcpowers aes_encrypt_block);
43823c57df7Smcpowers }
4397c478bd9Sstevel@tonic-gate } /* end switch */
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate if (update)
4427c478bd9Sstevel@tonic-gate return (CKR_OK);
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate /*
4457c478bd9Sstevel@tonic-gate * The following code will be executed if the caller is
4467c478bd9Sstevel@tonic-gate * soft_encrypt() or an error occurred. The encryption
4477c478bd9Sstevel@tonic-gate * operation will be terminated so we need to do some cleanup.
4487c478bd9Sstevel@tonic-gate */
4497c478bd9Sstevel@tonic-gate cleanup:
4507c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&session_p->session_mutex);
4517c478bd9Sstevel@tonic-gate aes_ctx = (aes_ctx_t *)soft_aes_ctx->aes_cbc;
4527c478bd9Sstevel@tonic-gate if (aes_ctx != NULL) {
4537c478bd9Sstevel@tonic-gate bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len);
4547c478bd9Sstevel@tonic-gate free(soft_aes_ctx->aes_cbc);
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate
4577c478bd9Sstevel@tonic-gate bzero(soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len);
4587c478bd9Sstevel@tonic-gate free(soft_aes_ctx->key_sched);
4597c478bd9Sstevel@tonic-gate free(session_p->encrypt.context);
4607c478bd9Sstevel@tonic-gate session_p->encrypt.context = NULL;
4617c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&session_p->session_mutex);
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate return (rv);
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate /*
4687c478bd9Sstevel@tonic-gate * soft_aes_decrypt_common()
4697c478bd9Sstevel@tonic-gate *
4707c478bd9Sstevel@tonic-gate * Arguments:
4717c478bd9Sstevel@tonic-gate * session_p: pointer to soft_session_t struct
4727c478bd9Sstevel@tonic-gate * pEncrypted: pointer to the input data to be decrypted
4737c478bd9Sstevel@tonic-gate * ulEncryptedLen: length of the input data
4747c478bd9Sstevel@tonic-gate * pData: pointer to the output data
4757c478bd9Sstevel@tonic-gate * pulDataLen: pointer to the length of the output data
4767c478bd9Sstevel@tonic-gate * Update: boolean flag indicates caller is soft_decrypt
4777c478bd9Sstevel@tonic-gate * or soft_decrypt_update
4787c478bd9Sstevel@tonic-gate *
4797c478bd9Sstevel@tonic-gate * Description:
4807c478bd9Sstevel@tonic-gate * This function calls the corresponding decrypt routine based
4817c478bd9Sstevel@tonic-gate * on the mechanism.
4827c478bd9Sstevel@tonic-gate *
4837c478bd9Sstevel@tonic-gate * Returns:
4847c478bd9Sstevel@tonic-gate * CKR_OK: success
4857c478bd9Sstevel@tonic-gate * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
4867c478bd9Sstevel@tonic-gate * is too small
4877c478bd9Sstevel@tonic-gate * CKR_ENCRYPTED_DATA_LEN_RANGE: the input data is not a multiple
4887c478bd9Sstevel@tonic-gate * of blocksize
4897c478bd9Sstevel@tonic-gate * CKR_FUNCTION_FAILED: decrypt function failed
4907c478bd9Sstevel@tonic-gate */
4917c478bd9Sstevel@tonic-gate CK_RV
soft_aes_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)4927c478bd9Sstevel@tonic-gate soft_aes_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted,
4937c478bd9Sstevel@tonic-gate CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData,
4947c478bd9Sstevel@tonic-gate CK_ULONG_PTR pulDataLen, boolean_t update)
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate int rc = 0;
4987c478bd9Sstevel@tonic-gate CK_RV rv = CKR_OK;
4997c478bd9Sstevel@tonic-gate soft_aes_ctx_t *soft_aes_ctx =
5007c478bd9Sstevel@tonic-gate (soft_aes_ctx_t *)session_p->decrypt.context;
5017c478bd9Sstevel@tonic-gate aes_ctx_t *aes_ctx;
5027c478bd9Sstevel@tonic-gate CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
5037c478bd9Sstevel@tonic-gate CK_BYTE *in_buf = NULL;
5047c478bd9Sstevel@tonic-gate CK_BYTE *out_buf = NULL;
5057c478bd9Sstevel@tonic-gate CK_ULONG out_len;
5067c478bd9Sstevel@tonic-gate CK_ULONG total_len;
5077c478bd9Sstevel@tonic-gate CK_ULONG remain;
5087c478bd9Sstevel@tonic-gate
50923c57df7Smcpowers if (mechanism == CKM_AES_CTR)
51023c57df7Smcpowers goto do_decryption;
51123c57df7Smcpowers
5127c478bd9Sstevel@tonic-gate /*
5137c478bd9Sstevel@tonic-gate * AES only takes input length that is a multiple of 16 bytes
5147c478bd9Sstevel@tonic-gate * for C_Decrypt function with the mechanism CKM_AES_ECB,
5157c478bd9Sstevel@tonic-gate * CKM_AES_CBC or CKM_AES_CBC_PAD.
5167c478bd9Sstevel@tonic-gate *
5177c478bd9Sstevel@tonic-gate * AES allows any input length for C_DecryptUpdate function.
5187c478bd9Sstevel@tonic-gate */
5197c478bd9Sstevel@tonic-gate if (!update) {
5207c478bd9Sstevel@tonic-gate /*
5217c478bd9Sstevel@tonic-gate * Called by C_Decrypt
5227c478bd9Sstevel@tonic-gate */
5237c478bd9Sstevel@tonic-gate if ((ulEncryptedLen % AES_BLOCK_LEN) != 0) {
5247c478bd9Sstevel@tonic-gate rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
5257c478bd9Sstevel@tonic-gate goto cleanup;
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate /*
5297c478bd9Sstevel@tonic-gate * If application asks for the length of the output buffer
5307c478bd9Sstevel@tonic-gate * to hold the plaintext?
5317c478bd9Sstevel@tonic-gate */
5327c478bd9Sstevel@tonic-gate if (pData == NULL) {
5337c478bd9Sstevel@tonic-gate *pulDataLen = ulEncryptedLen;
5347c478bd9Sstevel@tonic-gate return (CKR_OK);
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate /* Is the application-supplied buffer large enough? */
5387c478bd9Sstevel@tonic-gate if (mechanism != CKM_AES_CBC_PAD) {
5397c478bd9Sstevel@tonic-gate if (*pulDataLen < ulEncryptedLen) {
5407c478bd9Sstevel@tonic-gate *pulDataLen = ulEncryptedLen;
5417c478bd9Sstevel@tonic-gate return (CKR_BUFFER_TOO_SMALL);
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate out_len = ulEncryptedLen;
5447c478bd9Sstevel@tonic-gate } else {
5457c478bd9Sstevel@tonic-gate /*
5467c478bd9Sstevel@tonic-gate * For CKM_AES_CBC_PAD, we don't know how
5477c478bd9Sstevel@tonic-gate * many bytes for padding at this time, so
5487c478bd9Sstevel@tonic-gate * we'd assume one block was padded.
5497c478bd9Sstevel@tonic-gate */
5507c478bd9Sstevel@tonic-gate if (*pulDataLen < (ulEncryptedLen - AES_BLOCK_LEN)) {
5517c478bd9Sstevel@tonic-gate *pulDataLen = ulEncryptedLen - AES_BLOCK_LEN;
5527c478bd9Sstevel@tonic-gate return (CKR_BUFFER_TOO_SMALL);
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate out_len = ulEncryptedLen - AES_BLOCK_LEN;
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate in_buf = pEncrypted;
5577c478bd9Sstevel@tonic-gate out_buf = pData;
5587c478bd9Sstevel@tonic-gate } else {
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate * Called by C_DecryptUpdate
5617c478bd9Sstevel@tonic-gate *
5627c478bd9Sstevel@tonic-gate * Add the lengths of last remaining data and current
5637c478bd9Sstevel@tonic-gate * input data together to get the total input length.
5647c478bd9Sstevel@tonic-gate */
5657c478bd9Sstevel@tonic-gate total_len = soft_aes_ctx->remain_len + ulEncryptedLen;
5667c478bd9Sstevel@tonic-gate
5677c478bd9Sstevel@tonic-gate /*
5687c478bd9Sstevel@tonic-gate * If the total input length is less than one blocksize,
5697c478bd9Sstevel@tonic-gate * or if the total input length is just one blocksize and
5707c478bd9Sstevel@tonic-gate * the mechanism is CKM_AES_CBC_PAD, we will need to delay
5717c478bd9Sstevel@tonic-gate * decryption until when more data comes in next
5727c478bd9Sstevel@tonic-gate * C_DecryptUpdate or when C_DecryptFinal is called.
5737c478bd9Sstevel@tonic-gate */
5747c478bd9Sstevel@tonic-gate if ((total_len < AES_BLOCK_LEN) ||
5757c478bd9Sstevel@tonic-gate ((mechanism == CKM_AES_CBC_PAD) &&
5767c478bd9Sstevel@tonic-gate (total_len == AES_BLOCK_LEN))) {
5777c478bd9Sstevel@tonic-gate if (pData != NULL) {
5787c478bd9Sstevel@tonic-gate /*
5797c478bd9Sstevel@tonic-gate * Save input data and its length in
5807c478bd9Sstevel@tonic-gate * the remaining buffer of AES context.
5817c478bd9Sstevel@tonic-gate */
5827c478bd9Sstevel@tonic-gate (void) memcpy(soft_aes_ctx->data +
5837c478bd9Sstevel@tonic-gate soft_aes_ctx->remain_len,
5847c478bd9Sstevel@tonic-gate pEncrypted, ulEncryptedLen);
5857c478bd9Sstevel@tonic-gate soft_aes_ctx->remain_len += ulEncryptedLen;
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate
5887c478bd9Sstevel@tonic-gate /* Set output data length to 0. */
5897c478bd9Sstevel@tonic-gate *pulDataLen = 0;
5907c478bd9Sstevel@tonic-gate return (CKR_OK);
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate
5937c478bd9Sstevel@tonic-gate /* Compute the length of remaing data. */
5947c478bd9Sstevel@tonic-gate remain = total_len % AES_BLOCK_LEN;
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate /*
5977c478bd9Sstevel@tonic-gate * Make sure that the output length is a multiple of
5987c478bd9Sstevel@tonic-gate * blocksize.
5997c478bd9Sstevel@tonic-gate */
6007c478bd9Sstevel@tonic-gate out_len = total_len - remain;
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate if (mechanism == CKM_AES_CBC_PAD) {
6037c478bd9Sstevel@tonic-gate /*
6047c478bd9Sstevel@tonic-gate * If the input data length is a multiple of
6057c478bd9Sstevel@tonic-gate * blocksize, then save the last block of input
6067c478bd9Sstevel@tonic-gate * data in the remaining buffer. C_DecryptFinal
6077c478bd9Sstevel@tonic-gate * will handle this last block of data.
6087c478bd9Sstevel@tonic-gate */
6097c478bd9Sstevel@tonic-gate if (remain == 0) {
6107c478bd9Sstevel@tonic-gate remain = AES_BLOCK_LEN;
6117c478bd9Sstevel@tonic-gate out_len -= AES_BLOCK_LEN;
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate /*
6167c478bd9Sstevel@tonic-gate * If application asks for the length of the output buffer
6177c478bd9Sstevel@tonic-gate * to hold the plaintext?
6187c478bd9Sstevel@tonic-gate */
6197c478bd9Sstevel@tonic-gate if (pData == NULL) {
6207c478bd9Sstevel@tonic-gate *pulDataLen = out_len;
6217c478bd9Sstevel@tonic-gate return (CKR_OK);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate /*
6257c478bd9Sstevel@tonic-gate * Is the application-supplied buffer large enough?
6267c478bd9Sstevel@tonic-gate */
6277c478bd9Sstevel@tonic-gate if (*pulDataLen < out_len) {
6287c478bd9Sstevel@tonic-gate *pulDataLen = out_len;
6297c478bd9Sstevel@tonic-gate return (CKR_BUFFER_TOO_SMALL);
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate if (soft_aes_ctx->remain_len != 0) {
6337c478bd9Sstevel@tonic-gate /*
6347c478bd9Sstevel@tonic-gate * Copy last remaining data and current input data
6357c478bd9Sstevel@tonic-gate * to the output buffer.
6367c478bd9Sstevel@tonic-gate */
6377c478bd9Sstevel@tonic-gate (void) memmove(pData + soft_aes_ctx->remain_len,
6387c478bd9Sstevel@tonic-gate pEncrypted, out_len - soft_aes_ctx->remain_len);
6397c478bd9Sstevel@tonic-gate (void) memcpy(pData, soft_aes_ctx->data,
6407c478bd9Sstevel@tonic-gate soft_aes_ctx->remain_len);
6417c478bd9Sstevel@tonic-gate bzero(soft_aes_ctx->data, soft_aes_ctx->remain_len);
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate in_buf = pData;
6447c478bd9Sstevel@tonic-gate } else {
6457c478bd9Sstevel@tonic-gate in_buf = pEncrypted;
6467c478bd9Sstevel@tonic-gate }
6477c478bd9Sstevel@tonic-gate out_buf = pData;
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate
65023c57df7Smcpowers do_decryption:
6517c478bd9Sstevel@tonic-gate /*
6527c478bd9Sstevel@tonic-gate * Begin Decryption.
6537c478bd9Sstevel@tonic-gate */
6547c478bd9Sstevel@tonic-gate switch (mechanism) {
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate case CKM_AES_ECB:
6577c478bd9Sstevel@tonic-gate {
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate ulong_t i;
6607c478bd9Sstevel@tonic-gate uint8_t *tmp_inbuf;
6617c478bd9Sstevel@tonic-gate uint8_t *tmp_outbuf;
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate for (i = 0; i < out_len; i += AES_BLOCK_LEN) {
6647c478bd9Sstevel@tonic-gate tmp_inbuf = &in_buf[i];
6657c478bd9Sstevel@tonic-gate tmp_outbuf = &out_buf[i];
6667c478bd9Sstevel@tonic-gate /* Crunch one block of data for AES. */
66723c57df7Smcpowers (void) aes_decrypt_block(soft_aes_ctx->key_sched,
6687c478bd9Sstevel@tonic-gate tmp_inbuf, tmp_outbuf);
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate if (update) {
6727c478bd9Sstevel@tonic-gate /*
6737c478bd9Sstevel@tonic-gate * For decrypt update, if there is a remaining
6747c478bd9Sstevel@tonic-gate * data, save it and its length in the context.
6757c478bd9Sstevel@tonic-gate */
6767c478bd9Sstevel@tonic-gate if (remain != 0)
6777c478bd9Sstevel@tonic-gate (void) memcpy(soft_aes_ctx->data, pEncrypted +
6787c478bd9Sstevel@tonic-gate (ulEncryptedLen - remain), remain);
6797c478bd9Sstevel@tonic-gate soft_aes_ctx->remain_len = remain;
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate *pulDataLen = out_len;
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate break;
6857c478bd9Sstevel@tonic-gate }
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate case CKM_AES_CBC:
6887c478bd9Sstevel@tonic-gate case CKM_AES_CBC_PAD:
6897c478bd9Sstevel@tonic-gate {
6907c478bd9Sstevel@tonic-gate crypto_data_t out;
6917c478bd9Sstevel@tonic-gate CK_ULONG rem_len;
6927c478bd9Sstevel@tonic-gate uint8_t last_block[AES_BLOCK_LEN];
6937c478bd9Sstevel@tonic-gate
6947c478bd9Sstevel@tonic-gate out.cd_format = CRYPTO_DATA_RAW;
6957c478bd9Sstevel@tonic-gate out.cd_offset = 0;
6967c478bd9Sstevel@tonic-gate out.cd_length = out_len;
6977c478bd9Sstevel@tonic-gate out.cd_raw.iov_base = (char *)out_buf;
6987c478bd9Sstevel@tonic-gate out.cd_raw.iov_len = out_len;
6997c478bd9Sstevel@tonic-gate
7007c478bd9Sstevel@tonic-gate /* Decrypt multiple blocks of data. */
7017c478bd9Sstevel@tonic-gate rc = aes_decrypt_contiguous_blocks(
7027c478bd9Sstevel@tonic-gate (aes_ctx_t *)soft_aes_ctx->aes_cbc,
7037c478bd9Sstevel@tonic-gate (char *)in_buf, out_len, &out);
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate if (rc != 0)
7067c478bd9Sstevel@tonic-gate goto decrypt_failed;
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate if ((mechanism == CKM_AES_CBC_PAD) && (!update)) {
7097c478bd9Sstevel@tonic-gate /* Decrypt last block containing pad bytes. */
7107c478bd9Sstevel@tonic-gate out.cd_offset = 0;
7117c478bd9Sstevel@tonic-gate out.cd_length = AES_BLOCK_LEN;
7127c478bd9Sstevel@tonic-gate out.cd_raw.iov_base = (char *)last_block;
7137c478bd9Sstevel@tonic-gate out.cd_raw.iov_len = AES_BLOCK_LEN;
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate /* Decrypt last block containing pad bytes. */
7167c478bd9Sstevel@tonic-gate rc = aes_decrypt_contiguous_blocks(
7177c478bd9Sstevel@tonic-gate (aes_ctx_t *)soft_aes_ctx->aes_cbc,
7187c478bd9Sstevel@tonic-gate (char *)in_buf + out_len, AES_BLOCK_LEN, &out);
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate if (rc != 0)
7217c478bd9Sstevel@tonic-gate goto decrypt_failed;
7227c478bd9Sstevel@tonic-gate
7237c478bd9Sstevel@tonic-gate /*
7247c478bd9Sstevel@tonic-gate * Remove padding bytes after decryption of
7257c478bd9Sstevel@tonic-gate * ciphertext block to produce the original
7267c478bd9Sstevel@tonic-gate * plaintext.
7277c478bd9Sstevel@tonic-gate */
7287c478bd9Sstevel@tonic-gate rv = soft_remove_pkcs7_padding(last_block,
729*726fad2aSDina K Nimeh AES_BLOCK_LEN, &rem_len);
7307c478bd9Sstevel@tonic-gate if (rv == CKR_OK) {
7317c478bd9Sstevel@tonic-gate if (rem_len != 0)
7327c478bd9Sstevel@tonic-gate (void) memcpy(out_buf + out_len,
7337c478bd9Sstevel@tonic-gate last_block, rem_len);
7347c478bd9Sstevel@tonic-gate *pulDataLen = out_len + rem_len;
7357c478bd9Sstevel@tonic-gate } else {
7367c478bd9Sstevel@tonic-gate *pulDataLen = 0;
7377c478bd9Sstevel@tonic-gate goto cleanup;
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate } else {
7407c478bd9Sstevel@tonic-gate *pulDataLen = out_len;
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate if (update) {
7447c478bd9Sstevel@tonic-gate /*
7457c478bd9Sstevel@tonic-gate * For decrypt update, if there is remaining data,
7467c478bd9Sstevel@tonic-gate * save it and its length in the context.
7477c478bd9Sstevel@tonic-gate */
7487c478bd9Sstevel@tonic-gate if (remain != 0)
7497c478bd9Sstevel@tonic-gate (void) memcpy(soft_aes_ctx->data, pEncrypted +
7507c478bd9Sstevel@tonic-gate (ulEncryptedLen - remain), remain);
7517c478bd9Sstevel@tonic-gate soft_aes_ctx->remain_len = remain;
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate if (rc == 0)
7557c478bd9Sstevel@tonic-gate break;
7567c478bd9Sstevel@tonic-gate decrypt_failed:
7577c478bd9Sstevel@tonic-gate *pulDataLen = 0;
7587c478bd9Sstevel@tonic-gate rv = CKR_FUNCTION_FAILED;
7597c478bd9Sstevel@tonic-gate goto cleanup;
7607c478bd9Sstevel@tonic-gate }
76123c57df7Smcpowers case CKM_AES_CTR:
76223c57df7Smcpowers {
76323c57df7Smcpowers crypto_data_t out;
76423c57df7Smcpowers
76523c57df7Smcpowers out.cd_format = CRYPTO_DATA_RAW;
76623c57df7Smcpowers out.cd_offset = 0;
76723c57df7Smcpowers out.cd_length = *pulDataLen;
76823c57df7Smcpowers out.cd_raw.iov_base = (char *)pData;
76923c57df7Smcpowers out.cd_raw.iov_len = *pulDataLen;
77023c57df7Smcpowers
77123c57df7Smcpowers rc = aes_decrypt_contiguous_blocks(soft_aes_ctx->aes_cbc,
77223c57df7Smcpowers (char *)pEncrypted, ulEncryptedLen, &out);
77323c57df7Smcpowers
77423c57df7Smcpowers if (rc != 0) {
77523c57df7Smcpowers *pulDataLen = 0;
77623c57df7Smcpowers rv = CKR_FUNCTION_FAILED;
77723c57df7Smcpowers goto cleanup;
77823c57df7Smcpowers }
77923c57df7Smcpowers
78023c57df7Smcpowers /*
78123c57df7Smcpowers * Since AES counter mode is a stream cipher, we call
78223c57df7Smcpowers * aes_counter_final() to pick up any remaining bytes.
78323c57df7Smcpowers * It is an internal function that does not destroy
78423c57df7Smcpowers * the context like *normal* final routines.
78523c57df7Smcpowers */
78623c57df7Smcpowers if (((aes_ctx_t *)soft_aes_ctx->aes_cbc)->ac_remainder_len
78723c57df7Smcpowers > 0) {
78823c57df7Smcpowers rc = ctr_mode_final(soft_aes_ctx->aes_cbc, &out,
78923c57df7Smcpowers aes_encrypt_block);
79023c57df7Smcpowers if (rc == CRYPTO_DATA_LEN_RANGE)
79123c57df7Smcpowers rc = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
79223c57df7Smcpowers }
79323c57df7Smcpowers }
7947c478bd9Sstevel@tonic-gate } /* end switch */
7957c478bd9Sstevel@tonic-gate
7967c478bd9Sstevel@tonic-gate if (update)
7977c478bd9Sstevel@tonic-gate return (CKR_OK);
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate /*
8007c478bd9Sstevel@tonic-gate * The following code will be executed if the caller is
8017c478bd9Sstevel@tonic-gate * soft_decrypt() or an error occurred. The decryption
8027c478bd9Sstevel@tonic-gate * operation will be terminated so we need to do some cleanup.
8037c478bd9Sstevel@tonic-gate */
8047c478bd9Sstevel@tonic-gate cleanup:
8057c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&session_p->session_mutex);
8067c478bd9Sstevel@tonic-gate aes_ctx = (aes_ctx_t *)soft_aes_ctx->aes_cbc;
8077c478bd9Sstevel@tonic-gate if (aes_ctx != NULL) {
8087c478bd9Sstevel@tonic-gate bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len);
8097c478bd9Sstevel@tonic-gate free(soft_aes_ctx->aes_cbc);
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate bzero(soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len);
8137c478bd9Sstevel@tonic-gate free(soft_aes_ctx->key_sched);
8147c478bd9Sstevel@tonic-gate free(session_p->decrypt.context);
8157c478bd9Sstevel@tonic-gate session_p->decrypt.context = NULL;
8167c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&session_p->session_mutex);
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate return (rv);
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate /*
8237c478bd9Sstevel@tonic-gate * Allocate and initialize a context for AES CBC mode of operation.
8247c478bd9Sstevel@tonic-gate */
8257c478bd9Sstevel@tonic-gate void *
aes_cbc_ctx_init(void * key_sched,size_t size,uint8_t * ivec)8267c478bd9Sstevel@tonic-gate aes_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec)
8277c478bd9Sstevel@tonic-gate {
8287c478bd9Sstevel@tonic-gate
82923c57df7Smcpowers cbc_ctx_t *cbc_ctx;
8307c478bd9Sstevel@tonic-gate
83123c57df7Smcpowers if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
8327c478bd9Sstevel@tonic-gate return (NULL);
8337c478bd9Sstevel@tonic-gate
83416239bc8SMark Powers cbc_ctx->cbc_keysched = key_sched;
83516239bc8SMark Powers cbc_ctx->cbc_keysched_len = size;
8367c478bd9Sstevel@tonic-gate
83716239bc8SMark Powers (void) memcpy(&cbc_ctx->cbc_iv[0], ivec, AES_BLOCK_LEN);
8387c478bd9Sstevel@tonic-gate
83916239bc8SMark Powers cbc_ctx->cbc_lastp = (uint8_t *)cbc_ctx->cbc_iv;
84016239bc8SMark Powers cbc_ctx->cbc_flags |= CBC_MODE;
8417c478bd9Sstevel@tonic-gate
84223c57df7Smcpowers return (cbc_ctx);
84323c57df7Smcpowers }
8447c478bd9Sstevel@tonic-gate
84523c57df7Smcpowers /*
84623c57df7Smcpowers * Allocate and initialize a context for AES CTR mode of operation.
84723c57df7Smcpowers */
84823c57df7Smcpowers void *
aes_ctr_ctx_init(void * key_sched,size_t size,uint8_t * param)84923c57df7Smcpowers aes_ctr_ctx_init(void *key_sched, size_t size, uint8_t *param)
85023c57df7Smcpowers {
85123c57df7Smcpowers
85223c57df7Smcpowers ctr_ctx_t *ctr_ctx;
85323c57df7Smcpowers CK_AES_CTR_PARAMS *pp;
85423c57df7Smcpowers
85523c57df7Smcpowers /* LINTED: pointer alignment */
85623c57df7Smcpowers pp = (CK_AES_CTR_PARAMS *)param;
85723c57df7Smcpowers
85823c57df7Smcpowers if ((ctr_ctx = calloc(1, sizeof (ctr_ctx_t))) == NULL)
85923c57df7Smcpowers return (NULL);
86023c57df7Smcpowers
86123c57df7Smcpowers ctr_ctx->ctr_keysched = key_sched;
86223c57df7Smcpowers ctr_ctx->ctr_keysched_len = size;
86323c57df7Smcpowers
86423c57df7Smcpowers if (ctr_init_ctx(ctr_ctx, pp->ulCounterBits, pp->cb, aes_copy_block)
86523c57df7Smcpowers != CRYPTO_SUCCESS) {
86623c57df7Smcpowers free(ctr_ctx);
86723c57df7Smcpowers return (NULL);
86823c57df7Smcpowers }
86923c57df7Smcpowers
87023c57df7Smcpowers return (ctr_ctx);
8717c478bd9Sstevel@tonic-gate }
872