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