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 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 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 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 * 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