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.
30 #include <sys/types.h>
31 #include <security/cryptoki.h>
32 #include "softSession.h"
33 #include "softObject.h"
34 #include "softCrypt.h"
35 #include <blowfish_impl.h>
38 soft_blowfish_crypt_init_common(soft_session_t
*session_p
,
39 CK_MECHANISM_PTR pMechanism
, soft_object_t
*key_p
, boolean_t encrypt
) {
42 soft_blowfish_ctx_t
*soft_blowfish_ctx
;
44 soft_blowfish_ctx
= calloc(1, sizeof (soft_blowfish_ctx_t
));
45 if (soft_blowfish_ctx
== NULL
) {
46 return (CKR_HOST_MEMORY
);
49 soft_blowfish_ctx
->key_sched
= blowfish_alloc_keysched(&size
, 0);
51 if (soft_blowfish_ctx
->key_sched
== NULL
) {
52 free(soft_blowfish_ctx
);
53 return (CKR_HOST_MEMORY
);
56 soft_blowfish_ctx
->keysched_len
= size
;
58 (void) pthread_mutex_lock(&session_p
->session_mutex
);
60 /* Called by C_EncryptInit */
61 session_p
->encrypt
.context
= soft_blowfish_ctx
;
62 session_p
->encrypt
.mech
.mechanism
= pMechanism
->mechanism
;
64 /* Called by C_DecryptInit */
65 session_p
->decrypt
.context
= soft_blowfish_ctx
;
66 session_p
->decrypt
.mech
.mechanism
= pMechanism
->mechanism
;
68 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
71 * If this is a non-sensitive key and it does NOT have
72 * a key schedule yet, then allocate one and expand it.
73 * Otherwise, if it's a non-sensitive key, and it DOES have
74 * a key schedule already attached to it, just copy the
75 * pre-expanded schedule to the context and avoid the
76 * extra key schedule expansion operation.
78 if (!(key_p
->bool_attr_mask
& SENSITIVE_BOOL_ON
)) {
79 if (OBJ_KEY_SCHED(key_p
) == NULL
) {
82 (void) pthread_mutex_lock(&key_p
->object_mutex
);
83 if (OBJ_KEY_SCHED(key_p
) == NULL
) {
84 ks
= blowfish_alloc_keysched(&size
, 0);
86 (void) pthread_mutex_unlock(
87 &key_p
->object_mutex
);
88 free(soft_blowfish_ctx
);
89 return (CKR_HOST_MEMORY
);
92 blowfish_init_keysched(OBJ_SEC_VALUE(key_p
),
93 (OBJ_SEC_VALUE_LEN(key_p
) * 8), ks
);
95 OBJ_KEY_SCHED_LEN(key_p
) = size
;
96 OBJ_KEY_SCHED(key_p
) = ks
;
98 (void) pthread_mutex_unlock(&key_p
->object_mutex
);
100 (void) memcpy(soft_blowfish_ctx
->key_sched
,
101 OBJ_KEY_SCHED(key_p
), OBJ_KEY_SCHED_LEN(key_p
));
102 soft_blowfish_ctx
->keysched_len
= OBJ_KEY_SCHED_LEN(key_p
);
106 * Initialize key schedule for Blowfish.
107 * blowfish_init_keysched() requires key length in bits.
109 blowfish_init_keysched(OBJ_SEC_VALUE(key_p
),
110 (OBJ_SEC_VALUE_LEN(key_p
) * 8),
111 soft_blowfish_ctx
->key_sched
);
118 * soft_blowfish_encrypt_common()
121 * session_p: pointer to soft_session_t struct
122 * pData: pointer to the input data to be encrypted
123 * ulDataLen: length of the input data
124 * pEncrypted: pointer to the output data after encryption
125 * pulEncryptedLen: pointer to the length of the output data
126 * update: boolean flag indicates caller is soft_encrypt
127 * or soft_encrypt_update
130 * This function calls the corresponding encrypt routine based
135 * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
137 * CKR_FUNCTION_FAILED: encrypt function failed
138 * CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
141 soft_blowfish_encrypt_common(soft_session_t
*session_p
, CK_BYTE_PTR pData
,
142 CK_ULONG ulDataLen
, CK_BYTE_PTR pEncrypted
, CK_ULONG_PTR pulEncryptedLen
,
147 soft_blowfish_ctx_t
*soft_blowfish_ctx
=
148 (soft_blowfish_ctx_t
*)session_p
->encrypt
.context
;
149 blowfish_ctx_t
*blowfish_ctx
;
150 CK_BYTE
*in_buf
= NULL
;
151 CK_BYTE
*out_buf
= NULL
;
158 * Blowfish only takes input length that is a multiple of blocksize
159 * for C_Encrypt function with the mechanism CKM_BLOWFISH_CBC.
163 if ((ulDataLen
% BLOWFISH_BLOCK_LEN
) != 0) {
164 rv
= CKR_DATA_LEN_RANGE
;
170 * If application asks for the length of the output buffer
171 * to hold the ciphertext?
173 if (pEncrypted
== NULL
) {
174 *pulEncryptedLen
= out_len
;
178 /* Is the application-supplied buffer large enough? */
179 if (*pulEncryptedLen
< out_len
) {
180 *pulEncryptedLen
= out_len
;
181 return (CKR_BUFFER_TOO_SMALL
);
185 out_buf
= pEncrypted
;
188 * Called by C_EncryptUpdate
190 * Add the lengths of last remaining data and current
191 * plaintext together to get the total input length.
193 total_len
= soft_blowfish_ctx
->remain_len
+ ulDataLen
;
196 * If the total input length is less than one blocksize,
197 * we will need to delay encryption until when more data
198 * comes in next C_EncryptUpdate or when C_EncryptFinal
201 if (total_len
< BLOWFISH_BLOCK_LEN
) {
202 if (pEncrypted
!= NULL
) {
204 * Save input data and its length in
205 * the remaining buffer of BLOWFISH context.
207 (void) memcpy(soft_blowfish_ctx
->data
+
208 soft_blowfish_ctx
->remain_len
, pData
,
210 soft_blowfish_ctx
->remain_len
+= ulDataLen
;
213 /* Set encrypted data length to 0. */
214 *pulEncryptedLen
= 0;
218 /* Compute the length of remaing data. */
219 remain
= total_len
% BLOWFISH_BLOCK_LEN
;
222 * Make sure that the output length is a multiple of
225 out_len
= total_len
- remain
;
228 * If application asks for the length of the output buffer
229 * to hold the ciphertext?
231 if (pEncrypted
== NULL
) {
232 *pulEncryptedLen
= out_len
;
236 /* Is the application-supplied buffer large enough? */
237 if (*pulEncryptedLen
< out_len
) {
238 *pulEncryptedLen
= out_len
;
239 return (CKR_BUFFER_TOO_SMALL
);
242 if (soft_blowfish_ctx
->remain_len
!= 0) {
244 * Copy last remaining data and current input data
245 * to the output buffer.
247 (void) memmove(pEncrypted
+
248 soft_blowfish_ctx
->remain_len
,
249 pData
, out_len
- soft_blowfish_ctx
->remain_len
);
250 (void) memcpy(pEncrypted
, soft_blowfish_ctx
->data
,
251 soft_blowfish_ctx
->remain_len
);
252 bzero(soft_blowfish_ctx
->data
,
253 soft_blowfish_ctx
->remain_len
);
259 out_buf
= pEncrypted
;
263 * Begin Encryption now.
266 out
.cd_format
= CRYPTO_DATA_RAW
;
268 out
.cd_length
= out_len
;
269 out
.cd_raw
.iov_base
= (char *)out_buf
;
270 out
.cd_raw
.iov_len
= out_len
;
272 /* Encrypt multiple blocks of data. */
273 rc
= blowfish_encrypt_contiguous_blocks(
274 (blowfish_ctx_t
*)soft_blowfish_ctx
->blowfish_cbc
,
275 (char *)in_buf
, out_len
, &out
);
278 *pulEncryptedLen
= out_len
;
281 * For encrypt update, if there is remaining data,
282 * save it and it's length in the context.
285 (void) memcpy(soft_blowfish_ctx
->data
, pData
+
286 (ulDataLen
- remain
), remain
);
288 soft_blowfish_ctx
->remain_len
= remain
;
293 *pulEncryptedLen
= 0;
294 rv
= CKR_FUNCTION_FAILED
;
298 (void) pthread_mutex_lock(&session_p
->session_mutex
);
299 blowfish_ctx
= (blowfish_ctx_t
*)soft_blowfish_ctx
->blowfish_cbc
;
300 if (blowfish_ctx
!= NULL
) {
301 bzero(blowfish_ctx
->bc_keysched
,
302 blowfish_ctx
->bc_keysched_len
);
303 free(soft_blowfish_ctx
->blowfish_cbc
);
306 bzero(soft_blowfish_ctx
->key_sched
, soft_blowfish_ctx
->keysched_len
);
307 free(soft_blowfish_ctx
->key_sched
);
308 free(session_p
->encrypt
.context
);
309 session_p
->encrypt
.context
= NULL
;
310 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
317 soft_blowfish_decrypt_common(soft_session_t
*session_p
, CK_BYTE_PTR pEncrypted
,
318 CK_ULONG ulEncryptedLen
, CK_BYTE_PTR pData
, CK_ULONG_PTR pulDataLen
,
323 soft_blowfish_ctx_t
*soft_blowfish_ctx
=
324 (soft_blowfish_ctx_t
*)session_p
->decrypt
.context
;
325 blowfish_ctx_t
*blowfish_ctx
;
326 CK_BYTE
*in_buf
= NULL
;
327 CK_BYTE
*out_buf
= NULL
;
334 * Blowfish only takes input length that is a multiple of 16 bytes
335 * for C_Decrypt function using CKM_BLOWFISH_CBC.
339 /* Called by C_Decrypt */
340 if ((ulEncryptedLen
% BLOWFISH_BLOCK_LEN
) != 0) {
341 rv
= CKR_ENCRYPTED_DATA_LEN_RANGE
;
346 * If application asks for the length of the output buffer
347 * to hold the plaintext?
350 *pulDataLen
= ulEncryptedLen
;
354 /* Is the application-supplied buffer large enough? */
355 if (*pulDataLen
< ulEncryptedLen
) {
356 *pulDataLen
= ulEncryptedLen
;
357 return (CKR_BUFFER_TOO_SMALL
);
359 out_len
= ulEncryptedLen
;
364 * Called by C_DecryptUpdate
366 * Add the lengths of last remaining data and current
367 * input data together to get the total input length.
369 total_len
= soft_blowfish_ctx
->remain_len
+ ulEncryptedLen
;
371 if (total_len
< BLOWFISH_BLOCK_LEN
) {
373 (void) memcpy(soft_blowfish_ctx
->data
+
374 soft_blowfish_ctx
->remain_len
,
375 pEncrypted
, ulEncryptedLen
);
377 soft_blowfish_ctx
->remain_len
+= ulEncryptedLen
;
380 /* Set output data length to 0. */
385 /* Compute the length of remaining data. */
386 remain
= total_len
% BLOWFISH_BLOCK_LEN
;
389 * Make sure that the output length is a multiple of
392 out_len
= total_len
- remain
;
395 * if application asks for the length of the output buffer
396 * to hold the plaintext?
399 *pulDataLen
= out_len
;
404 * Is the application-supplied buffer large enough?
406 if (*pulDataLen
< out_len
) {
407 *pulDataLen
= out_len
;
408 return (CKR_BUFFER_TOO_SMALL
);
411 if (soft_blowfish_ctx
->remain_len
!= 0) {
413 * Copy last remaining data and current input data
414 * to the output buffer.
416 (void) memmove(pData
+ soft_blowfish_ctx
->remain_len
,
418 out_len
- soft_blowfish_ctx
->remain_len
);
419 (void) memcpy(pData
, soft_blowfish_ctx
->data
,
420 soft_blowfish_ctx
->remain_len
);
421 bzero(soft_blowfish_ctx
->data
,
422 soft_blowfish_ctx
->remain_len
);
433 out
.cd_format
= CRYPTO_DATA_RAW
;
435 out
.cd_length
= out_len
;
436 out
.cd_raw
.iov_base
= (char *)out_buf
;
437 out
.cd_raw
.iov_len
= out_len
;
439 /* Decrypt multiple blocks of data. */
440 rc
= blowfish_decrypt_contiguous_blocks(
441 (blowfish_ctx_t
*)soft_blowfish_ctx
->blowfish_cbc
,
442 (char *)in_buf
, out_len
, &out
);
445 *pulDataLen
= out_len
;
448 * For decrypt update, if there is remaining data,
449 * save it and its length in the context.
452 (void) memcpy(soft_blowfish_ctx
->data
,
453 pEncrypted
+ (ulEncryptedLen
- remain
),
455 soft_blowfish_ctx
->remain_len
= remain
;
462 rv
= CKR_FUNCTION_FAILED
;
466 (void) pthread_mutex_lock(&session_p
->session_mutex
);
467 blowfish_ctx
= (blowfish_ctx_t
*)soft_blowfish_ctx
->blowfish_cbc
;
468 if (blowfish_ctx
!= NULL
) {
469 bzero(blowfish_ctx
->bc_keysched
,
470 blowfish_ctx
->bc_keysched_len
);
471 free(soft_blowfish_ctx
->blowfish_cbc
);
474 bzero(soft_blowfish_ctx
->key_sched
, soft_blowfish_ctx
->keysched_len
);
475 free(soft_blowfish_ctx
->key_sched
);
476 free(session_p
->decrypt
.context
);
477 session_p
->decrypt
.context
= NULL
;
478 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
484 * Allocate and initialize a context for BLOWFISH CBC mode of operation.
488 blowfish_cbc_ctx_init(void *key_sched
, size_t size
, uint8_t *ivec
)
493 if ((cbc_ctx
= calloc(1, sizeof (cbc_ctx_t
))) == NULL
)
496 cbc_ctx
->cbc_keysched
= key_sched
;
498 (void) memcpy(&cbc_ctx
->cbc_iv
[0], ivec
, BLOWFISH_BLOCK_LEN
);
500 cbc_ctx
->cbc_lastp
= (uint8_t *)&(cbc_ctx
->cbc_iv
);
501 cbc_ctx
->cbc_keysched_len
= size
;
502 cbc_ctx
->cbc_flags
|= CBC_MODE
;