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 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <pthread.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <strings.h> 32 #include <sys/types.h> 33 #include <security/cryptoki.h> 34 #include "softSession.h" 35 #include "softObject.h" 36 #include "softCrypt.h" 37 #include <blowfish_impl.h> 38 39 CK_RV 40 soft_blowfish_crypt_init_common(soft_session_t *session_p, 41 CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t encrypt) { 42 43 size_t size; 44 soft_blowfish_ctx_t *soft_blowfish_ctx; 45 46 soft_blowfish_ctx = calloc(1, sizeof (soft_blowfish_ctx_t)); 47 if (soft_blowfish_ctx == NULL) { 48 return (CKR_HOST_MEMORY); 49 } 50 51 soft_blowfish_ctx->key_sched = blowfish_alloc_keysched(&size, 0); 52 53 if (soft_blowfish_ctx->key_sched == NULL) { 54 free(soft_blowfish_ctx); 55 return (CKR_HOST_MEMORY); 56 } 57 58 soft_blowfish_ctx->keysched_len = size; 59 60 (void) pthread_mutex_lock(&session_p->session_mutex); 61 if (encrypt) { 62 /* Called by C_EncryptInit */ 63 session_p->encrypt.context = soft_blowfish_ctx; 64 session_p->encrypt.mech.mechanism = pMechanism->mechanism; 65 } else { 66 /* Called by C_DecryptInit */ 67 session_p->decrypt.context = soft_blowfish_ctx; 68 session_p->decrypt.mech.mechanism = pMechanism->mechanism; 69 } 70 (void) pthread_mutex_unlock(&session_p->session_mutex); 71 72 /* 73 * If this is a non-sensitive key and it does NOT have 74 * a key schedule yet, then allocate one and expand it. 75 * Otherwise, if it's a non-sensitive key, and it DOES have 76 * a key schedule already attached to it, just copy the 77 * pre-expanded schedule to the context and avoid the 78 * extra key schedule expansion operation. 79 */ 80 if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) { 81 if (OBJ_KEY_SCHED(key_p) == NULL) { 82 void *ks; 83 84 (void) pthread_mutex_lock(&key_p->object_mutex); 85 if (OBJ_KEY_SCHED(key_p) == NULL) { 86 ks = blowfish_alloc_keysched(&size, 0); 87 if (ks == NULL) { 88 (void) pthread_mutex_unlock( 89 &key_p->object_mutex); 90 free(soft_blowfish_ctx); 91 return (CKR_HOST_MEMORY); 92 } 93 94 blowfish_init_keysched(OBJ_SEC_VALUE(key_p), 95 (OBJ_SEC_VALUE_LEN(key_p) * 8), ks); 96 97 OBJ_KEY_SCHED_LEN(key_p) = size; 98 OBJ_KEY_SCHED(key_p) = ks; 99 } 100 (void) pthread_mutex_unlock(&key_p->object_mutex); 101 } 102 (void) memcpy(soft_blowfish_ctx->key_sched, 103 OBJ_KEY_SCHED(key_p), OBJ_KEY_SCHED_LEN(key_p)); 104 soft_blowfish_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p); 105 106 } else { 107 /* 108 * Initialize key schedule for Blowfish. 109 * blowfish_init_keysched() requires key length in bits. 110 */ 111 blowfish_init_keysched(OBJ_SEC_VALUE(key_p), 112 (OBJ_SEC_VALUE_LEN(key_p) * 8), 113 soft_blowfish_ctx->key_sched); 114 } 115 return (CKR_OK); 116 } 117 118 119 /* 120 * soft_blowfish_encrypt_common() 121 * 122 * Arguments: 123 * session_p: pointer to soft_session_t struct 124 * pData: pointer to the input data to be encrypted 125 * ulDataLen: length of the input data 126 * pEncrypted: pointer to the output data after encryption 127 * pulEncryptedLen: pointer to the length of the output data 128 * update: boolean flag indicates caller is soft_encrypt 129 * or soft_encrypt_update 130 * 131 * Description: 132 * This function calls the corresponding encrypt routine based 133 * on the mechanism. 134 * 135 * Returns: 136 * CKR_OK: success 137 * CKR_BUFFER_TOO_SMALL: the output buffer provided by application 138 * is too small 139 * CKR_FUNCTION_FAILED: encrypt function failed 140 * CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize 141 */ 142 CK_RV 143 soft_blowfish_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData, 144 CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted, CK_ULONG_PTR pulEncryptedLen, 145 boolean_t update) { 146 147 int rc = 0; 148 CK_RV rv = CKR_OK; 149 soft_blowfish_ctx_t *soft_blowfish_ctx = 150 (soft_blowfish_ctx_t *)session_p->encrypt.context; 151 blowfish_ctx_t *blowfish_ctx; 152 CK_BYTE *in_buf = NULL; 153 CK_BYTE *out_buf = NULL; 154 CK_ULONG out_len; 155 CK_ULONG total_len; 156 CK_ULONG remain; 157 crypto_data_t out; 158 159 /* 160 * Blowfish only takes input length that is a multiple of blocksize 161 * for C_Encrypt function with the mechanism CKM_BLOWFISH_CBC. 162 * 163 */ 164 if (!update) { 165 if ((ulDataLen % BLOWFISH_BLOCK_LEN) != 0) { 166 rv = CKR_DATA_LEN_RANGE; 167 goto cleanup; 168 } 169 170 out_len = ulDataLen; 171 /* 172 * If application asks for the length of the output buffer 173 * to hold the ciphertext? 174 */ 175 if (pEncrypted == NULL) { 176 *pulEncryptedLen = out_len; 177 return (CKR_OK); 178 } 179 180 /* Is the application-supplied buffer large enough? */ 181 if (*pulEncryptedLen < out_len) { 182 *pulEncryptedLen = out_len; 183 return (CKR_BUFFER_TOO_SMALL); 184 } 185 186 in_buf = pData; 187 out_buf = pEncrypted; 188 } else { 189 /* 190 * Called by C_EncryptUpdate 191 * 192 * Add the lengths of last remaining data and current 193 * plaintext together to get the total input length. 194 */ 195 total_len = soft_blowfish_ctx->remain_len + ulDataLen; 196 197 /* 198 * If the total input length is less than one blocksize, 199 * we will need to delay encryption until when more data 200 * comes in next C_EncryptUpdate or when C_EncryptFinal 201 * is called. 202 */ 203 if (total_len < BLOWFISH_BLOCK_LEN) { 204 if (pEncrypted != NULL) { 205 /* 206 * Save input data and its length in 207 * the remaining buffer of BLOWFISH context. 208 */ 209 (void) memcpy(soft_blowfish_ctx->data + 210 soft_blowfish_ctx->remain_len, pData, 211 ulDataLen); 212 soft_blowfish_ctx->remain_len += ulDataLen; 213 } 214 215 /* Set encrypted data length to 0. */ 216 *pulEncryptedLen = 0; 217 return (CKR_OK); 218 } 219 220 /* Compute the length of remaing data. */ 221 remain = total_len % BLOWFISH_BLOCK_LEN; 222 223 /* 224 * Make sure that the output length is a multiple of 225 * blocksize. 226 */ 227 out_len = total_len - remain; 228 229 /* 230 * If application asks for the length of the output buffer 231 * to hold the ciphertext? 232 */ 233 if (pEncrypted == NULL) { 234 *pulEncryptedLen = out_len; 235 return (CKR_OK); 236 } 237 238 /* Is the application-supplied buffer large enough? */ 239 if (*pulEncryptedLen < out_len) { 240 *pulEncryptedLen = out_len; 241 return (CKR_BUFFER_TOO_SMALL); 242 } 243 244 if (soft_blowfish_ctx->remain_len != 0) { 245 /* 246 * Copy last remaining data and current input data 247 * to the output buffer. 248 */ 249 (void) memmove(pEncrypted + 250 soft_blowfish_ctx->remain_len, 251 pData, out_len - soft_blowfish_ctx->remain_len); 252 (void) memcpy(pEncrypted, soft_blowfish_ctx->data, 253 soft_blowfish_ctx->remain_len); 254 bzero(soft_blowfish_ctx->data, 255 soft_blowfish_ctx->remain_len); 256 257 in_buf = pEncrypted; 258 } else { 259 in_buf = pData; 260 } 261 out_buf = pEncrypted; 262 } 263 264 /* 265 * Begin Encryption now. 266 */ 267 268 out.cd_format = CRYPTO_DATA_RAW; 269 out.cd_offset = 0; 270 out.cd_length = out_len; 271 out.cd_raw.iov_base = (char *)out_buf; 272 out.cd_raw.iov_len = out_len; 273 274 /* Encrypt multiple blocks of data. */ 275 rc = blowfish_encrypt_contiguous_blocks( 276 (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc, 277 (char *)in_buf, out_len, &out); 278 279 if (rc == 0) { 280 *pulEncryptedLen = out_len; 281 if (update) { 282 /* 283 * For encrypt update, if there is remaining data, 284 * save it and it's length in the context. 285 */ 286 if (remain != 0) 287 (void) memcpy(soft_blowfish_ctx->data, pData + 288 (ulDataLen - remain), remain); 289 290 soft_blowfish_ctx->remain_len = remain; 291 return (CKR_OK); 292 } 293 294 } else { 295 *pulEncryptedLen = 0; 296 rv = CKR_FUNCTION_FAILED; 297 } 298 299 cleanup: 300 (void) pthread_mutex_lock(&session_p->session_mutex); 301 blowfish_ctx = (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc; 302 if (blowfish_ctx != NULL) { 303 bzero(blowfish_ctx->bc_keysched, 304 blowfish_ctx->bc_keysched_len); 305 free(soft_blowfish_ctx->blowfish_cbc); 306 } 307 308 bzero(soft_blowfish_ctx->key_sched, soft_blowfish_ctx->keysched_len); 309 free(soft_blowfish_ctx->key_sched); 310 free(session_p->encrypt.context); 311 session_p->encrypt.context = NULL; 312 (void) pthread_mutex_unlock(&session_p->session_mutex); 313 314 return (rv); 315 } 316 317 318 CK_RV 319 soft_blowfish_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted, 320 CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen, 321 boolean_t update) { 322 323 int rc = 0; 324 CK_RV rv = CKR_OK; 325 soft_blowfish_ctx_t *soft_blowfish_ctx = 326 (soft_blowfish_ctx_t *)session_p->decrypt.context; 327 blowfish_ctx_t *blowfish_ctx; 328 CK_BYTE *in_buf = NULL; 329 CK_BYTE *out_buf = NULL; 330 CK_ULONG out_len; 331 CK_ULONG total_len; 332 CK_ULONG remain; 333 crypto_data_t out; 334 335 /* 336 * Blowfish only takes input length that is a multiple of 16 bytes 337 * for C_Decrypt function using CKM_BLOWFISH_CBC. 338 */ 339 340 if (!update) { 341 /* Called by C_Decrypt */ 342 if ((ulEncryptedLen % BLOWFISH_BLOCK_LEN) != 0) { 343 rv = CKR_ENCRYPTED_DATA_LEN_RANGE; 344 goto cleanup; 345 } 346 347 /* 348 * If application asks for the length of the output buffer 349 * to hold the plaintext? 350 */ 351 if (pData == NULL) { 352 *pulDataLen = ulEncryptedLen; 353 return (CKR_OK); 354 } 355 356 /* Is the application-supplied buffer large enough? */ 357 if (*pulDataLen < ulEncryptedLen) { 358 *pulDataLen = ulEncryptedLen; 359 return (CKR_BUFFER_TOO_SMALL); 360 } 361 out_len = ulEncryptedLen; 362 in_buf = pEncrypted; 363 out_buf = pData; 364 } else { 365 /* 366 * Called by C_DecryptUpdate 367 * 368 * Add the lengths of last remaining data and current 369 * input data together to get the total input length. 370 */ 371 total_len = soft_blowfish_ctx->remain_len + ulEncryptedLen; 372 373 if (total_len < BLOWFISH_BLOCK_LEN) { 374 if (pData != NULL) { 375 (void) memcpy(soft_blowfish_ctx->data + 376 soft_blowfish_ctx->remain_len, 377 pEncrypted, ulEncryptedLen); 378 379 soft_blowfish_ctx->remain_len += ulEncryptedLen; 380 } 381 382 /* Set output data length to 0. */ 383 *pulDataLen = 0; 384 return (CKR_OK); 385 } 386 387 /* Compute the length of remaining data. */ 388 remain = total_len % BLOWFISH_BLOCK_LEN; 389 390 /* 391 * Make sure that the output length is a multiple of 392 * blocksize. 393 */ 394 out_len = total_len - remain; 395 396 /* 397 * if application asks for the length of the output buffer 398 * to hold the plaintext? 399 */ 400 if (pData == NULL) { 401 *pulDataLen = out_len; 402 return (CKR_OK); 403 } 404 405 /* 406 * Is the application-supplied buffer large enough? 407 */ 408 if (*pulDataLen < out_len) { 409 *pulDataLen = out_len; 410 return (CKR_BUFFER_TOO_SMALL); 411 } 412 413 if (soft_blowfish_ctx->remain_len != 0) { 414 /* 415 * Copy last remaining data and current input data 416 * to the output buffer. 417 */ 418 (void) memmove(pData + soft_blowfish_ctx->remain_len, 419 pEncrypted, 420 out_len - soft_blowfish_ctx->remain_len); 421 (void) memcpy(pData, soft_blowfish_ctx->data, 422 soft_blowfish_ctx->remain_len); 423 bzero(soft_blowfish_ctx->data, 424 soft_blowfish_ctx->remain_len); 425 426 427 in_buf = pData; 428 } else { 429 in_buf = pEncrypted; 430 } 431 432 out_buf = pData; 433 } 434 435 out.cd_format = CRYPTO_DATA_RAW; 436 out.cd_offset = 0; 437 out.cd_length = out_len; 438 out.cd_raw.iov_base = (char *)out_buf; 439 out.cd_raw.iov_len = out_len; 440 441 /* Decrypt multiple blocks of data. */ 442 rc = blowfish_decrypt_contiguous_blocks( 443 (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc, 444 (char *)in_buf, out_len, &out); 445 446 if (rc == 0) { 447 *pulDataLen = out_len; 448 if (update) { 449 /* 450 * For decrypt update, if there is remaining data, 451 * save it and its length in the context. 452 */ 453 if (remain != 0) 454 (void) memcpy(soft_blowfish_ctx->data, 455 pEncrypted + (ulEncryptedLen - remain), 456 remain); 457 soft_blowfish_ctx->remain_len = remain; 458 return (CKR_OK); 459 } 460 461 462 } else { 463 *pulDataLen = 0; 464 rv = CKR_FUNCTION_FAILED; 465 } 466 467 cleanup: 468 (void) pthread_mutex_lock(&session_p->session_mutex); 469 blowfish_ctx = (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc; 470 if (blowfish_ctx != NULL) { 471 bzero(blowfish_ctx->bc_keysched, 472 blowfish_ctx->bc_keysched_len); 473 free(soft_blowfish_ctx->blowfish_cbc); 474 } 475 476 bzero(soft_blowfish_ctx->key_sched, soft_blowfish_ctx->keysched_len); 477 free(soft_blowfish_ctx->key_sched); 478 free(session_p->decrypt.context); 479 session_p->decrypt.context = NULL; 480 (void) pthread_mutex_unlock(&session_p->session_mutex); 481 482 return (rv); 483 } 484 485 /* 486 * Allocate and initialize a context for BLOWFISH CBC mode of operation. 487 */ 488 489 void * 490 blowfish_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec) 491 { 492 493 cbc_ctx_t *cbc_ctx; 494 495 if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL) 496 return (NULL); 497 498 cbc_ctx->cc_keysched = key_sched; 499 500 (void) memcpy(&cbc_ctx->cc_iv[0], ivec, BLOWFISH_BLOCK_LEN); 501 502 cbc_ctx->cc_lastp = (uint8_t *)&(cbc_ctx->cc_iv); 503 cbc_ctx->cc_keysched_len = size; 504 cbc_ctx->cc_flags |= CBC_MODE; 505 506 return (cbc_ctx); 507 } 508