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