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