Home | History | Annotate | Download | only in modes
      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 #ifndef _KERNEL
     27 #include <strings.h>
     28 #include <limits.h>
     29 #include <assert.h>
     30 #include <security/cryptoki.h>
     31 #endif
     32 
     33 #include <sys/types.h>
     34 #include <modes/modes.h>
     35 #include <sys/crypto/common.h>
     36 #include <sys/crypto/impl.h>
     37 
     38 /*
     39  * Algorithm independent ECB functions.
     40  */
     41 int
     42 ecb_cipher_contiguous_blocks(ecb_ctx_t *ctx, char *data, size_t length,
     43     crypto_data_t *out, size_t block_size,
     44     int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct))
     45 {
     46 	size_t remainder = length;
     47 	size_t need;
     48 	uint8_t *datap = (uint8_t *)data;
     49 	uint8_t *blockp;
     50 	uint8_t *lastp;
     51 	void *iov_or_mp;
     52 	offset_t offset;
     53 	uint8_t *out_data_1;
     54 	uint8_t *out_data_2;
     55 	size_t out_data_1_len;
     56 
     57 	if (length + ctx->ecb_remainder_len < block_size) {
     58 		/* accumulate bytes here and return */
     59 		bcopy(datap,
     60 		    (uint8_t *)ctx->ecb_remainder + ctx->ecb_remainder_len,
     61 		    length);
     62 		ctx->ecb_remainder_len += length;
     63 		ctx->ecb_copy_to = datap;
     64 		return (CRYPTO_SUCCESS);
     65 	}
     66 
     67 	lastp = (uint8_t *)ctx->ecb_iv;
     68 	if (out != NULL)
     69 		crypto_init_ptrs(out, &iov_or_mp, &offset);
     70 
     71 	do {
     72 		/* Unprocessed data from last call. */
     73 		if (ctx->ecb_remainder_len > 0) {
     74 			need = block_size - ctx->ecb_remainder_len;
     75 
     76 			if (need > remainder)
     77 				return (CRYPTO_DATA_LEN_RANGE);
     78 
     79 			bcopy(datap, &((uint8_t *)ctx->ecb_remainder)
     80 			    [ctx->ecb_remainder_len], need);
     81 
     82 			blockp = (uint8_t *)ctx->ecb_remainder;
     83 		} else {
     84 			blockp = datap;
     85 		}
     86 
     87 		if (out == NULL) {
     88 			cipher(ctx->ecb_keysched, blockp, blockp);
     89 
     90 			ctx->ecb_lastp = blockp;
     91 			lastp = blockp;
     92 
     93 			if (ctx->ecb_remainder_len > 0) {
     94 				bcopy(blockp, ctx->ecb_copy_to,
     95 				    ctx->ecb_remainder_len);
     96 				bcopy(blockp + ctx->ecb_remainder_len, datap,
     97 				    need);
     98 			}
     99 		} else {
    100 			cipher(ctx->ecb_keysched, blockp, lastp);
    101 			crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
    102 			    &out_data_1_len, &out_data_2, block_size);
    103 
    104 			/* copy block to where it belongs */
    105 			bcopy(lastp, out_data_1, out_data_1_len);
    106 			if (out_data_2 != NULL) {
    107 				bcopy(lastp + out_data_1_len, out_data_2,
    108 				    block_size - out_data_1_len);
    109 			}
    110 			/* update offset */
    111 			out->cd_offset += block_size;
    112 		}
    113 
    114 		/* Update pointer to next block of data to be processed. */
    115 		if (ctx->ecb_remainder_len != 0) {
    116 			datap += need;
    117 			ctx->ecb_remainder_len = 0;
    118 		} else {
    119 			datap += block_size;
    120 		}
    121 
    122 		remainder = (size_t)&data[length] - (size_t)datap;
    123 
    124 		/* Incomplete last block. */
    125 		if (remainder > 0 && remainder < block_size) {
    126 			bcopy(datap, ctx->ecb_remainder, remainder);
    127 			ctx->ecb_remainder_len = remainder;
    128 			ctx->ecb_copy_to = datap;
    129 			goto out;
    130 		}
    131 		ctx->ecb_copy_to = NULL;
    132 
    133 	} while (remainder > 0);
    134 
    135 out:
    136 	return (CRYPTO_SUCCESS);
    137 }
    138 
    139 /* ARGSUSED */
    140 void *
    141 ecb_alloc_ctx(int kmflag)
    142 {
    143 	ecb_ctx_t *ecb_ctx;
    144 
    145 #ifdef _KERNEL
    146 	if ((ecb_ctx = kmem_zalloc(sizeof (ecb_ctx_t), kmflag)) == NULL)
    147 #else
    148 	if ((ecb_ctx = calloc(1, sizeof (ecb_ctx_t))) == NULL)
    149 #endif
    150 		return (NULL);
    151 
    152 	ecb_ctx->ecb_flags = ECB_MODE;
    153 	return (ecb_ctx);
    154 }
    155