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