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 #include <pthread.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <strings.h>
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>
36
37 CK_RV
soft_blowfish_crypt_init_common(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p,boolean_t encrypt)38 soft_blowfish_crypt_init_common(soft_session_t *session_p,
39 CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t encrypt) {
40
41 size_t size;
42 soft_blowfish_ctx_t *soft_blowfish_ctx;
43
44 soft_blowfish_ctx = calloc(1, sizeof (soft_blowfish_ctx_t));
45 if (soft_blowfish_ctx == NULL) {
46 return (CKR_HOST_MEMORY);
47 }
48
49 soft_blowfish_ctx->key_sched = blowfish_alloc_keysched(&size, 0);
50
51 if (soft_blowfish_ctx->key_sched == NULL) {
52 free(soft_blowfish_ctx);
53 return (CKR_HOST_MEMORY);
54 }
55
56 soft_blowfish_ctx->keysched_len = size;
57
58 (void) pthread_mutex_lock(&session_p->session_mutex);
59 if (encrypt) {
60 /* Called by C_EncryptInit */
61 session_p->encrypt.context = soft_blowfish_ctx;
62 session_p->encrypt.mech.mechanism = pMechanism->mechanism;
63 } else {
64 /* Called by C_DecryptInit */
65 session_p->decrypt.context = soft_blowfish_ctx;
66 session_p->decrypt.mech.mechanism = pMechanism->mechanism;
67 }
68 (void) pthread_mutex_unlock(&session_p->session_mutex);
69
70 /*
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.
77 */
78 if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
79 if (OBJ_KEY_SCHED(key_p) == NULL) {
80 void *ks;
81
82 (void) pthread_mutex_lock(&key_p->object_mutex);
83 if (OBJ_KEY_SCHED(key_p) == NULL) {
84 ks = blowfish_alloc_keysched(&size, 0);
85 if (ks == NULL) {
86 (void) pthread_mutex_unlock(
87 &key_p->object_mutex);
88 free(soft_blowfish_ctx);
89 return (CKR_HOST_MEMORY);
90 }
91
92 blowfish_init_keysched(OBJ_SEC_VALUE(key_p),
93 (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
94
95 OBJ_KEY_SCHED_LEN(key_p) = size;
96 OBJ_KEY_SCHED(key_p) = ks;
97 }
98 (void) pthread_mutex_unlock(&key_p->object_mutex);
99 }
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);
103
104 } else {
105 /*
106 * Initialize key schedule for Blowfish.
107 * blowfish_init_keysched() requires key length in bits.
108 */
109 blowfish_init_keysched(OBJ_SEC_VALUE(key_p),
110 (OBJ_SEC_VALUE_LEN(key_p) * 8),
111 soft_blowfish_ctx->key_sched);
112 }
113 return (CKR_OK);
114 }
115
116
117 /*
118 * soft_blowfish_encrypt_common()
119 *
120 * Arguments:
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
128 *
129 * Description:
130 * This function calls the corresponding encrypt routine based
131 * on the mechanism.
132 *
133 * Returns:
134 * CKR_OK: success
135 * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
136 * is too small
137 * CKR_FUNCTION_FAILED: encrypt function failed
138 * CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
139 */
140 CK_RV
soft_blowfish_encrypt_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pEncrypted,CK_ULONG_PTR pulEncryptedLen,boolean_t update)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,
143 boolean_t update) {
144
145 int rc = 0;
146 CK_RV rv = CKR_OK;
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;
152 CK_ULONG out_len;
153 CK_ULONG total_len;
154 CK_ULONG remain;
155 crypto_data_t out;
156
157 /*
158 * Blowfish only takes input length that is a multiple of blocksize
159 * for C_Encrypt function with the mechanism CKM_BLOWFISH_CBC.
160 *
161 */
162 if (!update) {
163 if ((ulDataLen % BLOWFISH_BLOCK_LEN) != 0) {
164 rv = CKR_DATA_LEN_RANGE;
165 goto cleanup;
166 }
167
168 out_len = ulDataLen;
169 /*
170 * If application asks for the length of the output buffer
171 * to hold the ciphertext?
172 */
173 if (pEncrypted == NULL) {
174 *pulEncryptedLen = out_len;
175 return (CKR_OK);
176 }
177
178 /* Is the application-supplied buffer large enough? */
179 if (*pulEncryptedLen < out_len) {
180 *pulEncryptedLen = out_len;
181 return (CKR_BUFFER_TOO_SMALL);
182 }
183
184 in_buf = pData;
185 out_buf = pEncrypted;
186 } else {
187 /*
188 * Called by C_EncryptUpdate
189 *
190 * Add the lengths of last remaining data and current
191 * plaintext together to get the total input length.
192 */
193 total_len = soft_blowfish_ctx->remain_len + ulDataLen;
194
195 /*
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
199 * is called.
200 */
201 if (total_len < BLOWFISH_BLOCK_LEN) {
202 if (pEncrypted != NULL) {
203 /*
204 * Save input data and its length in
205 * the remaining buffer of BLOWFISH context.
206 */
207 (void) memcpy(soft_blowfish_ctx->data +
208 soft_blowfish_ctx->remain_len, pData,
209 ulDataLen);
210 soft_blowfish_ctx->remain_len += ulDataLen;
211 }
212
213 /* Set encrypted data length to 0. */
214 *pulEncryptedLen = 0;
215 return (CKR_OK);
216 }
217
218 /* Compute the length of remaing data. */
219 remain = total_len % BLOWFISH_BLOCK_LEN;
220
221 /*
222 * Make sure that the output length is a multiple of
223 * blocksize.
224 */
225 out_len = total_len - remain;
226
227 /*
228 * If application asks for the length of the output buffer
229 * to hold the ciphertext?
230 */
231 if (pEncrypted == NULL) {
232 *pulEncryptedLen = out_len;
233 return (CKR_OK);
234 }
235
236 /* Is the application-supplied buffer large enough? */
237 if (*pulEncryptedLen < out_len) {
238 *pulEncryptedLen = out_len;
239 return (CKR_BUFFER_TOO_SMALL);
240 }
241
242 if (soft_blowfish_ctx->remain_len != 0) {
243 /*
244 * Copy last remaining data and current input data
245 * to the output buffer.
246 */
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);
254
255 in_buf = pEncrypted;
256 } else {
257 in_buf = pData;
258 }
259 out_buf = pEncrypted;
260 }
261
262 /*
263 * Begin Encryption now.
264 */
265
266 out.cd_format = CRYPTO_DATA_RAW;
267 out.cd_offset = 0;
268 out.cd_length = out_len;
269 out.cd_raw.iov_base = (char *)out_buf;
270 out.cd_raw.iov_len = out_len;
271
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);
276
277 if (rc == 0) {
278 *pulEncryptedLen = out_len;
279 if (update) {
280 /*
281 * For encrypt update, if there is remaining data,
282 * save it and it's length in the context.
283 */
284 if (remain != 0)
285 (void) memcpy(soft_blowfish_ctx->data, pData +
286 (ulDataLen - remain), remain);
287
288 soft_blowfish_ctx->remain_len = remain;
289 return (CKR_OK);
290 }
291
292 } else {
293 *pulEncryptedLen = 0;
294 rv = CKR_FUNCTION_FAILED;
295 }
296
297 cleanup:
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);
304 }
305
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);
311
312 return (rv);
313 }
314
315
316 CK_RV
soft_blowfish_decrypt_common(soft_session_t * session_p,CK_BYTE_PTR pEncrypted,CK_ULONG ulEncryptedLen,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen,boolean_t update)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,
319 boolean_t update) {
320
321 int rc = 0;
322 CK_RV rv = CKR_OK;
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;
328 CK_ULONG out_len;
329 CK_ULONG total_len;
330 CK_ULONG remain;
331 crypto_data_t out;
332
333 /*
334 * Blowfish only takes input length that is a multiple of 16 bytes
335 * for C_Decrypt function using CKM_BLOWFISH_CBC.
336 */
337
338 if (!update) {
339 /* Called by C_Decrypt */
340 if ((ulEncryptedLen % BLOWFISH_BLOCK_LEN) != 0) {
341 rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
342 goto cleanup;
343 }
344
345 /*
346 * If application asks for the length of the output buffer
347 * to hold the plaintext?
348 */
349 if (pData == NULL) {
350 *pulDataLen = ulEncryptedLen;
351 return (CKR_OK);
352 }
353
354 /* Is the application-supplied buffer large enough? */
355 if (*pulDataLen < ulEncryptedLen) {
356 *pulDataLen = ulEncryptedLen;
357 return (CKR_BUFFER_TOO_SMALL);
358 }
359 out_len = ulEncryptedLen;
360 in_buf = pEncrypted;
361 out_buf = pData;
362 } else {
363 /*
364 * Called by C_DecryptUpdate
365 *
366 * Add the lengths of last remaining data and current
367 * input data together to get the total input length.
368 */
369 total_len = soft_blowfish_ctx->remain_len + ulEncryptedLen;
370
371 if (total_len < BLOWFISH_BLOCK_LEN) {
372 if (pData != NULL) {
373 (void) memcpy(soft_blowfish_ctx->data +
374 soft_blowfish_ctx->remain_len,
375 pEncrypted, ulEncryptedLen);
376
377 soft_blowfish_ctx->remain_len += ulEncryptedLen;
378 }
379
380 /* Set output data length to 0. */
381 *pulDataLen = 0;
382 return (CKR_OK);
383 }
384
385 /* Compute the length of remaining data. */
386 remain = total_len % BLOWFISH_BLOCK_LEN;
387
388 /*
389 * Make sure that the output length is a multiple of
390 * blocksize.
391 */
392 out_len = total_len - remain;
393
394 /*
395 * if application asks for the length of the output buffer
396 * to hold the plaintext?
397 */
398 if (pData == NULL) {
399 *pulDataLen = out_len;
400 return (CKR_OK);
401 }
402
403 /*
404 * Is the application-supplied buffer large enough?
405 */
406 if (*pulDataLen < out_len) {
407 *pulDataLen = out_len;
408 return (CKR_BUFFER_TOO_SMALL);
409 }
410
411 if (soft_blowfish_ctx->remain_len != 0) {
412 /*
413 * Copy last remaining data and current input data
414 * to the output buffer.
415 */
416 (void) memmove(pData + soft_blowfish_ctx->remain_len,
417 pEncrypted,
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);
423
424
425 in_buf = pData;
426 } else {
427 in_buf = pEncrypted;
428 }
429
430 out_buf = pData;
431 }
432
433 out.cd_format = CRYPTO_DATA_RAW;
434 out.cd_offset = 0;
435 out.cd_length = out_len;
436 out.cd_raw.iov_base = (char *)out_buf;
437 out.cd_raw.iov_len = out_len;
438
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);
443
444 if (rc == 0) {
445 *pulDataLen = out_len;
446 if (update) {
447 /*
448 * For decrypt update, if there is remaining data,
449 * save it and its length in the context.
450 */
451 if (remain != 0)
452 (void) memcpy(soft_blowfish_ctx->data,
453 pEncrypted + (ulEncryptedLen - remain),
454 remain);
455 soft_blowfish_ctx->remain_len = remain;
456 return (CKR_OK);
457 }
458
459
460 } else {
461 *pulDataLen = 0;
462 rv = CKR_FUNCTION_FAILED;
463 }
464
465 cleanup:
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);
472 }
473
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);
479
480 return (rv);
481 }
482
483 /*
484 * Allocate and initialize a context for BLOWFISH CBC mode of operation.
485 */
486
487 void *
blowfish_cbc_ctx_init(void * key_sched,size_t size,uint8_t * ivec)488 blowfish_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec)
489 {
490
491 cbc_ctx_t *cbc_ctx;
492
493 if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
494 return (NULL);
495
496 cbc_ctx->cbc_keysched = key_sched;
497
498 (void) memcpy(&cbc_ctx->cbc_iv[0], ivec, BLOWFISH_BLOCK_LEN);
499
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;
503
504 return (cbc_ctx);
505 }
506