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