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