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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2018, Joyent, Inc.
31 #include <sys/types.h>
32 #include <security/cryptoki.h>
33 #include "softSession.h"
34 #include "softObject.h"
35 #include "softCrypt.h"
36 #include <blowfish_impl.h>
39 soft_blowfish_crypt_init_common(soft_session_t
*session_p
,
40 CK_MECHANISM_PTR pMechanism
, soft_object_t
*key_p
, boolean_t encrypt
)
43 soft_blowfish_ctx_t
*soft_blowfish_ctx
;
45 soft_blowfish_ctx
= calloc(1, sizeof (soft_blowfish_ctx_t
));
46 if (soft_blowfish_ctx
== NULL
) {
47 return (CKR_HOST_MEMORY
);
50 soft_blowfish_ctx
->key_sched
= blowfish_alloc_keysched(&size
, 0);
52 if (soft_blowfish_ctx
->key_sched
== NULL
) {
53 free(soft_blowfish_ctx
);
54 return (CKR_HOST_MEMORY
);
57 soft_blowfish_ctx
->keysched_len
= size
;
59 (void) pthread_mutex_lock(&session_p
->session_mutex
);
61 /* Called by C_EncryptInit */
62 session_p
->encrypt
.context
= soft_blowfish_ctx
;
63 session_p
->encrypt
.mech
.mechanism
= pMechanism
->mechanism
;
65 /* Called by C_DecryptInit */
66 session_p
->decrypt
.context
= soft_blowfish_ctx
;
67 session_p
->decrypt
.mech
.mechanism
= pMechanism
->mechanism
;
69 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
72 * If this is a non-sensitive key and it does NOT have
73 * a key schedule yet, then allocate one and expand it.
74 * Otherwise, if it's a non-sensitive key, and it DOES have
75 * a key schedule already attached to it, just copy the
76 * pre-expanded schedule to the context and avoid the
77 * extra key schedule expansion operation.
79 if (!(key_p
->bool_attr_mask
& SENSITIVE_BOOL_ON
)) {
80 if (OBJ_KEY_SCHED(key_p
) == NULL
) {
83 (void) pthread_mutex_lock(&key_p
->object_mutex
);
84 if (OBJ_KEY_SCHED(key_p
) == NULL
) {
85 ks
= blowfish_alloc_keysched(&size
, 0);
87 (void) pthread_mutex_unlock(
88 &key_p
->object_mutex
);
89 free(soft_blowfish_ctx
);
90 return (CKR_HOST_MEMORY
);
93 blowfish_init_keysched(OBJ_SEC_VALUE(key_p
),
94 (OBJ_SEC_VALUE_LEN(key_p
) * 8), ks
);
96 OBJ_KEY_SCHED_LEN(key_p
) = size
;
97 OBJ_KEY_SCHED(key_p
) = ks
;
99 (void) pthread_mutex_unlock(&key_p
->object_mutex
);
101 (void) memcpy(soft_blowfish_ctx
->key_sched
,
102 OBJ_KEY_SCHED(key_p
), OBJ_KEY_SCHED_LEN(key_p
));
103 soft_blowfish_ctx
->keysched_len
= OBJ_KEY_SCHED_LEN(key_p
);
107 * Initialize key schedule for Blowfish.
108 * blowfish_init_keysched() requires key length in bits.
110 blowfish_init_keysched(OBJ_SEC_VALUE(key_p
),
111 (OBJ_SEC_VALUE_LEN(key_p
) * 8),
112 soft_blowfish_ctx
->key_sched
);
119 * soft_blowfish_encrypt_common()
122 * session_p: pointer to soft_session_t struct
123 * pData: pointer to the input data to be encrypted
124 * ulDataLen: length of the input data
125 * pEncrypted: pointer to the output data after encryption
126 * pulEncryptedLen: pointer to the length of the output data
127 * update: boolean flag indicates caller is soft_encrypt
128 * or soft_encrypt_update
131 * This function calls the corresponding encrypt routine based
136 * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
138 * CKR_FUNCTION_FAILED: encrypt function failed
139 * CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
142 soft_blowfish_encrypt_common(soft_session_t
*session_p
, CK_BYTE_PTR pData
,
143 CK_ULONG ulDataLen
, CK_BYTE_PTR pEncrypted
, CK_ULONG_PTR pulEncryptedLen
,
148 soft_blowfish_ctx_t
*soft_blowfish_ctx
=
149 (soft_blowfish_ctx_t
*)session_p
->encrypt
.context
;
150 blowfish_ctx_t
*blowfish_ctx
;
151 CK_BYTE
*in_buf
= NULL
;
152 CK_BYTE
*out_buf
= NULL
;
159 * Blowfish only takes input length that is a multiple of blocksize
160 * for C_Encrypt function with the mechanism CKM_BLOWFISH_CBC.
164 if ((ulDataLen
% BLOWFISH_BLOCK_LEN
) != 0) {
165 rv
= CKR_DATA_LEN_RANGE
;
171 * If application asks for the length of the output buffer
172 * to hold the ciphertext?
174 if (pEncrypted
== NULL
) {
175 *pulEncryptedLen
= out_len
;
179 /* Is the application-supplied buffer large enough? */
180 if (*pulEncryptedLen
< out_len
) {
181 *pulEncryptedLen
= out_len
;
182 return (CKR_BUFFER_TOO_SMALL
);
186 out_buf
= pEncrypted
;
189 * Called by C_EncryptUpdate
191 * Add the lengths of last remaining data and current
192 * plaintext together to get the total input length.
194 total_len
= soft_blowfish_ctx
->remain_len
+ ulDataLen
;
197 * If the total input length is less than one blocksize,
198 * we will need to delay encryption until when more data
199 * comes in next C_EncryptUpdate or when C_EncryptFinal
202 if (total_len
< BLOWFISH_BLOCK_LEN
) {
203 if (pEncrypted
!= NULL
) {
205 * Save input data and its length in
206 * the remaining buffer of BLOWFISH context.
208 (void) memcpy(soft_blowfish_ctx
->data
+
209 soft_blowfish_ctx
->remain_len
, pData
,
211 soft_blowfish_ctx
->remain_len
+= ulDataLen
;
214 /* Set encrypted data length to 0. */
215 *pulEncryptedLen
= 0;
219 /* Compute the length of remaing data. */
220 remain
= total_len
% BLOWFISH_BLOCK_LEN
;
223 * Make sure that the output length is a multiple of
226 out_len
= total_len
- remain
;
229 * If application asks for the length of the output buffer
230 * to hold the ciphertext?
232 if (pEncrypted
== NULL
) {
233 *pulEncryptedLen
= out_len
;
237 /* Is the application-supplied buffer large enough? */
238 if (*pulEncryptedLen
< out_len
) {
239 *pulEncryptedLen
= out_len
;
240 return (CKR_BUFFER_TOO_SMALL
);
243 if (soft_blowfish_ctx
->remain_len
!= 0) {
245 * Copy last remaining data and current input data
246 * to the output buffer.
248 (void) memmove(pEncrypted
+
249 soft_blowfish_ctx
->remain_len
,
250 pData
, out_len
- soft_blowfish_ctx
->remain_len
);
251 (void) memcpy(pEncrypted
, soft_blowfish_ctx
->data
,
252 soft_blowfish_ctx
->remain_len
);
253 bzero(soft_blowfish_ctx
->data
,
254 soft_blowfish_ctx
->remain_len
);
260 out_buf
= pEncrypted
;
264 * Begin Encryption now.
267 out
.cd_format
= CRYPTO_DATA_RAW
;
269 out
.cd_length
= out_len
;
270 out
.cd_raw
.iov_base
= (char *)out_buf
;
271 out
.cd_raw
.iov_len
= out_len
;
273 /* Encrypt multiple blocks of data. */
274 rc
= blowfish_encrypt_contiguous_blocks(
275 (blowfish_ctx_t
*)soft_blowfish_ctx
->blowfish_cbc
,
276 (char *)in_buf
, out_len
, &out
);
279 *pulEncryptedLen
= out_len
;
282 * For encrypt update, if there is remaining data,
283 * save it and it's length in the context.
286 (void) memcpy(soft_blowfish_ctx
->data
, pData
+
287 (ulDataLen
- remain
), remain
);
289 soft_blowfish_ctx
->remain_len
= remain
;
294 *pulEncryptedLen
= 0;
295 rv
= CKR_FUNCTION_FAILED
;
299 (void) pthread_mutex_lock(&session_p
->session_mutex
);
300 blowfish_ctx
= (blowfish_ctx_t
*)soft_blowfish_ctx
->blowfish_cbc
;
301 freezero(blowfish_ctx
, sizeof (cbc_ctx_t
));
302 freezero(soft_blowfish_ctx
->key_sched
,
303 soft_blowfish_ctx
->keysched_len
);
304 freezero(session_p
->encrypt
.context
,
305 sizeof (soft_blowfish_ctx_t
));
306 session_p
->encrypt
.context
= NULL
;
307 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
314 soft_blowfish_decrypt_common(soft_session_t
*session_p
, CK_BYTE_PTR pEncrypted
,
315 CK_ULONG ulEncryptedLen
, CK_BYTE_PTR pData
, CK_ULONG_PTR pulDataLen
,
320 soft_blowfish_ctx_t
*soft_blowfish_ctx
=
321 (soft_blowfish_ctx_t
*)session_p
->decrypt
.context
;
322 blowfish_ctx_t
*blowfish_ctx
;
323 CK_BYTE
*in_buf
= NULL
;
324 CK_BYTE
*out_buf
= NULL
;
331 * Blowfish only takes input length that is a multiple of 16 bytes
332 * for C_Decrypt function using CKM_BLOWFISH_CBC.
336 /* Called by C_Decrypt */
337 if ((ulEncryptedLen
% BLOWFISH_BLOCK_LEN
) != 0) {
338 rv
= CKR_ENCRYPTED_DATA_LEN_RANGE
;
343 * If application asks for the length of the output buffer
344 * to hold the plaintext?
347 *pulDataLen
= ulEncryptedLen
;
351 /* Is the application-supplied buffer large enough? */
352 if (*pulDataLen
< ulEncryptedLen
) {
353 *pulDataLen
= ulEncryptedLen
;
354 return (CKR_BUFFER_TOO_SMALL
);
356 out_len
= ulEncryptedLen
;
361 * Called by C_DecryptUpdate
363 * Add the lengths of last remaining data and current
364 * input data together to get the total input length.
366 total_len
= soft_blowfish_ctx
->remain_len
+ ulEncryptedLen
;
368 if (total_len
< BLOWFISH_BLOCK_LEN
) {
370 (void) memcpy(soft_blowfish_ctx
->data
+
371 soft_blowfish_ctx
->remain_len
,
372 pEncrypted
, ulEncryptedLen
);
374 soft_blowfish_ctx
->remain_len
+= ulEncryptedLen
;
377 /* Set output data length to 0. */
382 /* Compute the length of remaining data. */
383 remain
= total_len
% BLOWFISH_BLOCK_LEN
;
386 * Make sure that the output length is a multiple of
389 out_len
= total_len
- remain
;
392 * if application asks for the length of the output buffer
393 * to hold the plaintext?
396 *pulDataLen
= out_len
;
401 * Is the application-supplied buffer large enough?
403 if (*pulDataLen
< out_len
) {
404 *pulDataLen
= out_len
;
405 return (CKR_BUFFER_TOO_SMALL
);
408 if (soft_blowfish_ctx
->remain_len
!= 0) {
410 * Copy last remaining data and current input data
411 * to the output buffer.
413 (void) memmove(pData
+ soft_blowfish_ctx
->remain_len
,
415 out_len
- soft_blowfish_ctx
->remain_len
);
416 (void) memcpy(pData
, soft_blowfish_ctx
->data
,
417 soft_blowfish_ctx
->remain_len
);
418 bzero(soft_blowfish_ctx
->data
,
419 soft_blowfish_ctx
->remain_len
);
430 out
.cd_format
= CRYPTO_DATA_RAW
;
432 out
.cd_length
= out_len
;
433 out
.cd_raw
.iov_base
= (char *)out_buf
;
434 out
.cd_raw
.iov_len
= out_len
;
436 /* Decrypt multiple blocks of data. */
437 rc
= blowfish_decrypt_contiguous_blocks(
438 (blowfish_ctx_t
*)soft_blowfish_ctx
->blowfish_cbc
,
439 (char *)in_buf
, out_len
, &out
);
442 *pulDataLen
= out_len
;
445 * For decrypt update, if there is remaining data,
446 * save it and its length in the context.
449 (void) memcpy(soft_blowfish_ctx
->data
,
450 pEncrypted
+ (ulEncryptedLen
- remain
),
452 soft_blowfish_ctx
->remain_len
= remain
;
459 rv
= CKR_FUNCTION_FAILED
;
463 (void) pthread_mutex_lock(&session_p
->session_mutex
);
464 blowfish_ctx
= (blowfish_ctx_t
*)soft_blowfish_ctx
->blowfish_cbc
;
466 freezero(soft_blowfish_ctx
->key_sched
,
467 soft_blowfish_ctx
->keysched_len
);
468 freezero(session_p
->decrypt
.context
,
469 sizeof (soft_blowfish_ctx_t
));
470 session_p
->decrypt
.context
= NULL
;
471 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
477 * Allocate and initialize a context for BLOWFISH CBC mode of operation.
481 blowfish_cbc_ctx_init(void *key_sched
, size_t size
, uint8_t *ivec
)
486 if ((cbc_ctx
= calloc(1, sizeof (cbc_ctx_t
))) == NULL
)
489 cbc_ctx
->cbc_keysched
= key_sched
;
491 (void) memcpy(&cbc_ctx
->cbc_iv
[0], ivec
, BLOWFISH_BLOCK_LEN
);
493 cbc_ctx
->cbc_lastp
= (uint8_t *)&(cbc_ctx
->cbc_iv
);
494 cbc_ctx
->cbc_keysched_len
= size
;
495 cbc_ctx
->cbc_flags
|= CBC_MODE
;