xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_softtoken/common/softDESCrypt.c (revision 628e3cbed6489fa1db545d8524a06cd6535af456)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <pthread.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <sys/types.h>
31 #include <security/cryptoki.h>
32 #include <modes/modes.h>
33 #include <des_impl.h>
34 #include "softSession.h"
35 #include "softObject.h"
36 #include "softCrypt.h"
37 #include "softOps.h"
38 
39 /*
40  * Allocate context for the active encryption or decryption operation, and
41  * generate DES or DES3 key schedule to speed up the operation.
42  */
43 CK_RV
44 soft_des_crypt_init_common(soft_session_t *session_p,
45     CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
46     boolean_t encrypt)
47 {
48 
49 	size_t size;
50 	soft_des_ctx_t *soft_des_ctx;
51 
52 	soft_des_ctx = calloc(1, sizeof (soft_des_ctx_t));
53 	if (soft_des_ctx == NULL) {
54 		return (CKR_HOST_MEMORY);
55 	}
56 
57 	/* Allocate key schedule for DES or DES3 based on key type. */
58 	if (key_p->key_type == CKK_DES)
59 		soft_des_ctx->key_sched = des_alloc_keysched(&size, DES, 0);
60 	else
61 		soft_des_ctx->key_sched = des_alloc_keysched(&size, DES3, 0);
62 
63 	if (soft_des_ctx->key_sched == NULL) {
64 		free(soft_des_ctx);
65 		return (CKR_HOST_MEMORY);
66 	}
67 
68 	soft_des_ctx->keysched_len = size;
69 	soft_des_ctx->key_type = key_p->key_type;
70 
71 	(void) pthread_mutex_lock(&session_p->session_mutex);
72 	if (encrypt) {
73 		/* Called by C_EncryptInit. */
74 		session_p->encrypt.context = soft_des_ctx;
75 		session_p->encrypt.mech.mechanism = pMechanism->mechanism;
76 	} else {
77 		/* Called by C_DecryptInit. */
78 		session_p->decrypt.context = soft_des_ctx;
79 		session_p->decrypt.mech.mechanism = pMechanism->mechanism;
80 	}
81 	(void) pthread_mutex_unlock(&session_p->session_mutex);
82 
83 	/*
84 	 * If this is a non-sensitive key and it does NOT have
85 	 * a key schedule yet, then allocate one and expand it.
86 	 * Otherwise, if its a non-sensitive key, and it DOES have
87 	 * a key schedule already attached to it, just copy the
88 	 * pre-expanded schedule to the context and avoid the
89 	 * extra key schedule expansion operation.
90 	 */
91 	if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
92 		if (OBJ_KEY_SCHED(key_p) == NULL) {
93 			void *ks;
94 			(void) pthread_mutex_lock(&key_p->object_mutex);
95 			if (OBJ_KEY_SCHED(key_p) == NULL) {
96 				if (key_p->key_type == CKK_DES)
97 					ks = des_alloc_keysched(&size, DES, 0);
98 				else
99 					ks = des_alloc_keysched(&size, DES3, 0);
100 				if (ks == NULL) {
101 					(void) pthread_mutex_unlock(
102 					    &key_p->object_mutex);
103 					free(soft_des_ctx);
104 					return (CKR_HOST_MEMORY);
105 				}
106 				/* Initialize key schedule for DES or DES3. */
107 				if (key_p->key_type == CKK_DES)
108 					des_init_keysched(
109 					    OBJ_SEC(key_p)->sk_value, DES, ks);
110 				else if (key_p->key_type == CKK_DES2)
111 					/*
112 					 * DES3 encryption/decryption needs to
113 					 * support a DES2 key.
114 					 */
115 					des_init_keysched(
116 					    OBJ_SEC(key_p)->sk_value, DES2, ks);
117 				else
118 					des_init_keysched(
119 					    OBJ_SEC(key_p)->sk_value, DES3, ks);
120 
121 				OBJ_KEY_SCHED_LEN(key_p) = size;
122 				OBJ_KEY_SCHED(key_p) = ks;
123 			}
124 			(void) pthread_mutex_unlock(&key_p->object_mutex);
125 		}
126 
127 		/* Copy the pre-expanded key schedule from the key object */
128 		(void) memcpy(soft_des_ctx->key_sched, OBJ_KEY_SCHED(key_p),
129 		    OBJ_KEY_SCHED_LEN(key_p));
130 		soft_des_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
131 	} else {
132 		/* for sensitive keys, we cannot cache the key schedule */
133 		if (key_p->key_type == CKK_DES)
134 			des_init_keysched(OBJ_SEC(key_p)->sk_value,
135 			    DES, soft_des_ctx->key_sched);
136 		else if (key_p->key_type == CKK_DES2)
137 			/*
138 			 * DES3 encryption/decryption needs to
139 			 * support a DES2 key.
140 			 */
141 			des_init_keysched(OBJ_SEC(key_p)->sk_value,
142 			    DES2, soft_des_ctx->key_sched);
143 		else
144 			des_init_keysched(OBJ_SEC(key_p)->sk_value,
145 			    DES3, soft_des_ctx->key_sched);
146 	}
147 
148 	return (CKR_OK);
149 }
150 
151 
152 /*
153  * soft_des_encrypt_common()
154  *
155  * Arguments:
156  *      session_p:	pointer to soft_session_t struct
157  *	pData:		pointer to the input data to be encrypted
158  *	ulDataLen:	length of the input data
159  *	pEncrypted:	pointer to the output data after encryption
160  *	pulEncryptedLen: pointer to the length of the output data
161  *	update:		boolean flag indicates caller is soft_encrypt
162  *			or soft_encrypt_update
163  *
164  * Description:
165  *      This function calls the corresponding encrypt routine based
166  *	on the mechanism.
167  *
168  * Returns:
169  *      CKR_OK: success
170  *      CKR_BUFFER_TOO_SMALL: the output buffer provided by application
171  *			      is too small
172  *	CKR_FUNCTION_FAILED: encrypt function failed
173  *	CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
174  */
175 CK_RV
176 soft_des_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
177     CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted,
178     CK_ULONG_PTR pulEncryptedLen, boolean_t update)
179 {
180 	int rc = 0;
181 	CK_RV rv = CKR_OK;
182 	soft_des_ctx_t *soft_des_ctx =
183 	    (soft_des_ctx_t *)session_p->encrypt.context;
184 	des_ctx_t *des_ctx;
185 	CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
186 	CK_BYTE *in_buf = NULL;
187 	CK_BYTE *out_buf = NULL;
188 	CK_ULONG out_len;
189 	CK_ULONG total_len;
190 	CK_ULONG remain;
191 	boolean_t pad_mechanism = B_FALSE;
192 
193 	pad_mechanism = (mechanism == CKM_DES_CBC_PAD ||
194 	    mechanism == CKM_DES3_CBC_PAD);
195 	/*
196 	 * DES only takes input length that is a multiple of blocksize
197 	 * for C_Encrypt function with the mechanism CKM_DES<n>_ECB or
198 	 * CKM_DES<n>_CBC.
199 	 *
200 	 * DES allows any input length for C_Encrypt function with the
201 	 * mechanism CKM_DES<n>_CBC_PAD and for C_EncryptUpdate function.
202 	 */
203 	if (!update && !pad_mechanism) {
204 		if ((ulDataLen % DES_BLOCK_LEN) != 0) {
205 			rv = CKR_DATA_LEN_RANGE;
206 			goto cleanup;
207 		}
208 	}
209 
210 	if (!update) {
211 		/*
212 		 * Called by C_Encrypt
213 		 */
214 		if (pad_mechanism) {
215 			/*
216 			 * For CKM_DES<n>_CBC_PAD, compute output length to
217 			 * count for the padding. If the length of input
218 			 * data is a multiple of blocksize, then make output
219 			 * length to be the sum of the input length and
220 			 * one blocksize. Otherwise, output length will
221 			 * be rounded up to the next multiple of blocksize.
222 			 */
223 			out_len = DES_BLOCK_LEN *
224 			    (ulDataLen / DES_BLOCK_LEN + 1);
225 		} else {
226 			/*
227 			 * For non-padding mode, the output length will
228 			 * be same as the input length.
229 			 */
230 			out_len = ulDataLen;
231 		}
232 
233 		/*
234 		 * If application asks for the length of the output buffer
235 		 * to hold the ciphertext?
236 		 */
237 		if (pEncrypted == NULL) {
238 			*pulEncryptedLen = out_len;
239 			return (CKR_OK);
240 		}
241 
242 		/* Is the application-supplied buffer large enough? */
243 		if (*pulEncryptedLen < out_len) {
244 			*pulEncryptedLen = out_len;
245 			return (CKR_BUFFER_TOO_SMALL);
246 		}
247 
248 		/* Encrypt pad bytes in a separate operation */
249 		if (pad_mechanism) {
250 			out_len -= DES_BLOCK_LEN;
251 		}
252 
253 		in_buf = pData;
254 		out_buf = pEncrypted;
255 	} else {
256 		/*
257 		 * Called by C_EncryptUpdate
258 		 *
259 		 * Add the lengths of last remaining data and current
260 		 * plaintext together to get the total input length.
261 		 */
262 		total_len = soft_des_ctx->remain_len + ulDataLen;
263 
264 		/*
265 		 * If the total input length is less than one blocksize,
266 		 * or if the total input length is just one blocksize and
267 		 * the mechanism is CKM_DES<n>_CBC_PAD, we will need to delay
268 		 * encryption until when more data comes in next
269 		 * C_EncryptUpdate or when C_EncryptFinal is called.
270 		 */
271 		if ((total_len < DES_BLOCK_LEN) ||
272 		    (pad_mechanism && (total_len == DES_BLOCK_LEN))) {
273 			if (pData != NULL) {
274 				/*
275 				 * Save input data and its length in
276 				 * the remaining buffer of DES context.
277 				 */
278 				(void) memcpy(soft_des_ctx->data +
279 				    soft_des_ctx->remain_len, pData, ulDataLen);
280 				soft_des_ctx->remain_len += ulDataLen;
281 			}
282 
283 			/* Set encrypted data length to 0. */
284 			*pulEncryptedLen = 0;
285 			return (CKR_OK);
286 		}
287 
288 		/* Compute the length of remaing data. */
289 		remain = total_len % DES_BLOCK_LEN;
290 
291 		/*
292 		 * Make sure that the output length is a multiple of
293 		 * blocksize.
294 		 */
295 		out_len = total_len - remain;
296 
297 		/*
298 		 * If application asks for the length of the output buffer
299 		 * to hold the ciphertext?
300 		 */
301 		if (pEncrypted == NULL) {
302 			*pulEncryptedLen = out_len;
303 			return (CKR_OK);
304 		}
305 
306 		/* Is the application-supplied buffer large enough? */
307 		if (*pulEncryptedLen < out_len) {
308 			*pulEncryptedLen = out_len;
309 			return (CKR_BUFFER_TOO_SMALL);
310 		}
311 
312 		if (soft_des_ctx->remain_len != 0) {
313 			/*
314 			 * Copy last remaining data and current input data
315 			 * to the output buffer.
316 			 */
317 			(void) memmove(pEncrypted + soft_des_ctx->remain_len,
318 			    pData, out_len - soft_des_ctx->remain_len);
319 			(void) memcpy(pEncrypted, soft_des_ctx->data,
320 			    soft_des_ctx->remain_len);
321 			bzero(soft_des_ctx->data, soft_des_ctx->remain_len);
322 
323 			in_buf = pEncrypted;
324 		} else {
325 			in_buf = pData;
326 		}
327 		out_buf = pEncrypted;
328 	}
329 
330 	/*
331 	 * Begin Encryption now.
332 	 */
333 	switch (mechanism) {
334 
335 	case CKM_DES_ECB:
336 	case CKM_DES3_ECB:
337 	{
338 
339 		ulong_t i;
340 		uint8_t *tmp_inbuf;
341 		uint8_t *tmp_outbuf;
342 
343 		for (i = 0; i < out_len; i += DES_BLOCK_LEN) {
344 			tmp_inbuf = &in_buf[i];
345 			tmp_outbuf = &out_buf[i];
346 			/* Crunch one block of data for DES. */
347 			if (soft_des_ctx->key_type == CKK_DES)
348 				(void) des_crunch_block(
349 				    soft_des_ctx->key_sched,
350 				    tmp_inbuf, tmp_outbuf, B_FALSE);
351 			else
352 				(void) des3_crunch_block(
353 				    soft_des_ctx->key_sched,
354 				    tmp_inbuf, tmp_outbuf, B_FALSE);
355 		}
356 
357 		if (update) {
358 			/*
359 			 * For encrypt update, if there is remaining
360 			 * data, save it and its length in the context.
361 			 */
362 			if (remain != 0)
363 				(void) memcpy(soft_des_ctx->data, pData +
364 				    (ulDataLen - remain), remain);
365 			soft_des_ctx->remain_len = remain;
366 		}
367 
368 		*pulEncryptedLen = out_len;
369 		break;
370 	}
371 
372 	case CKM_DES_CBC:
373 	case CKM_DES_CBC_PAD:
374 	case CKM_DES3_CBC:
375 	case CKM_DES3_CBC_PAD:
376 	{
377 		crypto_data_t out;
378 
379 		out.cd_format =  CRYPTO_DATA_RAW;
380 		out.cd_offset = 0;
381 		out.cd_length = out_len;
382 		out.cd_raw.iov_base = (char *)out_buf;
383 		out.cd_raw.iov_len = out_len;
384 
385 		/* Encrypt multiple blocks of data. */
386 		rc = des_encrypt_contiguous_blocks(
387 		    (des_ctx_t *)soft_des_ctx->des_cbc,
388 		    (char *)in_buf, out_len, &out);
389 
390 		if (rc != 0)
391 			goto encrypt_failed;
392 
393 		if (update) {
394 			/*
395 			 * For encrypt update, if there is remaining data,
396 			 * save it and its length in the context.
397 			 */
398 			if (remain != 0)
399 				(void) memcpy(soft_des_ctx->data, pData +
400 				    (ulDataLen - remain), remain);
401 			soft_des_ctx->remain_len = remain;
402 		} else if (pad_mechanism) {
403 			/*
404 			 * Save the remainder of the input
405 			 * block in a temporary block because
406 			 * we don't want to overrun the input buffer
407 			 * by tacking on pad bytes.
408 			 */
409 			CK_BYTE tmpblock[DES_BLOCK_LEN];
410 			(void) memcpy(tmpblock, in_buf + out_len,
411 			    ulDataLen - out_len);
412 			soft_add_pkcs7_padding(tmpblock +
413 			    (ulDataLen - out_len),
414 			    DES_BLOCK_LEN, ulDataLen - out_len);
415 
416 			out.cd_offset = out_len;
417 			out.cd_length = DES_BLOCK_LEN;
418 			out.cd_raw.iov_base = (char *)out_buf;
419 			out.cd_raw.iov_len = out_len + DES_BLOCK_LEN;
420 
421 			/* Encrypt last block containing pad bytes. */
422 			rc = des_encrypt_contiguous_blocks(
423 			    (des_ctx_t *)soft_des_ctx->des_cbc,
424 			    (char *)tmpblock, DES_BLOCK_LEN, &out);
425 			out_len += DES_BLOCK_LEN;
426 		}
427 
428 		if (rc == 0) {
429 			*pulEncryptedLen = out_len;
430 			break;
431 		}
432 encrypt_failed:
433 		*pulEncryptedLen = 0;
434 		rv = CKR_FUNCTION_FAILED;
435 		goto cleanup;
436 
437 	}
438 	} /* end switch */
439 
440 	if (update)
441 		return (CKR_OK);
442 
443 	/*
444 	 * The following code will be executed if the caller is
445 	 * soft_encrypt() or an error occurred. The encryption
446 	 * operation will be terminated so we need to do some cleanup.
447 	 */
448 cleanup:
449 	(void) pthread_mutex_lock(&session_p->session_mutex);
450 	des_ctx = (des_ctx_t *)soft_des_ctx->des_cbc;
451 	if (des_ctx != NULL) {
452 		bzero(des_ctx->dc_keysched, des_ctx->dc_keysched_len);
453 		free(soft_des_ctx->des_cbc);
454 	}
455 
456 	bzero(soft_des_ctx->key_sched, soft_des_ctx->keysched_len);
457 	free(soft_des_ctx->key_sched);
458 	free(session_p->encrypt.context);
459 	session_p->encrypt.context = NULL;
460 	(void) pthread_mutex_unlock(&session_p->session_mutex);
461 
462 	return (rv);
463 }
464 
465 
466 /*
467  * soft_des_decrypt_common()
468  *
469  * Arguments:
470  *      session_p:	pointer to soft_session_t struct
471  *	pEncrypted:	pointer to the input data to be decrypted
472  *	ulEncryptedLen:	length of the input data
473  *	pData:		pointer to the output data
474  *	pulDataLen:	pointer to the length of the output data
475  *	Update:		boolean flag indicates caller is soft_decrypt
476  *			or soft_decrypt_update
477  *
478  * Description:
479  *      This function calls the corresponding decrypt routine based
480  *	on the mechanism.
481  *
482  * Returns:
483  *      CKR_OK: success
484  *      CKR_BUFFER_TOO_SMALL: the output buffer provided by application
485  *			      is too small
486  *	CKR_ENCRYPTED_DATA_LEN_RANGE: the input data is not a multiple
487  *				      of blocksize
488  *	CKR_FUNCTION_FAILED: decrypt function failed
489  */
490 CK_RV
491 soft_des_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted,
492     CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData,
493     CK_ULONG_PTR pulDataLen, boolean_t update)
494 {
495 
496 	int rc = 0;
497 	CK_RV rv = CKR_OK;
498 	soft_des_ctx_t *soft_des_ctx =
499 	    (soft_des_ctx_t *)session_p->decrypt.context;
500 	des_ctx_t *des_ctx;
501 	CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
502 	CK_BYTE *in_buf = NULL;
503 	CK_BYTE *out_buf = NULL;
504 	CK_ULONG out_len;
505 	CK_ULONG total_len;
506 	CK_ULONG remain;
507 	boolean_t pad_mechanism = B_FALSE;
508 
509 	pad_mechanism = (mechanism == CKM_DES_CBC_PAD ||
510 	    mechanism == CKM_DES3_CBC_PAD);
511 	/*
512 	 * DES only takes input length that is a multiple of 8 bytes
513 	 * for C_Decrypt function with the mechanism CKM_DES<n>_ECB,
514 	 * CKM_DES<n>_CBC or CKM_DES<n>_CBC_PAD.
515 	 *
516 	 * DES allows any input length for C_DecryptUpdate function.
517 	 */
518 	if (!update) {
519 		/*
520 		 * Called by C_Decrypt
521 		 */
522 		if ((ulEncryptedLen % DES_BLOCK_LEN) != 0) {
523 			rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
524 			goto cleanup;
525 		}
526 
527 		/*
528 		 * If application asks for the length of the output buffer
529 		 * to hold the plaintext?
530 		 */
531 		if (pData == NULL) {
532 			*pulDataLen = ulEncryptedLen;
533 			return (CKR_OK);
534 		}
535 
536 		/* Is the application-supplied buffer large enough? */
537 		if (!pad_mechanism) {
538 			if (*pulDataLen < ulEncryptedLen) {
539 				*pulDataLen = ulEncryptedLen;
540 				return (CKR_BUFFER_TOO_SMALL);
541 			}
542 
543 			/* Set output length same as input length. */
544 			out_len = ulEncryptedLen;
545 		} else {
546 			/*
547 			 * For CKM_DES<n>_CBC_PAD, we don't know how
548 			 * many bytes for padding at this time, so
549 			 * we'd assume one block was padded.
550 			 */
551 			if (*pulDataLen < (ulEncryptedLen - DES_BLOCK_LEN)) {
552 				*pulDataLen = ulEncryptedLen - DES_BLOCK_LEN;
553 				return (CKR_BUFFER_TOO_SMALL);
554 			}
555 			out_len = ulEncryptedLen - DES_BLOCK_LEN;
556 		}
557 		in_buf = pEncrypted;
558 		out_buf = pData;
559 	} else {
560 		/*
561 		 *  Called by C_DecryptUpdate
562 		 *
563 		 * Add the lengths of last remaining data and current
564 		 * input data together to get the total input length.
565 		 */
566 		total_len = soft_des_ctx->remain_len + ulEncryptedLen;
567 
568 		/*
569 		 * If the total input length is less than one blocksize,
570 		 * or if the total input length is just one blocksize and
571 		 * the mechanism is CKM_DES<n>_CBC_PAD, we will need to delay
572 		 * decryption until when more data comes in next
573 		 * C_DecryptUpdate or when C_DecryptFinal is called.
574 		 */
575 		if ((total_len < DES_BLOCK_LEN) ||
576 		    (pad_mechanism && (total_len == DES_BLOCK_LEN))) {
577 			if (pEncrypted != NULL) {
578 				/*
579 				 * Save input data and its length in
580 				 * the remaining buffer of DES context.
581 				 */
582 				(void) memcpy(soft_des_ctx->data +
583 				    soft_des_ctx->remain_len,
584 				    pEncrypted, ulEncryptedLen);
585 				soft_des_ctx->remain_len += ulEncryptedLen;
586 			}
587 
588 			/* Set output data length to 0. */
589 			*pulDataLen = 0;
590 			return (CKR_OK);
591 		}
592 
593 		/* Compute the length of remaing data. */
594 		remain = total_len % DES_BLOCK_LEN;
595 
596 		/*
597 		 * Make sure that the output length is a multiple of
598 		 * blocksize.
599 		 */
600 		out_len = total_len - remain;
601 
602 		if (pad_mechanism) {
603 			/*
604 			 * If the input data length is a multiple of
605 			 * blocksize, then save the last block of input
606 			 * data in the remaining buffer. C_DecryptFinal
607 			 * will handle this last block of data.
608 			 */
609 			if (remain == 0) {
610 				remain = DES_BLOCK_LEN;
611 				out_len -= DES_BLOCK_LEN;
612 			}
613 		}
614 
615 		/*
616 		 * If application asks for the length of the output buffer
617 		 * to hold the plaintext?
618 		 */
619 		if (pData == NULL) {
620 			*pulDataLen = out_len;
621 			return (CKR_OK);
622 		}
623 
624 		/*
625 		 * Is the application-supplied buffer large enough?
626 		 */
627 		if (*pulDataLen < out_len) {
628 			*pulDataLen = out_len;
629 			return (CKR_BUFFER_TOO_SMALL);
630 		}
631 
632 		if (soft_des_ctx->remain_len != 0) {
633 			/*
634 			 * Copy last remaining data and current input data
635 			 * to the output buffer.
636 			 */
637 			(void) memmove(pData + soft_des_ctx->remain_len,
638 			    pEncrypted, out_len - soft_des_ctx->remain_len);
639 			(void) memcpy(pData, soft_des_ctx->data,
640 			    soft_des_ctx->remain_len);
641 			bzero(soft_des_ctx->data, soft_des_ctx->remain_len);
642 
643 			in_buf = pData;
644 		} else {
645 			in_buf = pEncrypted;
646 		}
647 		out_buf = pData;
648 	}
649 
650 	/*
651 	 * Begin Decryption.
652 	 */
653 	switch (mechanism) {
654 
655 	case CKM_DES_ECB:
656 	case CKM_DES3_ECB:
657 	{
658 		uint8_t *tmp_inbuf;
659 		uint8_t *tmp_outbuf;
660 		ulong_t i;
661 
662 		for (i = 0; i < out_len; i += DES_BLOCK_LEN) {
663 			tmp_inbuf = &in_buf[i];
664 			tmp_outbuf = &out_buf[i];
665 			/* Crunch one block of data for DES. */
666 			if (soft_des_ctx->key_type == CKK_DES)
667 				(void) des_crunch_block(
668 				    soft_des_ctx->key_sched,
669 				    tmp_inbuf, tmp_outbuf, B_TRUE);
670 			else
671 				(void) des3_crunch_block(
672 				    soft_des_ctx->key_sched,
673 				    tmp_inbuf, tmp_outbuf, B_TRUE);
674 		}
675 
676 		if (update) {
677 			/*
678 			 * For decrypt update, if there is remaining
679 			 * data, save it and its length in the context.
680 			 */
681 			if (remain != 0)
682 				(void) memcpy(soft_des_ctx->data, pEncrypted +
683 				    (ulEncryptedLen - remain), remain);
684 			soft_des_ctx->remain_len = remain;
685 		}
686 
687 		*pulDataLen = out_len;
688 		break;
689 	}
690 
691 	case CKM_DES_CBC:
692 	case CKM_DES_CBC_PAD:
693 	case CKM_DES3_CBC:
694 	case CKM_DES3_CBC_PAD:
695 	{
696 		crypto_data_t out;
697 		CK_ULONG rem_len;
698 		uint8_t last_block[DES_BLOCK_LEN];
699 
700 		out.cd_format =  CRYPTO_DATA_RAW;
701 		out.cd_offset = 0;
702 		out.cd_length = out_len;
703 		out.cd_raw.iov_base = (char *)out_buf;
704 		out.cd_raw.iov_len = out_len;
705 
706 		/* Decrypt multiple blocks of data. */
707 		rc = des_decrypt_contiguous_blocks(
708 		    (des_ctx_t *)soft_des_ctx->des_cbc,
709 		    (char *)in_buf, out_len, &out);
710 
711 		if (rc != 0)
712 			goto decrypt_failed;
713 
714 		if (pad_mechanism && !update) {
715 			/* Decrypt last block containing pad bytes. */
716 			out.cd_offset = 0;
717 			out.cd_length = DES_BLOCK_LEN;
718 			out.cd_raw.iov_base = (char *)last_block;
719 			out.cd_raw.iov_len = DES_BLOCK_LEN;
720 
721 			/* Decrypt last block containing pad bytes. */
722 			rc = des_decrypt_contiguous_blocks(
723 			    (des_ctx_t *)soft_des_ctx->des_cbc,
724 			    (char *)in_buf + out_len, DES_BLOCK_LEN, &out);
725 
726 			if (rc != 0)
727 				goto decrypt_failed;
728 
729 			/*
730 			 * Remove padding bytes after decryption of
731 			 * ciphertext block to produce the original
732 			 * plaintext.
733 			 */
734 			rv = soft_remove_pkcs7_padding(last_block,
735 			    DES_BLOCK_LEN, &rem_len, DES_BLOCK_LEN);
736 			if (rv == CKR_OK) {
737 				if (rem_len != 0)
738 					(void) memcpy(out_buf + out_len,
739 					    last_block, rem_len);
740 				*pulDataLen = out_len + rem_len;
741 			} else {
742 				*pulDataLen = 0;
743 				goto cleanup;
744 			}
745 		} else {
746 			*pulDataLen = out_len;
747 		}
748 
749 		if (update) {
750 			/*
751 			 * For decrypt update, if there is remaining data,
752 			 * save it and its length in the context.
753 			 */
754 			if (remain != 0)
755 				(void) memcpy(soft_des_ctx->data, pEncrypted +
756 				    (ulEncryptedLen - remain), remain);
757 			soft_des_ctx->remain_len = remain;
758 		}
759 
760 		if (rc == 0)
761 			break;
762 decrypt_failed:
763 		*pulDataLen = 0;
764 		rv = CKR_FUNCTION_FAILED;
765 		goto cleanup;
766 	}
767 	} /* end switch */
768 
769 	if (update)
770 		return (CKR_OK);
771 
772 	/*
773 	 * The following code will be executed if the caller is
774 	 * soft_decrypt() or an error occurred. The decryption
775 	 * operation will be terminated so we need to do some cleanup.
776 	 */
777 cleanup:
778 	(void) pthread_mutex_lock(&session_p->session_mutex);
779 	des_ctx = (des_ctx_t *)soft_des_ctx->des_cbc;
780 	if (des_ctx != NULL) {
781 		bzero(des_ctx->dc_keysched, des_ctx->dc_keysched_len);
782 		free(soft_des_ctx->des_cbc);
783 	}
784 
785 	bzero(soft_des_ctx->key_sched, soft_des_ctx->keysched_len);
786 	free(soft_des_ctx->key_sched);
787 	free(session_p->decrypt.context);
788 	session_p->decrypt.context = NULL;
789 	(void) pthread_mutex_unlock(&session_p->session_mutex);
790 
791 	return (rv);
792 }
793 
794 
795 /*
796  * Allocate and initialize a context for DES CBC mode of operation.
797  */
798 void *
799 des_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec, CK_KEY_TYPE type)
800 {
801 
802 	cbc_ctx_t *cbc_ctx;
803 
804 	if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
805 		return (NULL);
806 
807 	cbc_ctx->cbc_keysched = key_sched;
808 
809 	(void) memcpy(&cbc_ctx->cbc_iv[0], ivec, DES_BLOCK_LEN);
810 
811 	cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0];
812 	cbc_ctx->cbc_keysched_len = size;
813 	if (type == CKK_DES)
814 		cbc_ctx->cbc_flags |= CBC_MODE;
815 	else
816 		cbc_ctx->cbc_flags |= CBC_MODE | DES3_STRENGTH;
817 
818 	return (cbc_ctx);
819 
820 }
821 
822 /*
823  * Allocate and initialize DES contexts for both signing and encrypting,
824  * saving both context pointers in the session struct. For general-length DES
825  * MAC, check the length in the parameter to see if it is in the right range.
826  */
827 CK_RV
828 soft_des_sign_verify_init_common(soft_session_t *session_p,
829 	CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t sign_op)
830 {
831 	soft_des_ctx_t	*soft_des_ctx;
832 	CK_MECHANISM	encrypt_mech;
833 	CK_RV rv;
834 
835 	if ((key_p->class != CKO_SECRET_KEY) || (key_p->key_type != CKK_DES)) {
836 		return (CKR_KEY_TYPE_INCONSISTENT);
837 	}
838 
839 	/* allocate memory for the sign/verify context */
840 	soft_des_ctx = malloc(sizeof (soft_des_ctx_t));
841 	if (soft_des_ctx == NULL) {
842 		return (CKR_HOST_MEMORY);
843 	}
844 
845 	soft_des_ctx->key_type = key_p->key_type;
846 
847 	/* initialization vector is zero for DES MAC */
848 	bzero(soft_des_ctx->ivec, DES_BLOCK_LEN);
849 
850 	switch (pMechanism->mechanism) {
851 
852 	case CKM_DES_MAC_GENERAL:
853 
854 		if (pMechanism->ulParameterLen !=
855 		    sizeof (CK_MAC_GENERAL_PARAMS)) {
856 			free(soft_des_ctx);
857 			return (CKR_MECHANISM_PARAM_INVALID);
858 		}
859 
860 		if (*(CK_MAC_GENERAL_PARAMS *)pMechanism->pParameter >
861 		    DES_BLOCK_LEN) {
862 			free(soft_des_ctx);
863 			return (CKR_MECHANISM_PARAM_INVALID);
864 		}
865 
866 		soft_des_ctx->mac_len = *((CK_MAC_GENERAL_PARAMS_PTR)
867 		    pMechanism->pParameter);
868 
869 		/*FALLTHRU*/
870 	case CKM_DES_MAC:
871 
872 		/*
873 		 * For non-general DES MAC, output is always half as
874 		 * large as block size
875 		 */
876 		if (pMechanism->mechanism == CKM_DES_MAC) {
877 			soft_des_ctx->mac_len = DES_MAC_LEN;
878 		}
879 
880 		/* allocate a context for DES encryption */
881 		encrypt_mech.mechanism = CKM_DES_CBC_PAD;
882 		encrypt_mech.pParameter = (void *)soft_des_ctx->ivec;
883 		encrypt_mech.ulParameterLen = DES_BLOCK_LEN;
884 		rv = soft_encrypt_init_internal(session_p, &encrypt_mech,
885 		    key_p);
886 		if (rv != CKR_OK) {
887 			free(soft_des_ctx);
888 			return (rv);
889 		}
890 
891 		(void) pthread_mutex_lock(&session_p->session_mutex);
892 
893 		if (sign_op) {
894 			session_p->sign.context = soft_des_ctx;
895 			session_p->sign.mech.mechanism = pMechanism->mechanism;
896 		} else {
897 			session_p->verify.context = soft_des_ctx;
898 			session_p->verify.mech.mechanism =
899 			    pMechanism->mechanism;
900 		}
901 
902 		(void) pthread_mutex_unlock(&session_p->session_mutex);
903 
904 		break;
905 	}
906 	return (CKR_OK);
907 }
908 
909 /*
910  * Called by soft_sign(), soft_sign_final(), soft_verify() or
911  * soft_verify_final().
912  */
913 CK_RV
914 soft_des_sign_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
915 	CK_ULONG ulDataLen, CK_BYTE_PTR pSigned, CK_ULONG_PTR pulSignedLen,
916 	boolean_t sign_op, boolean_t Final)
917 {
918 	soft_des_ctx_t		*soft_des_ctx_sign_verify;
919 	soft_des_ctx_t		*soft_des_ctx_encrypt;
920 	CK_RV			rv;
921 	CK_BYTE			*pEncrypted = NULL;
922 	CK_ULONG		ulEncryptedLen = 0;
923 	uint8_t			remainder;
924 	CK_BYTE			last_block[DES_BLOCK_LEN];
925 	des_ctx_t		*des_ctx = NULL;
926 
927 	if (sign_op) {
928 		soft_des_ctx_sign_verify =
929 		    (soft_des_ctx_t *)session_p->sign.context;
930 
931 		if (soft_des_ctx_sign_verify->mac_len == 0) {
932 			*pulSignedLen = 0;
933 			goto clean_exit;
934 		}
935 
936 		/* Application asks for the length of the output buffer. */
937 		if (pSigned == NULL) {
938 			*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
939 			return (CKR_OK);
940 		}
941 
942 		/* Is the application-supplied buffer large enough? */
943 		if (*pulSignedLen < soft_des_ctx_sign_verify->mac_len) {
944 			*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
945 			return (CKR_BUFFER_TOO_SMALL);
946 		}
947 	} else {
948 		soft_des_ctx_sign_verify =
949 		    (soft_des_ctx_t *)session_p->verify.context;
950 	}
951 
952 	if (Final) {
953 		soft_des_ctx_encrypt =
954 		    (soft_des_ctx_t *)session_p->encrypt.context;
955 
956 		/*
957 		 * If there is data left in the buffer from a previous
958 		 * SignUpdate() call, pass enough zeroed data to a
959 		 * soft_sign_update call to pad the remainder
960 		 */
961 		if (soft_des_ctx_encrypt->remain_len != 0) {
962 			bzero(last_block, DES_BLOCK_LEN);
963 			ulEncryptedLen = DES_BLOCK_LEN;
964 
965 			/*
966 			 * By passing a buffer to soft_encrypt_final,
967 			 * we force it to pad the remaining block
968 			 * and encrypt it.
969 			 */
970 			rv = soft_encrypt_final(session_p, last_block,
971 			    &ulEncryptedLen);
972 			if (rv != CKR_OK) {
973 				goto clean_exit;
974 			}
975 		} else {
976 			/*
977 			 * The last block of enciphered data is stored in:
978 			 * soft_des_ctx_encrypt->des_cbc->des_ctx->dc_lastp
979 			 * Copy that data to last_block
980 			 */
981 			soft_des_ctx_encrypt =
982 			    (soft_des_ctx_t *)session_p->encrypt.context;
983 			des_ctx = (des_ctx_t *)soft_des_ctx_encrypt->des_cbc;
984 			(void) memcpy(last_block, des_ctx->dc_lastp,
985 			    DES_BLOCK_LEN);
986 
987 			/*
988 			 * Passing a NULL output buffer here
989 			 * forces the routine to just return.
990 			 */
991 			rv = soft_encrypt_final(session_p, NULL,
992 			    &ulEncryptedLen);
993 		}
994 
995 	} else {
996 		/*
997 		 * If the input length is not multiple of block size, then
998 		 * determine the correct encrypted data length by rounding
999 		 */
1000 		remainder = ulDataLen % DES_BLOCK_LEN;
1001 		/*
1002 		 * Because we always use DES_CBC_PAD mechanism
1003 		 * for sign/verify operations, the input will
1004 		 * be padded to the next 8 byte boundary.
1005 		 * Adjust the length fields here accordingly.
1006 		 */
1007 		ulEncryptedLen = ulDataLen + (DES_BLOCK_LEN - remainder);
1008 
1009 		pEncrypted = malloc(sizeof (CK_BYTE) * ulEncryptedLen);
1010 		if (pEncrypted == NULL) {
1011 			rv = CKR_HOST_MEMORY;
1012 			goto clean_exit;
1013 		}
1014 
1015 		/*
1016 		 * Pad the last block with zeros by copying pData into a zeroed
1017 		 * pEncrypted. Then pass pEncrypted into soft_encrypt as input
1018 		 */
1019 		bzero(pEncrypted, ulEncryptedLen);
1020 		(void) memcpy(pEncrypted, pData, ulDataLen);
1021 
1022 		rv = soft_encrypt(session_p, pEncrypted, ulDataLen,
1023 		    pEncrypted, &ulEncryptedLen);
1024 		(void) memcpy(last_block,
1025 		    &pEncrypted[ulEncryptedLen - DES_BLOCK_LEN], DES_BLOCK_LEN);
1026 	}
1027 
1028 	if (rv == CKR_OK) {
1029 		*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
1030 
1031 		/* the leftmost mac_len bytes of last_block is our MAC */
1032 		(void) memcpy(pSigned, last_block, *pulSignedLen);
1033 	}
1034 
1035 clean_exit:
1036 
1037 	(void) pthread_mutex_lock(&session_p->session_mutex);
1038 
1039 	/* soft_encrypt_common() has freed the encrypt context */
1040 	if (sign_op) {
1041 		free(session_p->sign.context);
1042 		session_p->sign.context = NULL;
1043 	} else {
1044 		free(session_p->verify.context);
1045 		session_p->verify.context = NULL;
1046 	}
1047 	session_p->encrypt.flags = 0;
1048 
1049 	(void) pthread_mutex_unlock(&session_p->session_mutex);
1050 
1051 	if (pEncrypted) {
1052 		free(pEncrypted);
1053 	}
1054 
1055 	return (rv);
1056 }
1057 
1058 /*
1059  * Called by soft_sign_update()
1060  */
1061 CK_RV
1062 soft_des_mac_sign_verify_update(soft_session_t *session_p, CK_BYTE_PTR pPart,
1063 	CK_ULONG ulPartLen)
1064 {
1065 	/*
1066 	 * The DES MAC is calculated by taking the specified number of
1067 	 * left-most bytes within the last block of
1068 	 * encrypted data, while the context of the multi-part
1069 	 * encryption stores the block necessary for XORing with the
1070 	 * input as per cipher block chaining . Therefore, none of the
1071 	 * intermediary encrypted blocks of data are necessary for
1072 	 * the DES MAC, and we can create a placeholder local buffer
1073 	 * for the encrypted data, which is immediately throw away.
1074 	 */
1075 
1076 	soft_des_ctx_t	*soft_des_ctx_encrypt;
1077 	CK_BYTE		*pEncrypted = NULL;
1078 	CK_ULONG	ulEncryptedLen;
1079 	CK_ULONG	total_len;
1080 	uint8_t		remainder;
1081 	CK_RV		rv;
1082 
1083 	soft_des_ctx_encrypt = (soft_des_ctx_t *)session_p->encrypt.context;
1084 
1085 	/* Avoid the malloc if we won't be encrypting any data */
1086 	total_len = soft_des_ctx_encrypt->remain_len + ulPartLen;
1087 
1088 	if (total_len < DES_BLOCK_LEN) {
1089 		rv = soft_encrypt_update(session_p, pPart, ulPartLen, NULL,
1090 		    &ulEncryptedLen);
1091 	} else {
1092 		remainder = ulPartLen % DES_BLOCK_LEN;
1093 
1094 		/* round up to the nearest multiple of block size */
1095 		ulEncryptedLen = ulPartLen + (DES_BLOCK_LEN - remainder);
1096 		pEncrypted = malloc(sizeof (CK_BYTE) * ulEncryptedLen);
1097 
1098 		if (pEncrypted != NULL) {
1099 			rv = soft_encrypt_update(session_p, pPart, ulPartLen,
1100 			    pEncrypted, &ulEncryptedLen);
1101 			free(pEncrypted);
1102 		} else {
1103 			rv = CKR_HOST_MEMORY;
1104 		}
1105 	}
1106 	return (rv);
1107 }
1108