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