Merge commit '06307114472bd8aad5ff18ccdb8e25f128ae6652'
[unleashed.git] / usr / src / lib / pkcs11 / pkcs11_softtoken / common / softAESCrypt.c
blob3b910fdd1141f6196f3b5355af33a92895b3fb97
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 * Copyright (c) 2018, Joyent, Inc.
28 #include <pthread.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <sys/types.h>
33 #include <security/cryptoki.h>
34 #include <aes_impl.h>
35 #include "softSession.h"
36 #include "softObject.h"
37 #include "softCrypt.h"
38 #include "softOps.h"
41 * Allocate context for the active encryption or decryption operation, and
42 * generate AES key schedule to speed up the operation.
44 CK_RV
45 soft_aes_crypt_init_common(soft_session_t *session_p,
46 CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
47 boolean_t encrypt)
49 size_t size;
50 soft_aes_ctx_t *soft_aes_ctx;
52 soft_aes_ctx = calloc(1, sizeof (soft_aes_ctx_t));
53 if (soft_aes_ctx == NULL) {
54 return (CKR_HOST_MEMORY);
57 soft_aes_ctx->key_sched = aes_alloc_keysched(&size, 0);
59 if (soft_aes_ctx->key_sched == NULL) {
60 free(soft_aes_ctx);
61 return (CKR_HOST_MEMORY);
64 soft_aes_ctx->keysched_len = size;
66 (void) pthread_mutex_lock(&session_p->session_mutex);
67 if (encrypt) {
68 /* Called by C_EncryptInit. */
69 session_p->encrypt.context = soft_aes_ctx;
70 session_p->encrypt.mech.mechanism = pMechanism->mechanism;
71 } else {
72 /* Called by C_DecryptInit. */
73 session_p->decrypt.context = soft_aes_ctx;
74 session_p->decrypt.mech.mechanism = pMechanism->mechanism;
76 (void) pthread_mutex_unlock(&session_p->session_mutex);
79 * If this is a non-sensitive key and it does NOT have
80 * a key schedule yet, then allocate one and expand it.
81 * Otherwise, if it's a non-sensitive key, and it DOES have
82 * a key schedule already attached to it, just copy the
83 * pre-expanded schedule to the context and avoid the
84 * extra key schedule expansion operation.
86 if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
87 if (OBJ_KEY_SCHED(key_p) == NULL) {
88 void *ks;
90 (void) pthread_mutex_lock(&key_p->object_mutex);
91 if (OBJ_KEY_SCHED(key_p) == NULL) {
92 ks = aes_alloc_keysched(&size, 0);
93 if (ks == NULL) {
94 (void) pthread_mutex_unlock(
95 &key_p->object_mutex);
96 free(soft_aes_ctx);
97 return (CKR_HOST_MEMORY);
99 aes_init_keysched(OBJ_SEC_VALUE(key_p),
100 (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
101 OBJ_KEY_SCHED_LEN(key_p) = size;
102 OBJ_KEY_SCHED(key_p) = ks;
104 (void) pthread_mutex_unlock(&key_p->object_mutex);
106 (void) memcpy(soft_aes_ctx->key_sched, OBJ_KEY_SCHED(key_p),
107 OBJ_KEY_SCHED_LEN(key_p));
108 soft_aes_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
109 } else {
111 * Initialize key schedule for AES. aes_init_keysched()
112 * requires key length in bits.
114 aes_init_keysched(OBJ_SEC_VALUE(key_p),
115 (OBJ_SEC_VALUE_LEN(key_p) * 8), soft_aes_ctx->key_sched);
117 return (CKR_OK);
122 * soft_aes_encrypt_common()
124 * Arguments:
125 * session_p: pointer to soft_session_t struct
126 * pData: pointer to the input data to be encrypted
127 * ulDataLen: length of the input data
128 * pEncrypted: pointer to the output data after encryption
129 * pulEncryptedLen: pointer to the length of the output data
130 * update: boolean flag indicates caller is soft_encrypt
131 * or soft_encrypt_update
133 * Description:
134 * This function calls the corresponding encrypt routine based
135 * on the mechanism.
137 * Returns:
138 * CKR_OK: success
139 * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
140 * is too small
141 * CKR_FUNCTION_FAILED: encrypt function failed
142 * CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
144 CK_RV
145 soft_aes_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
146 CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted,
147 CK_ULONG_PTR pulEncryptedLen, boolean_t update)
150 int rc = 0;
151 CK_RV rv = CKR_OK;
152 soft_aes_ctx_t *soft_aes_ctx =
153 (soft_aes_ctx_t *)session_p->encrypt.context;
154 aes_ctx_t *aes_ctx;
155 CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
156 CK_BYTE *in_buf = NULL;
157 CK_BYTE *out_buf = NULL;
158 CK_ULONG out_len;
159 CK_ULONG total_len;
160 CK_ULONG remain;
162 if (mechanism == CKM_AES_CTR)
163 goto do_encryption;
166 * AES only takes input length that is a multiple of blocksize
167 * for C_Encrypt function with the mechanism CKM_AES_ECB or
168 * CKM_AES_CBC.
170 * AES allows any input length for C_Encrypt function with the
171 * mechanism CKM_AES_CBC_PAD and for C_EncryptUpdate function.
173 if ((!update) && (mechanism != CKM_AES_CBC_PAD) &&
174 (mechanism != CKM_AES_CMAC)) {
175 if ((ulDataLen % AES_BLOCK_LEN) != 0) {
176 rv = CKR_DATA_LEN_RANGE;
177 goto cleanup;
181 if (!update) {
183 * Called by C_Encrypt
185 if (mechanism == CKM_AES_CBC_PAD) {
187 * For CKM_AES_CBC_PAD, compute output length to
188 * count for the padding. If the length of input
189 * data is a multiple of blocksize, then make output
190 * length to be the sum of the input length and
191 * one blocksize. Otherwise, output length will
192 * be rounded up to the next multiple of blocksize.
194 out_len = AES_BLOCK_LEN *
195 (ulDataLen / AES_BLOCK_LEN + 1);
196 } else if (mechanism == CKM_AES_CMAC) {
197 out_len = AES_BLOCK_LEN;
198 } else {
200 * For non-padding mode, the output length will
201 * be same as the input length.
203 out_len = ulDataLen;
207 * If application asks for the length of the output buffer
208 * to hold the ciphertext?
210 if (pEncrypted == NULL) {
211 *pulEncryptedLen = out_len;
212 return (CKR_OK);
215 /* Is the application-supplied buffer large enough? */
216 if (*pulEncryptedLen < out_len) {
217 *pulEncryptedLen = out_len;
218 return (CKR_BUFFER_TOO_SMALL);
221 /* Encrypt pad bytes in a separate operation */
222 if (mechanism == CKM_AES_CBC_PAD) {
223 out_len -= AES_BLOCK_LEN;
226 in_buf = pData;
227 out_buf = pEncrypted;
228 } else {
230 * Called by C_EncryptUpdate
232 * Add the lengths of last remaining data and current
233 * plaintext together to get the total input length.
235 total_len = soft_aes_ctx->remain_len + ulDataLen;
238 * If the total input length is less than one blocksize,
239 * or if the total input length is just one blocksize and
240 * the mechanism is CKM_AES_CBC_PAD, we will need to delay
241 * encryption until when more data comes in next
242 * C_EncryptUpdate or when C_EncryptFinal is called.
244 out_buf = pEncrypted;
247 * We prefer to let the underlying implementation of CMAC handle
248 * the storing of extra bytes, and no data is output until
249 * *_final, so skip that part of the following validation.
251 if (mechanism == CKM_AES_CMAC) {
252 if (pEncrypted == NULL) {
253 *pulEncryptedLen = ulDataLen;
254 return (CKR_OK);
257 remain = 0;
258 in_buf = pData;
259 goto do_encryption;
262 if ((total_len < AES_BLOCK_LEN) ||
263 ((mechanism == CKM_AES_CBC_PAD) &&
264 (total_len == AES_BLOCK_LEN))) {
265 if (pEncrypted != NULL) {
267 * Save input data and its length in
268 * the remaining buffer of AES context.
270 (void) memcpy(soft_aes_ctx->data +
271 soft_aes_ctx->remain_len, pData, ulDataLen);
272 soft_aes_ctx->remain_len += ulDataLen;
275 /* Set encrypted data length to 0. */
276 *pulEncryptedLen = 0;
277 return (CKR_OK);
280 /* Compute the length of remaing data. */
281 remain = total_len % AES_BLOCK_LEN;
284 * Make sure that the output length is a multiple of
285 * blocksize.
287 out_len = total_len - remain;
290 * If application asks for the length of the output buffer
291 * to hold the ciphertext?
293 if (pEncrypted == NULL) {
294 *pulEncryptedLen = out_len;
295 return (CKR_OK);
298 /* Is the application-supplied buffer large enough? */
299 if (*pulEncryptedLen < out_len) {
300 *pulEncryptedLen = out_len;
301 return (CKR_BUFFER_TOO_SMALL);
304 if (soft_aes_ctx->remain_len != 0) {
306 * Copy last remaining data and current input data
307 * to the output buffer.
309 (void) memmove(pEncrypted + soft_aes_ctx->remain_len,
310 pData, out_len - soft_aes_ctx->remain_len);
311 (void) memcpy(pEncrypted, soft_aes_ctx->data,
312 soft_aes_ctx->remain_len);
313 bzero(soft_aes_ctx->data, soft_aes_ctx->remain_len);
315 in_buf = pEncrypted;
316 } else {
317 in_buf = pData;
321 do_encryption:
323 * Begin Encryption now.
325 switch (mechanism) {
327 case CKM_AES_ECB:
330 ulong_t i;
331 uint8_t *tmp_inbuf;
332 uint8_t *tmp_outbuf;
334 for (i = 0; i < out_len; i += AES_BLOCK_LEN) {
335 tmp_inbuf = &in_buf[i];
336 tmp_outbuf = &out_buf[i];
337 /* Crunch one block of data for AES. */
338 (void) aes_encrypt_block(soft_aes_ctx->key_sched,
339 tmp_inbuf, tmp_outbuf);
342 if (update) {
344 * For encrypt update, if there is a remaining
345 * data, save it and its length in the context.
347 if (remain != 0)
348 (void) memcpy(soft_aes_ctx->data, pData +
349 (ulDataLen - remain), remain);
350 soft_aes_ctx->remain_len = remain;
353 *pulEncryptedLen = out_len;
355 break;
358 case CKM_AES_CMAC:
359 out_len = ulDataLen;
360 /*FALLTHRU*/
361 case CKM_AES_CBC:
362 case CKM_AES_CBC_PAD:
364 crypto_data_t out;
366 out.cd_format = CRYPTO_DATA_RAW;
367 out.cd_offset = 0;
368 out.cd_length = out_len;
369 out.cd_raw.iov_base = (char *)out_buf;
370 out.cd_raw.iov_len = out_len;
372 /* Encrypt multiple blocks of data. */
373 rc = aes_encrypt_contiguous_blocks(
374 (aes_ctx_t *)soft_aes_ctx->aes_cbc,
375 (char *)in_buf, out_len, &out);
377 if (rc != 0)
378 goto encrypt_failed;
380 if (update) {
382 * For encrypt update, if there is remaining data,
383 * save it and its length in the context.
385 if (remain != 0)
386 (void) memcpy(soft_aes_ctx->data, pData +
387 (ulDataLen - remain), remain);
388 soft_aes_ctx->remain_len = remain;
389 } else if (mechanism == CKM_AES_CBC_PAD) {
391 * Save the remainder of the input
392 * block in a temporary block because
393 * we dont want to overrun the buffer
394 * by tacking on pad bytes.
396 CK_BYTE tmpblock[AES_BLOCK_LEN];
397 (void) memcpy(tmpblock, in_buf + out_len,
398 ulDataLen - out_len);
399 soft_add_pkcs7_padding(tmpblock +
400 (ulDataLen - out_len),
401 AES_BLOCK_LEN, ulDataLen - out_len);
403 out.cd_offset = out_len;
404 out.cd_length = AES_BLOCK_LEN;
405 out.cd_raw.iov_base = (char *)out_buf;
406 out.cd_raw.iov_len = out_len + AES_BLOCK_LEN;
408 /* Encrypt last block containing pad bytes. */
409 rc = aes_encrypt_contiguous_blocks(
410 (aes_ctx_t *)soft_aes_ctx->aes_cbc,
411 (char *)tmpblock, AES_BLOCK_LEN, &out);
413 out_len += AES_BLOCK_LEN;
414 } else if (mechanism == CKM_AES_CMAC) {
415 out.cd_length = AES_BLOCK_LEN;
416 out.cd_raw.iov_base = (char *)out_buf;
417 out.cd_raw.iov_len = AES_BLOCK_LEN;
419 rc = cmac_mode_final(soft_aes_ctx->aes_cbc, &out,
420 aes_encrypt_block, aes_xor_block);
423 if (rc == 0) {
424 *pulEncryptedLen = out_len;
425 break;
427 encrypt_failed:
428 *pulEncryptedLen = 0;
429 rv = CKR_FUNCTION_FAILED;
430 goto cleanup;
432 case CKM_AES_CTR:
434 crypto_data_t out;
436 out.cd_format = CRYPTO_DATA_RAW;
437 out.cd_offset = 0;
438 out.cd_length = *pulEncryptedLen;
439 out.cd_raw.iov_base = (char *)pEncrypted;
440 out.cd_raw.iov_len = *pulEncryptedLen;
442 rc = aes_encrypt_contiguous_blocks(soft_aes_ctx->aes_cbc,
443 (char *)pData, ulDataLen, &out);
445 if (rc != 0) {
446 *pulEncryptedLen = 0;
447 rv = CKR_FUNCTION_FAILED;
448 goto cleanup;
451 * Since AES counter mode is a stream cipher, we call
452 * aes_counter_final() to pick up any remaining bytes.
453 * It is an internal function that does not destroy
454 * the context like *normal* final routines.
456 if (((aes_ctx_t *)soft_aes_ctx->aes_cbc)->ac_remainder_len > 0)
457 rc = ctr_mode_final(soft_aes_ctx->aes_cbc, &out,
458 aes_encrypt_block);
461 * Even though success means we've encrypted all of the input,
462 * we should still behave like the other functions and return
463 * the encrypted length in pulEncryptedLen
465 *pulEncryptedLen = ulDataLen;
467 } /* end switch */
469 if (update)
470 return (CKR_OK);
473 * The following code will be executed if the caller is
474 * soft_encrypt() or an error occurred. The encryption
475 * operation will be terminated so we need to do some cleanup.
477 cleanup:
478 (void) pthread_mutex_lock(&session_p->session_mutex);
479 aes_ctx = (aes_ctx_t *)soft_aes_ctx->aes_cbc;
480 switch (mechanism) {
481 case CKM_AES_ECB:
482 freezero(aes_ctx, sizeof (ecb_ctx_t));
483 break;
484 case CKM_AES_CMAC:
485 case CKM_AES_CBC:
486 case CKM_AES_CBC_PAD:
487 freezero(aes_ctx, sizeof (cbc_ctx_t));
488 break;
489 case CKM_AES_CTR:
490 freezero(aes_ctx, sizeof (ctr_ctx_t));
491 break;
493 freezero(soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len);
494 freezero(session_p->encrypt.context, sizeof (soft_aes_ctx_t));
495 session_p->encrypt.context = NULL;
496 (void) pthread_mutex_unlock(&session_p->session_mutex);
498 return (rv);
503 * soft_aes_decrypt_common()
505 * Arguments:
506 * session_p: pointer to soft_session_t struct
507 * pEncrypted: pointer to the input data to be decrypted
508 * ulEncryptedLen: length of the input data
509 * pData: pointer to the output data
510 * pulDataLen: pointer to the length of the output data
511 * Update: boolean flag indicates caller is soft_decrypt
512 * or soft_decrypt_update
514 * Description:
515 * This function calls the corresponding decrypt routine based
516 * on the mechanism.
518 * Returns:
519 * CKR_OK: success
520 * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
521 * is too small
522 * CKR_ENCRYPTED_DATA_LEN_RANGE: the input data is not a multiple
523 * of blocksize
524 * CKR_FUNCTION_FAILED: decrypt function failed
526 CK_RV
527 soft_aes_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted,
528 CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData,
529 CK_ULONG_PTR pulDataLen, boolean_t update)
532 int rc = 0;
533 CK_RV rv = CKR_OK;
534 soft_aes_ctx_t *soft_aes_ctx =
535 (soft_aes_ctx_t *)session_p->decrypt.context;
536 aes_ctx_t *aes_ctx;
537 CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
538 CK_BYTE *in_buf = NULL;
539 CK_BYTE *out_buf = NULL;
540 CK_ULONG out_len;
541 CK_ULONG total_len;
542 CK_ULONG remain;
544 if (mechanism == CKM_AES_CTR)
545 goto do_decryption;
548 * AES only takes input length that is a multiple of 16 bytes
549 * for C_Decrypt function with the mechanism CKM_AES_ECB,
550 * CKM_AES_CBC or CKM_AES_CBC_PAD.
552 * AES allows any input length for C_DecryptUpdate function.
554 if (!update) {
556 * Called by C_Decrypt
558 if ((ulEncryptedLen % AES_BLOCK_LEN) != 0) {
559 rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
560 goto cleanup;
564 * If application asks for the length of the output buffer
565 * to hold the plaintext?
567 if (pData == NULL) {
568 *pulDataLen = ulEncryptedLen;
569 return (CKR_OK);
572 /* Is the application-supplied buffer large enough? */
573 if (mechanism != CKM_AES_CBC_PAD) {
574 if (*pulDataLen < ulEncryptedLen) {
575 *pulDataLen = ulEncryptedLen;
576 return (CKR_BUFFER_TOO_SMALL);
578 out_len = ulEncryptedLen;
579 } else {
581 * For CKM_AES_CBC_PAD, we don't know how
582 * many bytes for padding at this time, so
583 * we'd assume one block was padded.
585 if (*pulDataLen < (ulEncryptedLen - AES_BLOCK_LEN)) {
586 *pulDataLen = ulEncryptedLen - AES_BLOCK_LEN;
587 return (CKR_BUFFER_TOO_SMALL);
589 out_len = ulEncryptedLen - AES_BLOCK_LEN;
591 in_buf = pEncrypted;
592 out_buf = pData;
593 } else {
595 * Called by C_DecryptUpdate
597 * Add the lengths of last remaining data and current
598 * input data together to get the total input length.
600 total_len = soft_aes_ctx->remain_len + ulEncryptedLen;
603 * If the total input length is less than one blocksize,
604 * or if the total input length is just one blocksize and
605 * the mechanism is CKM_AES_CBC_PAD, we will need to delay
606 * decryption until when more data comes in next
607 * C_DecryptUpdate or when C_DecryptFinal is called.
609 if ((total_len < AES_BLOCK_LEN) ||
610 ((mechanism == CKM_AES_CBC_PAD) &&
611 (total_len == AES_BLOCK_LEN))) {
612 if (pData != NULL) {
614 * Save input data and its length in
615 * the remaining buffer of AES context.
617 (void) memcpy(soft_aes_ctx->data +
618 soft_aes_ctx->remain_len,
619 pEncrypted, ulEncryptedLen);
620 soft_aes_ctx->remain_len += ulEncryptedLen;
623 /* Set output data length to 0. */
624 *pulDataLen = 0;
625 return (CKR_OK);
628 /* Compute the length of remaing data. */
629 remain = total_len % AES_BLOCK_LEN;
632 * Make sure that the output length is a multiple of
633 * blocksize.
635 out_len = total_len - remain;
637 if (mechanism == CKM_AES_CBC_PAD) {
639 * If the input data length is a multiple of
640 * blocksize, then save the last block of input
641 * data in the remaining buffer. C_DecryptFinal
642 * will handle this last block of data.
644 if (remain == 0) {
645 remain = AES_BLOCK_LEN;
646 out_len -= AES_BLOCK_LEN;
651 * If application asks for the length of the output buffer
652 * to hold the plaintext?
654 if (pData == NULL) {
655 *pulDataLen = out_len;
656 return (CKR_OK);
660 * Is the application-supplied buffer large enough?
662 if (*pulDataLen < out_len) {
663 *pulDataLen = out_len;
664 return (CKR_BUFFER_TOO_SMALL);
667 if (soft_aes_ctx->remain_len != 0) {
669 * Copy last remaining data and current input data
670 * to the output buffer.
672 (void) memmove(pData + soft_aes_ctx->remain_len,
673 pEncrypted, out_len - soft_aes_ctx->remain_len);
674 (void) memcpy(pData, soft_aes_ctx->data,
675 soft_aes_ctx->remain_len);
676 bzero(soft_aes_ctx->data, soft_aes_ctx->remain_len);
678 in_buf = pData;
679 } else {
680 in_buf = pEncrypted;
682 out_buf = pData;
685 do_decryption:
687 * Begin Decryption.
689 switch (mechanism) {
691 case CKM_AES_ECB:
694 ulong_t i;
695 uint8_t *tmp_inbuf;
696 uint8_t *tmp_outbuf;
698 for (i = 0; i < out_len; i += AES_BLOCK_LEN) {
699 tmp_inbuf = &in_buf[i];
700 tmp_outbuf = &out_buf[i];
701 /* Crunch one block of data for AES. */
702 (void) aes_decrypt_block(soft_aes_ctx->key_sched,
703 tmp_inbuf, tmp_outbuf);
706 if (update) {
708 * For decrypt update, if there is a remaining
709 * data, save it and its length in the context.
711 if (remain != 0)
712 (void) memcpy(soft_aes_ctx->data, pEncrypted +
713 (ulEncryptedLen - remain), remain);
714 soft_aes_ctx->remain_len = remain;
717 *pulDataLen = out_len;
719 break;
722 case CKM_AES_CBC:
723 case CKM_AES_CBC_PAD:
725 crypto_data_t out;
726 CK_ULONG rem_len;
727 uint8_t last_block[AES_BLOCK_LEN];
729 out.cd_format = CRYPTO_DATA_RAW;
730 out.cd_offset = 0;
731 out.cd_length = out_len;
732 out.cd_raw.iov_base = (char *)out_buf;
733 out.cd_raw.iov_len = out_len;
735 /* Decrypt multiple blocks of data. */
736 rc = aes_decrypt_contiguous_blocks(
737 (aes_ctx_t *)soft_aes_ctx->aes_cbc,
738 (char *)in_buf, out_len, &out);
740 if (rc != 0)
741 goto decrypt_failed;
743 if ((mechanism == CKM_AES_CBC_PAD) && (!update)) {
744 /* Decrypt last block containing pad bytes. */
745 out.cd_offset = 0;
746 out.cd_length = AES_BLOCK_LEN;
747 out.cd_raw.iov_base = (char *)last_block;
748 out.cd_raw.iov_len = AES_BLOCK_LEN;
750 /* Decrypt last block containing pad bytes. */
751 rc = aes_decrypt_contiguous_blocks(
752 (aes_ctx_t *)soft_aes_ctx->aes_cbc,
753 (char *)in_buf + out_len, AES_BLOCK_LEN, &out);
755 if (rc != 0)
756 goto decrypt_failed;
759 * Remove padding bytes after decryption of
760 * ciphertext block to produce the original
761 * plaintext.
763 rv = soft_remove_pkcs7_padding(last_block,
764 AES_BLOCK_LEN, &rem_len);
765 if (rv == CKR_OK) {
766 if (rem_len != 0)
767 (void) memcpy(out_buf + out_len,
768 last_block, rem_len);
769 *pulDataLen = out_len + rem_len;
770 } else {
771 *pulDataLen = 0;
772 goto cleanup;
774 } else {
775 *pulDataLen = out_len;
778 if (update) {
780 * For decrypt update, if there is remaining data,
781 * save it and its length in the context.
783 if (remain != 0)
784 (void) memcpy(soft_aes_ctx->data, pEncrypted +
785 (ulEncryptedLen - remain), remain);
786 soft_aes_ctx->remain_len = remain;
789 if (rc == 0)
790 break;
791 decrypt_failed:
792 *pulDataLen = 0;
793 rv = CKR_FUNCTION_FAILED;
794 goto cleanup;
796 case CKM_AES_CTR:
798 crypto_data_t out;
800 out.cd_format = CRYPTO_DATA_RAW;
801 out.cd_offset = 0;
802 out.cd_length = *pulDataLen;
803 out.cd_raw.iov_base = (char *)pData;
804 out.cd_raw.iov_len = *pulDataLen;
806 rc = aes_decrypt_contiguous_blocks(soft_aes_ctx->aes_cbc,
807 (char *)pEncrypted, ulEncryptedLen, &out);
809 if (rc != 0) {
810 *pulDataLen = 0;
811 rv = CKR_FUNCTION_FAILED;
812 goto cleanup;
816 * Since AES counter mode is a stream cipher, we call
817 * aes_counter_final() to pick up any remaining bytes.
818 * It is an internal function that does not destroy
819 * the context like *normal* final routines.
821 if (((aes_ctx_t *)soft_aes_ctx->aes_cbc)->ac_remainder_len
822 > 0) {
823 rc = ctr_mode_final(soft_aes_ctx->aes_cbc, &out,
824 aes_encrypt_block);
825 if (rc == CRYPTO_DATA_LEN_RANGE)
826 rc = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
830 * Even though success means we've decrypted all of the input,
831 * we should still behave like the other functions and return
832 * the decrypted length in pulDataLen
834 *pulDataLen = ulEncryptedLen;
837 } /* end switch */
839 if (update)
840 return (CKR_OK);
843 * The following code will be executed if the caller is
844 * soft_decrypt() or an error occurred. The decryption
845 * operation will be terminated so we need to do some cleanup.
847 cleanup:
848 (void) pthread_mutex_lock(&session_p->session_mutex);
849 aes_ctx = (aes_ctx_t *)soft_aes_ctx->aes_cbc;
850 free(aes_ctx);
851 freezero(soft_aes_ctx->key_sched, soft_aes_ctx->keysched_len);
852 freezero(session_p->decrypt.context, sizeof (soft_aes_ctx_t));
853 session_p->decrypt.context = NULL;
854 (void) pthread_mutex_unlock(&session_p->session_mutex);
856 return (rv);
861 * Allocate and initialize a context for AES CBC mode of operation.
863 void *
864 aes_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec)
867 cbc_ctx_t *cbc_ctx;
869 if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
870 return (NULL);
872 cbc_ctx->cbc_keysched = key_sched;
873 cbc_ctx->cbc_keysched_len = size;
875 (void) memcpy(&cbc_ctx->cbc_iv[0], ivec, AES_BLOCK_LEN);
877 cbc_ctx->cbc_lastp = (uint8_t *)cbc_ctx->cbc_iv;
878 cbc_ctx->cbc_flags |= CBC_MODE;
879 cbc_ctx->max_remain = AES_BLOCK_LEN;
881 return (cbc_ctx);
884 void *
885 aes_cmac_ctx_init(void *key_sched, size_t size)
888 cbc_ctx_t *cbc_ctx;
890 if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
891 return (NULL);
893 cbc_ctx->cbc_keysched = key_sched;
894 cbc_ctx->cbc_keysched_len = size;
896 cbc_ctx->cbc_lastp = (uint8_t *)cbc_ctx->cbc_iv;
897 cbc_ctx->cbc_flags |= CMAC_MODE;
898 cbc_ctx->max_remain = AES_BLOCK_LEN + 1;
900 return (cbc_ctx);
904 * Allocate and initialize a context for AES CTR mode of operation.
906 void *
907 aes_ctr_ctx_init(void *key_sched, size_t size, uint8_t *param)
910 ctr_ctx_t *ctr_ctx;
911 CK_AES_CTR_PARAMS *pp;
913 /* LINTED: pointer alignment */
914 pp = (CK_AES_CTR_PARAMS *)param;
916 if ((ctr_ctx = calloc(1, sizeof (ctr_ctx_t))) == NULL)
917 return (NULL);
919 ctr_ctx->ctr_keysched = key_sched;
920 ctr_ctx->ctr_keysched_len = size;
922 if (ctr_init_ctx(ctr_ctx, pp->ulCounterBits, pp->cb, aes_copy_block)
923 != CRYPTO_SUCCESS) {
924 free(ctr_ctx);
925 return (NULL);
928 return (ctr_ctx);
932 * Allocate and initialize AES contexts for both signing and encrypting,
933 * saving both context pointers in the session struct. For general-length AES
934 * MAC, check the length in the parameter to see if it is in the right range.
936 CK_RV
937 soft_aes_sign_verify_init_common(soft_session_t *session_p,
938 CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t sign_op)
940 soft_aes_ctx_t *soft_aes_ctx;
941 CK_MECHANISM encrypt_mech;
942 CK_RV rv;
944 if (key_p->key_type != CKK_AES) {
945 return (CKR_KEY_TYPE_INCONSISTENT);
948 /* allocate memory for the sign/verify context */
949 soft_aes_ctx = malloc(sizeof (soft_aes_ctx_t));
950 if (soft_aes_ctx == NULL) {
951 return (CKR_HOST_MEMORY);
954 /* initialization vector is zero for AES CMAC */
955 bzero(soft_aes_ctx->ivec, AES_BLOCK_LEN);
957 switch (pMechanism->mechanism) {
959 case CKM_AES_CMAC_GENERAL:
961 if (pMechanism->ulParameterLen !=
962 sizeof (CK_MAC_GENERAL_PARAMS)) {
963 free(soft_aes_ctx);
964 return (CKR_MECHANISM_PARAM_INVALID);
967 if (*(CK_MAC_GENERAL_PARAMS *)pMechanism->pParameter >
968 AES_BLOCK_LEN) {
969 free(soft_aes_ctx);
970 return (CKR_MECHANISM_PARAM_INVALID);
973 soft_aes_ctx->mac_len = *((CK_MAC_GENERAL_PARAMS_PTR)
974 pMechanism->pParameter);
976 /*FALLTHRU*/
977 case CKM_AES_CMAC:
980 * For non-general AES MAC, output is always block size
982 if (pMechanism->mechanism == CKM_AES_CMAC) {
983 soft_aes_ctx->mac_len = AES_BLOCK_LEN;
986 /* allocate a context for AES encryption */
987 encrypt_mech.mechanism = CKM_AES_CMAC;
988 encrypt_mech.pParameter = (void *)soft_aes_ctx->ivec;
989 encrypt_mech.ulParameterLen = AES_BLOCK_LEN;
990 rv = soft_encrypt_init_internal(session_p, &encrypt_mech,
991 key_p);
992 if (rv != CKR_OK) {
993 free(soft_aes_ctx);
994 return (rv);
997 (void) pthread_mutex_lock(&session_p->session_mutex);
999 if (sign_op) {
1000 session_p->sign.context = soft_aes_ctx;
1001 session_p->sign.mech.mechanism = pMechanism->mechanism;
1002 } else {
1003 session_p->verify.context = soft_aes_ctx;
1004 session_p->verify.mech.mechanism =
1005 pMechanism->mechanism;
1008 (void) pthread_mutex_unlock(&session_p->session_mutex);
1010 break;
1012 return (CKR_OK);
1016 * Called by soft_sign(), soft_sign_final(), soft_verify() or
1017 * soft_verify_final().
1019 CK_RV
1020 soft_aes_sign_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
1021 CK_ULONG ulDataLen, CK_BYTE_PTR pSigned, CK_ULONG_PTR pulSignedLen,
1022 boolean_t sign_op, boolean_t Final)
1024 soft_aes_ctx_t *soft_aes_ctx_sign_verify;
1025 CK_RV rv;
1026 CK_BYTE *pEncrypted = NULL;
1027 CK_ULONG ulEncryptedLen = AES_BLOCK_LEN;
1028 CK_BYTE last_block[AES_BLOCK_LEN];
1030 if (sign_op) {
1031 soft_aes_ctx_sign_verify =
1032 (soft_aes_ctx_t *)session_p->sign.context;
1034 if (soft_aes_ctx_sign_verify->mac_len == 0) {
1035 *pulSignedLen = 0;
1036 goto clean_exit;
1039 /* Application asks for the length of the output buffer. */
1040 if (pSigned == NULL) {
1041 *pulSignedLen = soft_aes_ctx_sign_verify->mac_len;
1042 return (CKR_OK);
1045 /* Is the application-supplied buffer large enough? */
1046 if (*pulSignedLen < soft_aes_ctx_sign_verify->mac_len) {
1047 *pulSignedLen = soft_aes_ctx_sign_verify->mac_len;
1048 return (CKR_BUFFER_TOO_SMALL);
1050 } else {
1051 soft_aes_ctx_sign_verify =
1052 (soft_aes_ctx_t *)session_p->verify.context;
1055 if (Final) {
1056 rv = soft_encrypt_final(session_p, last_block,
1057 &ulEncryptedLen);
1058 } else {
1059 rv = soft_encrypt(session_p, pData, ulDataLen,
1060 last_block, &ulEncryptedLen);
1063 if (rv == CKR_OK) {
1064 *pulSignedLen = soft_aes_ctx_sign_verify->mac_len;
1066 /* the leftmost mac_len bytes of last_block is our MAC */
1067 (void) memcpy(pSigned, last_block, *pulSignedLen);
1070 clean_exit:
1072 (void) pthread_mutex_lock(&session_p->session_mutex);
1074 /* soft_encrypt_common() has freed the encrypt context */
1075 if (sign_op) {
1076 free(session_p->sign.context);
1077 session_p->sign.context = NULL;
1078 } else {
1079 free(session_p->verify.context);
1080 session_p->verify.context = NULL;
1082 session_p->encrypt.flags = 0;
1084 (void) pthread_mutex_unlock(&session_p->session_mutex);
1086 if (pEncrypted) {
1087 free(pEncrypted);
1090 return (rv);
1094 * Called by soft_sign_update()
1096 CK_RV
1097 soft_aes_mac_sign_verify_update(soft_session_t *session_p, CK_BYTE_PTR pPart,
1098 CK_ULONG ulPartLen)
1100 CK_BYTE buf[AES_BLOCK_LEN];
1101 CK_ULONG ulEncryptedLen = AES_BLOCK_LEN;
1102 CK_RV rv;
1104 rv = soft_encrypt_update(session_p, pPart, ulPartLen,
1105 buf, &ulEncryptedLen);
1107 return (rv);