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