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