1676Sizick /*
22940Sizick * CDDL HEADER START
32940Sizick *
42940Sizick * The contents of this file are subject to the terms of the
52940Sizick * Common Development and Distribution License (the "License").
62940Sizick * You may not use this file except in compliance with the License.
72940Sizick *
82940Sizick * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92940Sizick * or http://www.opensolaris.org/os/licensing.
102940Sizick * See the License for the specific language governing permissions
112940Sizick * and limitations under the License.
122940Sizick *
132940Sizick * When distributing Covered Code, include this CDDL HEADER in each
142940Sizick * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152940Sizick * If applicable, add the following below this CDDL HEADER, with the
162940Sizick * fields enclosed by brackets "[]" replaced with your own identifying
172940Sizick * information: Portions Copyright [yyyy] [name of copyright owner]
182940Sizick *
192940Sizick * CDDL HEADER END
202940Sizick */
212940Sizick /*
225862Smcpowers * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23676Sizick * Use is subject to license terms.
24676Sizick */
25676Sizick
26676Sizick #include <pthread.h>
27676Sizick #include <stdlib.h>
28676Sizick #include <string.h>
29676Sizick #include <strings.h>
30676Sizick #include <sys/types.h>
31676Sizick #include <security/cryptoki.h>
32676Sizick #include "softSession.h"
33676Sizick #include "softObject.h"
34676Sizick #include "softCrypt.h"
357188Smcpowers #include <blowfish_impl.h>
36676Sizick
37676Sizick CK_RV
soft_blowfish_crypt_init_common(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p,boolean_t encrypt)38676Sizick soft_blowfish_crypt_init_common(soft_session_t *session_p,
39676Sizick CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t encrypt) {
40676Sizick
41676Sizick size_t size;
42676Sizick soft_blowfish_ctx_t *soft_blowfish_ctx;
43676Sizick
44676Sizick soft_blowfish_ctx = calloc(1, sizeof (soft_blowfish_ctx_t));
45676Sizick if (soft_blowfish_ctx == NULL) {
46676Sizick return (CKR_HOST_MEMORY);
47676Sizick }
48676Sizick
49676Sizick soft_blowfish_ctx->key_sched = blowfish_alloc_keysched(&size, 0);
50676Sizick
51676Sizick if (soft_blowfish_ctx->key_sched == NULL) {
52676Sizick free(soft_blowfish_ctx);
53676Sizick return (CKR_HOST_MEMORY);
54676Sizick }
55676Sizick
56676Sizick soft_blowfish_ctx->keysched_len = size;
57676Sizick
58676Sizick (void) pthread_mutex_lock(&session_p->session_mutex);
59676Sizick if (encrypt) {
60676Sizick /* Called by C_EncryptInit */
61676Sizick session_p->encrypt.context = soft_blowfish_ctx;
62676Sizick session_p->encrypt.mech.mechanism = pMechanism->mechanism;
63676Sizick } else {
64676Sizick /* Called by C_DecryptInit */
65676Sizick session_p->decrypt.context = soft_blowfish_ctx;
66676Sizick session_p->decrypt.mech.mechanism = pMechanism->mechanism;
67676Sizick }
68676Sizick (void) pthread_mutex_unlock(&session_p->session_mutex);
69676Sizick
70676Sizick /*
71676Sizick * If this is a non-sensitive key and it does NOT have
72676Sizick * a key schedule yet, then allocate one and expand it.
73676Sizick * Otherwise, if it's a non-sensitive key, and it DOES have
74676Sizick * a key schedule already attached to it, just copy the
75676Sizick * pre-expanded schedule to the context and avoid the
76676Sizick * extra key schedule expansion operation.
77676Sizick */
78676Sizick if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
795862Smcpowers if (OBJ_KEY_SCHED(key_p) == NULL) {
80676Sizick void *ks;
815862Smcpowers
825862Smcpowers (void) pthread_mutex_lock(&key_p->object_mutex);
835862Smcpowers if (OBJ_KEY_SCHED(key_p) == NULL) {
845862Smcpowers ks = blowfish_alloc_keysched(&size, 0);
855862Smcpowers if (ks == NULL) {
865862Smcpowers (void) pthread_mutex_unlock(
875862Smcpowers &key_p->object_mutex);
885862Smcpowers free(soft_blowfish_ctx);
895862Smcpowers return (CKR_HOST_MEMORY);
905862Smcpowers }
915862Smcpowers
925862Smcpowers blowfish_init_keysched(OBJ_SEC_VALUE(key_p),
935862Smcpowers (OBJ_SEC_VALUE_LEN(key_p) * 8), ks);
945862Smcpowers
955862Smcpowers OBJ_KEY_SCHED_LEN(key_p) = size;
965862Smcpowers OBJ_KEY_SCHED(key_p) = ks;
97676Sizick }
985862Smcpowers (void) pthread_mutex_unlock(&key_p->object_mutex);
99676Sizick }
100676Sizick (void) memcpy(soft_blowfish_ctx->key_sched,
101676Sizick OBJ_KEY_SCHED(key_p), OBJ_KEY_SCHED_LEN(key_p));
102676Sizick soft_blowfish_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
103676Sizick
104676Sizick } else {
105676Sizick /*
106676Sizick * Initialize key schedule for Blowfish.
107676Sizick * blowfish_init_keysched() requires key length in bits.
108676Sizick */
109676Sizick blowfish_init_keysched(OBJ_SEC_VALUE(key_p),
110676Sizick (OBJ_SEC_VALUE_LEN(key_p) * 8),
111676Sizick soft_blowfish_ctx->key_sched);
112676Sizick }
113676Sizick return (CKR_OK);
114676Sizick }
115676Sizick
116676Sizick
117676Sizick /*
118676Sizick * soft_blowfish_encrypt_common()
119676Sizick *
120676Sizick * Arguments:
121676Sizick * session_p: pointer to soft_session_t struct
122676Sizick * pData: pointer to the input data to be encrypted
123676Sizick * ulDataLen: length of the input data
124676Sizick * pEncrypted: pointer to the output data after encryption
125676Sizick * pulEncryptedLen: pointer to the length of the output data
126676Sizick * update: boolean flag indicates caller is soft_encrypt
127676Sizick * or soft_encrypt_update
128676Sizick *
129676Sizick * Description:
130676Sizick * This function calls the corresponding encrypt routine based
131676Sizick * on the mechanism.
132676Sizick *
133676Sizick * Returns:
134676Sizick * CKR_OK: success
135676Sizick * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
136676Sizick * is too small
137676Sizick * CKR_FUNCTION_FAILED: encrypt function failed
138676Sizick * CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
139676Sizick */
140676Sizick CK_RV
soft_blowfish_encrypt_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pEncrypted,CK_ULONG_PTR pulEncryptedLen,boolean_t update)141676Sizick soft_blowfish_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
142676Sizick CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted, CK_ULONG_PTR pulEncryptedLen,
143676Sizick boolean_t update) {
144676Sizick
145676Sizick int rc = 0;
146676Sizick CK_RV rv = CKR_OK;
147676Sizick soft_blowfish_ctx_t *soft_blowfish_ctx =
148676Sizick (soft_blowfish_ctx_t *)session_p->encrypt.context;
149676Sizick blowfish_ctx_t *blowfish_ctx;
150676Sizick CK_BYTE *in_buf = NULL;
151676Sizick CK_BYTE *out_buf = NULL;
152676Sizick CK_ULONG out_len;
153676Sizick CK_ULONG total_len;
154676Sizick CK_ULONG remain;
155676Sizick crypto_data_t out;
156676Sizick
157676Sizick /*
158676Sizick * Blowfish only takes input length that is a multiple of blocksize
159676Sizick * for C_Encrypt function with the mechanism CKM_BLOWFISH_CBC.
160676Sizick *
161676Sizick */
162676Sizick if (!update) {
163676Sizick if ((ulDataLen % BLOWFISH_BLOCK_LEN) != 0) {
164676Sizick rv = CKR_DATA_LEN_RANGE;
165676Sizick goto cleanup;
166676Sizick }
167676Sizick
168676Sizick out_len = ulDataLen;
169676Sizick /*
170676Sizick * If application asks for the length of the output buffer
171676Sizick * to hold the ciphertext?
172676Sizick */
173676Sizick if (pEncrypted == NULL) {
174676Sizick *pulEncryptedLen = out_len;
175676Sizick return (CKR_OK);
176676Sizick }
177676Sizick
178676Sizick /* Is the application-supplied buffer large enough? */
179676Sizick if (*pulEncryptedLen < out_len) {
180676Sizick *pulEncryptedLen = out_len;
181676Sizick return (CKR_BUFFER_TOO_SMALL);
182676Sizick }
183676Sizick
184676Sizick in_buf = pData;
185676Sizick out_buf = pEncrypted;
186676Sizick } else {
187676Sizick /*
188676Sizick * Called by C_EncryptUpdate
189676Sizick *
190676Sizick * Add the lengths of last remaining data and current
191676Sizick * plaintext together to get the total input length.
192676Sizick */
193676Sizick total_len = soft_blowfish_ctx->remain_len + ulDataLen;
194676Sizick
195676Sizick /*
196676Sizick * If the total input length is less than one blocksize,
197676Sizick * we will need to delay encryption until when more data
198676Sizick * comes in next C_EncryptUpdate or when C_EncryptFinal
199676Sizick * is called.
200676Sizick */
201676Sizick if (total_len < BLOWFISH_BLOCK_LEN) {
202676Sizick if (pEncrypted != NULL) {
203676Sizick /*
204676Sizick * Save input data and its length in
205676Sizick * the remaining buffer of BLOWFISH context.
206676Sizick */
207676Sizick (void) memcpy(soft_blowfish_ctx->data +
208676Sizick soft_blowfish_ctx->remain_len, pData,
209676Sizick ulDataLen);
210676Sizick soft_blowfish_ctx->remain_len += ulDataLen;
211676Sizick }
212676Sizick
213676Sizick /* Set encrypted data length to 0. */
214676Sizick *pulEncryptedLen = 0;
215676Sizick return (CKR_OK);
216676Sizick }
217676Sizick
218676Sizick /* Compute the length of remaing data. */
219676Sizick remain = total_len % BLOWFISH_BLOCK_LEN;
220676Sizick
221676Sizick /*
222676Sizick * Make sure that the output length is a multiple of
223676Sizick * blocksize.
224676Sizick */
225676Sizick out_len = total_len - remain;
226676Sizick
227676Sizick /*
228676Sizick * If application asks for the length of the output buffer
229676Sizick * to hold the ciphertext?
230676Sizick */
231676Sizick if (pEncrypted == NULL) {
232676Sizick *pulEncryptedLen = out_len;
233676Sizick return (CKR_OK);
234676Sizick }
235676Sizick
236676Sizick /* Is the application-supplied buffer large enough? */
237676Sizick if (*pulEncryptedLen < out_len) {
238676Sizick *pulEncryptedLen = out_len;
239676Sizick return (CKR_BUFFER_TOO_SMALL);
240676Sizick }
241676Sizick
242676Sizick if (soft_blowfish_ctx->remain_len != 0) {
243676Sizick /*
244676Sizick * Copy last remaining data and current input data
245676Sizick * to the output buffer.
246676Sizick */
247676Sizick (void) memmove(pEncrypted +
248676Sizick soft_blowfish_ctx->remain_len,
249676Sizick pData, out_len - soft_blowfish_ctx->remain_len);
250676Sizick (void) memcpy(pEncrypted, soft_blowfish_ctx->data,
251676Sizick soft_blowfish_ctx->remain_len);
252676Sizick bzero(soft_blowfish_ctx->data,
253676Sizick soft_blowfish_ctx->remain_len);
254676Sizick
255676Sizick in_buf = pEncrypted;
256676Sizick } else {
257676Sizick in_buf = pData;
258676Sizick }
259676Sizick out_buf = pEncrypted;
260676Sizick }
261676Sizick
262676Sizick /*
263676Sizick * Begin Encryption now.
264676Sizick */
265676Sizick
266676Sizick out.cd_format = CRYPTO_DATA_RAW;
267676Sizick out.cd_offset = 0;
268676Sizick out.cd_length = out_len;
269676Sizick out.cd_raw.iov_base = (char *)out_buf;
270676Sizick out.cd_raw.iov_len = out_len;
271676Sizick
272676Sizick /* Encrypt multiple blocks of data. */
273676Sizick rc = blowfish_encrypt_contiguous_blocks(
274676Sizick (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc,
275676Sizick (char *)in_buf, out_len, &out);
276676Sizick
277676Sizick if (rc == 0) {
278676Sizick *pulEncryptedLen = out_len;
279676Sizick if (update) {
280676Sizick /*
281676Sizick * For encrypt update, if there is remaining data,
282676Sizick * save it and it's length in the context.
283676Sizick */
284676Sizick if (remain != 0)
285676Sizick (void) memcpy(soft_blowfish_ctx->data, pData +
286676Sizick (ulDataLen - remain), remain);
287676Sizick
288676Sizick soft_blowfish_ctx->remain_len = remain;
2892940Sizick return (CKR_OK);
290676Sizick }
291676Sizick
2922940Sizick } else {
2932940Sizick *pulEncryptedLen = 0;
2942940Sizick rv = CKR_FUNCTION_FAILED;
295676Sizick }
296676Sizick
297676Sizick cleanup:
298676Sizick (void) pthread_mutex_lock(&session_p->session_mutex);
299676Sizick blowfish_ctx = (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc;
300676Sizick if (blowfish_ctx != NULL) {
301676Sizick bzero(blowfish_ctx->bc_keysched,
302676Sizick blowfish_ctx->bc_keysched_len);
303676Sizick free(soft_blowfish_ctx->blowfish_cbc);
304676Sizick }
305676Sizick
306676Sizick bzero(soft_blowfish_ctx->key_sched, soft_blowfish_ctx->keysched_len);
307676Sizick free(soft_blowfish_ctx->key_sched);
308676Sizick free(session_p->encrypt.context);
309676Sizick session_p->encrypt.context = NULL;
310676Sizick (void) pthread_mutex_unlock(&session_p->session_mutex);
311676Sizick
312676Sizick return (rv);
313676Sizick }
314676Sizick
315676Sizick
316676Sizick CK_RV
soft_blowfish_decrypt_common(soft_session_t * session_p,CK_BYTE_PTR pEncrypted,CK_ULONG ulEncryptedLen,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen,boolean_t update)317676Sizick soft_blowfish_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted,
318676Sizick CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen,
319676Sizick boolean_t update) {
320676Sizick
321676Sizick int rc = 0;
322676Sizick CK_RV rv = CKR_OK;
323676Sizick soft_blowfish_ctx_t *soft_blowfish_ctx =
324676Sizick (soft_blowfish_ctx_t *)session_p->decrypt.context;
325676Sizick blowfish_ctx_t *blowfish_ctx;
326676Sizick CK_BYTE *in_buf = NULL;
327676Sizick CK_BYTE *out_buf = NULL;
328676Sizick CK_ULONG out_len;
329676Sizick CK_ULONG total_len;
330676Sizick CK_ULONG remain;
331676Sizick crypto_data_t out;
332676Sizick
333676Sizick /*
334676Sizick * Blowfish only takes input length that is a multiple of 16 bytes
335676Sizick * for C_Decrypt function using CKM_BLOWFISH_CBC.
336676Sizick */
337676Sizick
338676Sizick if (!update) {
339676Sizick /* Called by C_Decrypt */
340676Sizick if ((ulEncryptedLen % BLOWFISH_BLOCK_LEN) != 0) {
341676Sizick rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
342676Sizick goto cleanup;
343676Sizick }
344676Sizick
345676Sizick /*
3462940Sizick * If application asks for the length of the output buffer
347676Sizick * to hold the plaintext?
348676Sizick */
349676Sizick if (pData == NULL) {
350676Sizick *pulDataLen = ulEncryptedLen;
351676Sizick return (CKR_OK);
352676Sizick }
353676Sizick
354676Sizick /* Is the application-supplied buffer large enough? */
355676Sizick if (*pulDataLen < ulEncryptedLen) {
356676Sizick *pulDataLen = ulEncryptedLen;
357676Sizick return (CKR_BUFFER_TOO_SMALL);
358676Sizick }
359676Sizick out_len = ulEncryptedLen;
360676Sizick in_buf = pEncrypted;
361676Sizick out_buf = pData;
362676Sizick } else {
363676Sizick /*
364676Sizick * Called by C_DecryptUpdate
365676Sizick *
366676Sizick * Add the lengths of last remaining data and current
367676Sizick * input data together to get the total input length.
368676Sizick */
369676Sizick total_len = soft_blowfish_ctx->remain_len + ulEncryptedLen;
370676Sizick
371676Sizick if (total_len < BLOWFISH_BLOCK_LEN) {
372676Sizick if (pData != NULL) {
373676Sizick (void) memcpy(soft_blowfish_ctx->data +
374676Sizick soft_blowfish_ctx->remain_len,
375676Sizick pEncrypted, ulEncryptedLen);
376676Sizick
377676Sizick soft_blowfish_ctx->remain_len += ulEncryptedLen;
378676Sizick }
379676Sizick
380676Sizick /* Set output data length to 0. */
381676Sizick *pulDataLen = 0;
382676Sizick return (CKR_OK);
383676Sizick }
384676Sizick
385676Sizick /* Compute the length of remaining data. */
386676Sizick remain = total_len % BLOWFISH_BLOCK_LEN;
387676Sizick
388676Sizick /*
389676Sizick * Make sure that the output length is a multiple of
390676Sizick * blocksize.
391676Sizick */
392676Sizick out_len = total_len - remain;
393676Sizick
394676Sizick /*
395676Sizick * if application asks for the length of the output buffer
396676Sizick * to hold the plaintext?
397676Sizick */
398676Sizick if (pData == NULL) {
399676Sizick *pulDataLen = out_len;
400676Sizick return (CKR_OK);
401676Sizick }
402676Sizick
403676Sizick /*
404676Sizick * Is the application-supplied buffer large enough?
405676Sizick */
406676Sizick if (*pulDataLen < out_len) {
407676Sizick *pulDataLen = out_len;
408676Sizick return (CKR_BUFFER_TOO_SMALL);
409676Sizick }
410676Sizick
411676Sizick if (soft_blowfish_ctx->remain_len != 0) {
412676Sizick /*
413676Sizick * Copy last remaining data and current input data
414676Sizick * to the output buffer.
415676Sizick */
416676Sizick (void) memmove(pData + soft_blowfish_ctx->remain_len,
417676Sizick pEncrypted,
418676Sizick out_len - soft_blowfish_ctx->remain_len);
419676Sizick (void) memcpy(pData, soft_blowfish_ctx->data,
420676Sizick soft_blowfish_ctx->remain_len);
421676Sizick bzero(soft_blowfish_ctx->data,
422676Sizick soft_blowfish_ctx->remain_len);
423676Sizick
424676Sizick
425676Sizick in_buf = pData;
426676Sizick } else {
427676Sizick in_buf = pEncrypted;
428676Sizick }
429676Sizick
430676Sizick out_buf = pData;
431676Sizick }
432676Sizick
433676Sizick out.cd_format = CRYPTO_DATA_RAW;
434676Sizick out.cd_offset = 0;
435676Sizick out.cd_length = out_len;
436676Sizick out.cd_raw.iov_base = (char *)out_buf;
437676Sizick out.cd_raw.iov_len = out_len;
438676Sizick
439676Sizick /* Decrypt multiple blocks of data. */
440676Sizick rc = blowfish_decrypt_contiguous_blocks(
441676Sizick (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc,
442676Sizick (char *)in_buf, out_len, &out);
443676Sizick
444676Sizick if (rc == 0) {
445676Sizick *pulDataLen = out_len;
446676Sizick if (update) {
447676Sizick /*
448676Sizick * For decrypt update, if there is remaining data,
449676Sizick * save it and its length in the context.
450676Sizick */
451676Sizick if (remain != 0)
452676Sizick (void) memcpy(soft_blowfish_ctx->data,
453676Sizick pEncrypted + (ulEncryptedLen - remain),
454676Sizick remain);
455676Sizick soft_blowfish_ctx->remain_len = remain;
456676Sizick return (CKR_OK);
457676Sizick }
458676Sizick
459676Sizick
460676Sizick } else {
461676Sizick *pulDataLen = 0;
462676Sizick rv = CKR_FUNCTION_FAILED;
463676Sizick }
464676Sizick
465676Sizick cleanup:
466676Sizick (void) pthread_mutex_lock(&session_p->session_mutex);
467676Sizick blowfish_ctx = (blowfish_ctx_t *)soft_blowfish_ctx->blowfish_cbc;
468676Sizick if (blowfish_ctx != NULL) {
469676Sizick bzero(blowfish_ctx->bc_keysched,
470676Sizick blowfish_ctx->bc_keysched_len);
471676Sizick free(soft_blowfish_ctx->blowfish_cbc);
472676Sizick }
473676Sizick
474676Sizick bzero(soft_blowfish_ctx->key_sched, soft_blowfish_ctx->keysched_len);
475676Sizick free(soft_blowfish_ctx->key_sched);
476676Sizick free(session_p->decrypt.context);
477676Sizick session_p->decrypt.context = NULL;
478676Sizick (void) pthread_mutex_unlock(&session_p->session_mutex);
479676Sizick
480676Sizick return (rv);
481676Sizick }
482676Sizick
483676Sizick /*
484676Sizick * Allocate and initialize a context for BLOWFISH CBC mode of operation.
485676Sizick */
486676Sizick
487676Sizick void *
blowfish_cbc_ctx_init(void * key_sched,size_t size,uint8_t * ivec)488676Sizick blowfish_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec)
489676Sizick {
490676Sizick
4917188Smcpowers cbc_ctx_t *cbc_ctx;
492676Sizick
4937188Smcpowers if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
494676Sizick return (NULL);
495676Sizick
496*7581SMark.Powers@Sun.COM cbc_ctx->cbc_keysched = key_sched;
497676Sizick
498*7581SMark.Powers@Sun.COM (void) memcpy(&cbc_ctx->cbc_iv[0], ivec, BLOWFISH_BLOCK_LEN);
499676Sizick
500*7581SMark.Powers@Sun.COM cbc_ctx->cbc_lastp = (uint8_t *)&(cbc_ctx->cbc_iv);
501*7581SMark.Powers@Sun.COM cbc_ctx->cbc_keysched_len = size;
502*7581SMark.Powers@Sun.COM cbc_ctx->cbc_flags |= CBC_MODE;
503676Sizick
5047188Smcpowers return (cbc_ctx);
505676Sizick }
506