123c57df7Smcpowers /*
223c57df7Smcpowers * CDDL HEADER START
323c57df7Smcpowers *
423c57df7Smcpowers * The contents of this file are subject to the terms of the
523c57df7Smcpowers * Common Development and Distribution License (the "License").
623c57df7Smcpowers * You may not use this file except in compliance with the License.
723c57df7Smcpowers *
823c57df7Smcpowers * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
923c57df7Smcpowers * or http://www.opensolaris.org/os/licensing.
1023c57df7Smcpowers * See the License for the specific language governing permissions
1123c57df7Smcpowers * and limitations under the License.
1223c57df7Smcpowers *
1323c57df7Smcpowers * When distributing Covered Code, include this CDDL HEADER in each
1423c57df7Smcpowers * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1523c57df7Smcpowers * If applicable, add the following below this CDDL HEADER, with the
1623c57df7Smcpowers * fields enclosed by brackets "[]" replaced with your own identifying
1723c57df7Smcpowers * information: Portions Copyright [yyyy] [name of copyright owner]
1823c57df7Smcpowers *
1923c57df7Smcpowers * CDDL HEADER END
2023c57df7Smcpowers */
2123c57df7Smcpowers /*
2223c57df7Smcpowers * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2323c57df7Smcpowers * Use is subject to license terms.
2423c57df7Smcpowers */
2523c57df7Smcpowers
2623c57df7Smcpowers #ifndef _KERNEL
2723c57df7Smcpowers #include <strings.h>
2823c57df7Smcpowers #include <limits.h>
2923c57df7Smcpowers #include <assert.h>
3023c57df7Smcpowers #include <security/cryptoki.h>
3123c57df7Smcpowers #endif
3223c57df7Smcpowers
3323c57df7Smcpowers #include <sys/types.h>
3423c57df7Smcpowers #include <modes/modes.h>
3523c57df7Smcpowers #include <sys/crypto/common.h>
3623c57df7Smcpowers #include <sys/crypto/impl.h>
3723c57df7Smcpowers
3823c57df7Smcpowers /*
3923c57df7Smcpowers * Algorithm independent CBC functions.
4023c57df7Smcpowers */
4123c57df7Smcpowers int
cbc_encrypt_contiguous_blocks(cbc_ctx_t * ctx,char * data,size_t length,crypto_data_t * out,size_t block_size,int (* encrypt)(const void *,const uint8_t *,uint8_t *),void (* copy_block)(uint8_t *,uint8_t *),void (* xor_block)(uint8_t *,uint8_t *))4223c57df7Smcpowers cbc_encrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
4323c57df7Smcpowers crypto_data_t *out, size_t block_size,
4423c57df7Smcpowers int (*encrypt)(const void *, const uint8_t *, uint8_t *),
4523c57df7Smcpowers void (*copy_block)(uint8_t *, uint8_t *),
4623c57df7Smcpowers void (*xor_block)(uint8_t *, uint8_t *))
4723c57df7Smcpowers {
4823c57df7Smcpowers size_t remainder = length;
4923c57df7Smcpowers size_t need;
5023c57df7Smcpowers uint8_t *datap = (uint8_t *)data;
5123c57df7Smcpowers uint8_t *blockp;
5223c57df7Smcpowers uint8_t *lastp;
5323c57df7Smcpowers void *iov_or_mp;
5423c57df7Smcpowers offset_t offset;
5523c57df7Smcpowers uint8_t *out_data_1;
5623c57df7Smcpowers uint8_t *out_data_2;
5723c57df7Smcpowers size_t out_data_1_len;
5823c57df7Smcpowers
59*16239bc8SMark Powers if (length + ctx->cbc_remainder_len < block_size) {
6023c57df7Smcpowers /* accumulate bytes here and return */
6123c57df7Smcpowers bcopy(datap,
62*16239bc8SMark Powers (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len,
6323c57df7Smcpowers length);
64*16239bc8SMark Powers ctx->cbc_remainder_len += length;
65*16239bc8SMark Powers ctx->cbc_copy_to = datap;
6623c57df7Smcpowers return (CRYPTO_SUCCESS);
6723c57df7Smcpowers }
6823c57df7Smcpowers
69*16239bc8SMark Powers lastp = (uint8_t *)ctx->cbc_iv;
7023c57df7Smcpowers if (out != NULL)
7123c57df7Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset);
7223c57df7Smcpowers
7323c57df7Smcpowers do {
7423c57df7Smcpowers /* Unprocessed data from last call. */
75*16239bc8SMark Powers if (ctx->cbc_remainder_len > 0) {
76*16239bc8SMark Powers need = block_size - ctx->cbc_remainder_len;
7723c57df7Smcpowers
7823c57df7Smcpowers if (need > remainder)
7923c57df7Smcpowers return (CRYPTO_DATA_LEN_RANGE);
8023c57df7Smcpowers
81*16239bc8SMark Powers bcopy(datap, &((uint8_t *)ctx->cbc_remainder)
82*16239bc8SMark Powers [ctx->cbc_remainder_len], need);
8323c57df7Smcpowers
84*16239bc8SMark Powers blockp = (uint8_t *)ctx->cbc_remainder;
8523c57df7Smcpowers } else {
8623c57df7Smcpowers blockp = datap;
8723c57df7Smcpowers }
8823c57df7Smcpowers
8923c57df7Smcpowers if (out == NULL) {
9023c57df7Smcpowers /*
9123c57df7Smcpowers * XOR the previous cipher block or IV with the
9223c57df7Smcpowers * current clear block.
9323c57df7Smcpowers */
9423c57df7Smcpowers xor_block(lastp, blockp);
95*16239bc8SMark Powers encrypt(ctx->cbc_keysched, blockp, blockp);
9623c57df7Smcpowers
97*16239bc8SMark Powers ctx->cbc_lastp = blockp;
9823c57df7Smcpowers lastp = blockp;
9923c57df7Smcpowers
100*16239bc8SMark Powers if (ctx->cbc_remainder_len > 0) {
101*16239bc8SMark Powers bcopy(blockp, ctx->cbc_copy_to,
102*16239bc8SMark Powers ctx->cbc_remainder_len);
103*16239bc8SMark Powers bcopy(blockp + ctx->cbc_remainder_len, datap,
10423c57df7Smcpowers need);
10523c57df7Smcpowers }
10623c57df7Smcpowers } else {
10723c57df7Smcpowers /*
10823c57df7Smcpowers * XOR the previous cipher block or IV with the
10923c57df7Smcpowers * current clear block.
11023c57df7Smcpowers */
11123c57df7Smcpowers xor_block(blockp, lastp);
112*16239bc8SMark Powers encrypt(ctx->cbc_keysched, lastp, lastp);
11323c57df7Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
11423c57df7Smcpowers &out_data_1_len, &out_data_2, block_size);
11523c57df7Smcpowers
11623c57df7Smcpowers /* copy block to where it belongs */
11723c57df7Smcpowers if (out_data_1_len == block_size) {
11823c57df7Smcpowers copy_block(lastp, out_data_1);
11923c57df7Smcpowers } else {
12023c57df7Smcpowers bcopy(lastp, out_data_1, out_data_1_len);
12123c57df7Smcpowers if (out_data_2 != NULL) {
12223c57df7Smcpowers bcopy(lastp + out_data_1_len,
12323c57df7Smcpowers out_data_2,
12423c57df7Smcpowers block_size - out_data_1_len);
12523c57df7Smcpowers }
12623c57df7Smcpowers }
12723c57df7Smcpowers /* update offset */
12823c57df7Smcpowers out->cd_offset += block_size;
12923c57df7Smcpowers }
13023c57df7Smcpowers
13123c57df7Smcpowers /* Update pointer to next block of data to be processed. */
132*16239bc8SMark Powers if (ctx->cbc_remainder_len != 0) {
13323c57df7Smcpowers datap += need;
134*16239bc8SMark Powers ctx->cbc_remainder_len = 0;
13523c57df7Smcpowers } else {
13623c57df7Smcpowers datap += block_size;
13723c57df7Smcpowers }
13823c57df7Smcpowers
13923c57df7Smcpowers remainder = (size_t)&data[length] - (size_t)datap;
14023c57df7Smcpowers
14123c57df7Smcpowers /* Incomplete last block. */
14223c57df7Smcpowers if (remainder > 0 && remainder < block_size) {
143*16239bc8SMark Powers bcopy(datap, ctx->cbc_remainder, remainder);
144*16239bc8SMark Powers ctx->cbc_remainder_len = remainder;
145*16239bc8SMark Powers ctx->cbc_copy_to = datap;
14623c57df7Smcpowers goto out;
14723c57df7Smcpowers }
148*16239bc8SMark Powers ctx->cbc_copy_to = NULL;
14923c57df7Smcpowers
15023c57df7Smcpowers } while (remainder > 0);
15123c57df7Smcpowers
15223c57df7Smcpowers out:
15323c57df7Smcpowers /*
15423c57df7Smcpowers * Save the last encrypted block in the context.
15523c57df7Smcpowers */
156*16239bc8SMark Powers if (ctx->cbc_lastp != NULL) {
157*16239bc8SMark Powers copy_block((uint8_t *)ctx->cbc_lastp, (uint8_t *)ctx->cbc_iv);
158*16239bc8SMark Powers ctx->cbc_lastp = (uint8_t *)ctx->cbc_iv;
15923c57df7Smcpowers }
16023c57df7Smcpowers
16123c57df7Smcpowers return (CRYPTO_SUCCESS);
16223c57df7Smcpowers }
16323c57df7Smcpowers
16423c57df7Smcpowers #define OTHER(a, ctx) \
165*16239bc8SMark Powers (((a) == (ctx)->cbc_lastblock) ? (ctx)->cbc_iv : (ctx)->cbc_lastblock)
16623c57df7Smcpowers
16723c57df7Smcpowers /* ARGSUSED */
16823c57df7Smcpowers int
cbc_decrypt_contiguous_blocks(cbc_ctx_t * ctx,char * data,size_t length,crypto_data_t * out,size_t block_size,int (* decrypt)(const void *,const uint8_t *,uint8_t *),void (* copy_block)(uint8_t *,uint8_t *),void (* xor_block)(uint8_t *,uint8_t *))16923c57df7Smcpowers cbc_decrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
17023c57df7Smcpowers crypto_data_t *out, size_t block_size,
17123c57df7Smcpowers int (*decrypt)(const void *, const uint8_t *, uint8_t *),
17223c57df7Smcpowers void (*copy_block)(uint8_t *, uint8_t *),
17323c57df7Smcpowers void (*xor_block)(uint8_t *, uint8_t *))
17423c57df7Smcpowers {
17523c57df7Smcpowers size_t remainder = length;
17623c57df7Smcpowers size_t need;
17723c57df7Smcpowers uint8_t *datap = (uint8_t *)data;
17823c57df7Smcpowers uint8_t *blockp;
17923c57df7Smcpowers uint8_t *lastp;
18023c57df7Smcpowers void *iov_or_mp;
18123c57df7Smcpowers offset_t offset;
18223c57df7Smcpowers uint8_t *out_data_1;
18323c57df7Smcpowers uint8_t *out_data_2;
18423c57df7Smcpowers size_t out_data_1_len;
18523c57df7Smcpowers
186*16239bc8SMark Powers if (length + ctx->cbc_remainder_len < block_size) {
18723c57df7Smcpowers /* accumulate bytes here and return */
18823c57df7Smcpowers bcopy(datap,
189*16239bc8SMark Powers (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len,
19023c57df7Smcpowers length);
191*16239bc8SMark Powers ctx->cbc_remainder_len += length;
192*16239bc8SMark Powers ctx->cbc_copy_to = datap;
19323c57df7Smcpowers return (CRYPTO_SUCCESS);
19423c57df7Smcpowers }
19523c57df7Smcpowers
196*16239bc8SMark Powers lastp = ctx->cbc_lastp;
19723c57df7Smcpowers if (out != NULL)
19823c57df7Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset);
19923c57df7Smcpowers
20023c57df7Smcpowers do {
20123c57df7Smcpowers /* Unprocessed data from last call. */
202*16239bc8SMark Powers if (ctx->cbc_remainder_len > 0) {
203*16239bc8SMark Powers need = block_size - ctx->cbc_remainder_len;
20423c57df7Smcpowers
20523c57df7Smcpowers if (need > remainder)
20623c57df7Smcpowers return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
20723c57df7Smcpowers
208*16239bc8SMark Powers bcopy(datap, &((uint8_t *)ctx->cbc_remainder)
209*16239bc8SMark Powers [ctx->cbc_remainder_len], need);
21023c57df7Smcpowers
211*16239bc8SMark Powers blockp = (uint8_t *)ctx->cbc_remainder;
21223c57df7Smcpowers } else {
21323c57df7Smcpowers blockp = datap;
21423c57df7Smcpowers }
21523c57df7Smcpowers
21623c57df7Smcpowers /* LINTED: pointer alignment */
21723c57df7Smcpowers copy_block(blockp, (uint8_t *)OTHER((uint64_t *)lastp, ctx));
21823c57df7Smcpowers
21923c57df7Smcpowers if (out != NULL) {
220*16239bc8SMark Powers decrypt(ctx->cbc_keysched, blockp,
221*16239bc8SMark Powers (uint8_t *)ctx->cbc_remainder);
222*16239bc8SMark Powers blockp = (uint8_t *)ctx->cbc_remainder;
22323c57df7Smcpowers } else {
224*16239bc8SMark Powers decrypt(ctx->cbc_keysched, blockp, blockp);
22523c57df7Smcpowers }
22623c57df7Smcpowers
22723c57df7Smcpowers /*
22823c57df7Smcpowers * XOR the previous cipher block or IV with the
22923c57df7Smcpowers * currently decrypted block.
23023c57df7Smcpowers */
23123c57df7Smcpowers xor_block(lastp, blockp);
23223c57df7Smcpowers
23323c57df7Smcpowers /* LINTED: pointer alignment */
23423c57df7Smcpowers lastp = (uint8_t *)OTHER((uint64_t *)lastp, ctx);
23523c57df7Smcpowers
23623c57df7Smcpowers if (out != NULL) {
23723c57df7Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
23823c57df7Smcpowers &out_data_1_len, &out_data_2, block_size);
23923c57df7Smcpowers
24023c57df7Smcpowers bcopy(blockp, out_data_1, out_data_1_len);
24123c57df7Smcpowers if (out_data_2 != NULL) {
24223c57df7Smcpowers bcopy(blockp + out_data_1_len, out_data_2,
24323c57df7Smcpowers block_size - out_data_1_len);
24423c57df7Smcpowers }
24523c57df7Smcpowers
24623c57df7Smcpowers /* update offset */
24723c57df7Smcpowers out->cd_offset += block_size;
24823c57df7Smcpowers
249*16239bc8SMark Powers } else if (ctx->cbc_remainder_len > 0) {
25023c57df7Smcpowers /* copy temporary block to where it belongs */
251*16239bc8SMark Powers bcopy(blockp, ctx->cbc_copy_to, ctx->cbc_remainder_len);
252*16239bc8SMark Powers bcopy(blockp + ctx->cbc_remainder_len, datap, need);
25323c57df7Smcpowers }
25423c57df7Smcpowers
25523c57df7Smcpowers /* Update pointer to next block of data to be processed. */
256*16239bc8SMark Powers if (ctx->cbc_remainder_len != 0) {
25723c57df7Smcpowers datap += need;
258*16239bc8SMark Powers ctx->cbc_remainder_len = 0;
25923c57df7Smcpowers } else {
26023c57df7Smcpowers datap += block_size;
26123c57df7Smcpowers }
26223c57df7Smcpowers
26323c57df7Smcpowers remainder = (size_t)&data[length] - (size_t)datap;
26423c57df7Smcpowers
26523c57df7Smcpowers /* Incomplete last block. */
26623c57df7Smcpowers if (remainder > 0 && remainder < block_size) {
267*16239bc8SMark Powers bcopy(datap, ctx->cbc_remainder, remainder);
268*16239bc8SMark Powers ctx->cbc_remainder_len = remainder;
269*16239bc8SMark Powers ctx->cbc_lastp = lastp;
270*16239bc8SMark Powers ctx->cbc_copy_to = datap;
27123c57df7Smcpowers return (CRYPTO_SUCCESS);
27223c57df7Smcpowers }
273*16239bc8SMark Powers ctx->cbc_copy_to = NULL;
27423c57df7Smcpowers
27523c57df7Smcpowers } while (remainder > 0);
27623c57df7Smcpowers
277*16239bc8SMark Powers ctx->cbc_lastp = lastp;
27823c57df7Smcpowers return (CRYPTO_SUCCESS);
27923c57df7Smcpowers }
28023c57df7Smcpowers
28123c57df7Smcpowers int
cbc_init_ctx(cbc_ctx_t * cbc_ctx,char * param,size_t param_len,size_t block_size,void (* copy_block)(uint8_t *,uint64_t *))28223c57df7Smcpowers cbc_init_ctx(cbc_ctx_t *cbc_ctx, char *param, size_t param_len,
28323c57df7Smcpowers size_t block_size, void (*copy_block)(uint8_t *, uint64_t *))
28423c57df7Smcpowers {
28523c57df7Smcpowers /*
28623c57df7Smcpowers * Copy IV into context.
28723c57df7Smcpowers *
28823c57df7Smcpowers * If cm_param == NULL then the IV comes from the
28923c57df7Smcpowers * cd_miscdata field in the crypto_data structure.
29023c57df7Smcpowers */
29123c57df7Smcpowers if (param != NULL) {
29223c57df7Smcpowers #ifdef _KERNEL
29323c57df7Smcpowers ASSERT(param_len == block_size);
29423c57df7Smcpowers #else
29523c57df7Smcpowers assert(param_len == block_size);
29623c57df7Smcpowers #endif
297*16239bc8SMark Powers copy_block((uchar_t *)param, cbc_ctx->cbc_iv);
29823c57df7Smcpowers }
29923c57df7Smcpowers
300*16239bc8SMark Powers cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0];
301*16239bc8SMark Powers cbc_ctx->cbc_flags |= CBC_MODE;
30223c57df7Smcpowers return (CRYPTO_SUCCESS);
30323c57df7Smcpowers }
30423c57df7Smcpowers
30523c57df7Smcpowers /* ARGSUSED */
30623c57df7Smcpowers void *
cbc_alloc_ctx(int kmflag)30723c57df7Smcpowers cbc_alloc_ctx(int kmflag)
30823c57df7Smcpowers {
30923c57df7Smcpowers cbc_ctx_t *cbc_ctx;
31023c57df7Smcpowers
31123c57df7Smcpowers #ifdef _KERNEL
31223c57df7Smcpowers if ((cbc_ctx = kmem_zalloc(sizeof (cbc_ctx_t), kmflag)) == NULL)
31323c57df7Smcpowers #else
31423c57df7Smcpowers if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
31523c57df7Smcpowers #endif
31623c57df7Smcpowers return (NULL);
31723c57df7Smcpowers
318*16239bc8SMark Powers cbc_ctx->cbc_flags = CBC_MODE;
31923c57df7Smcpowers return (cbc_ctx);
32023c57df7Smcpowers }
321