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>
374b56a003SDaniel Anderson #include <sys/byteorder.h>
384b56a003SDaniel Anderson
3923c57df7Smcpowers /*
4023c57df7Smcpowers * Encrypt and decrypt multiple blocks of data in counter mode.
4123c57df7Smcpowers */
4223c57df7Smcpowers int
ctr_mode_contiguous_blocks(ctr_ctx_t * ctx,char * data,size_t length,crypto_data_t * out,size_t block_size,int (* cipher)(const void * ks,const uint8_t * pt,uint8_t * ct),void (* xor_block)(uint8_t *,uint8_t *))4323c57df7Smcpowers ctr_mode_contiguous_blocks(ctr_ctx_t *ctx, char *data, size_t length,
4423c57df7Smcpowers crypto_data_t *out, size_t block_size,
4523c57df7Smcpowers int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct),
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;
58*16239bc8SMark Powers uint64_t lower_counter, upper_counter;
5923c57df7Smcpowers
6023c57df7Smcpowers if (length + ctx->ctr_remainder_len < block_size) {
6123c57df7Smcpowers /* accumulate bytes here and return */
6223c57df7Smcpowers bcopy(datap,
6323c57df7Smcpowers (uint8_t *)ctx->ctr_remainder + ctx->ctr_remainder_len,
6423c57df7Smcpowers length);
6523c57df7Smcpowers ctx->ctr_remainder_len += length;
6623c57df7Smcpowers ctx->ctr_copy_to = datap;
6723c57df7Smcpowers return (CRYPTO_SUCCESS);
6823c57df7Smcpowers }
6923c57df7Smcpowers
7023c57df7Smcpowers lastp = (uint8_t *)ctx->ctr_cb;
7123c57df7Smcpowers if (out != NULL)
7223c57df7Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset);
7323c57df7Smcpowers
7423c57df7Smcpowers do {
7523c57df7Smcpowers /* Unprocessed data from last call. */
7623c57df7Smcpowers if (ctx->ctr_remainder_len > 0) {
7723c57df7Smcpowers need = block_size - ctx->ctr_remainder_len;
7823c57df7Smcpowers
7923c57df7Smcpowers if (need > remainder)
8023c57df7Smcpowers return (CRYPTO_DATA_LEN_RANGE);
8123c57df7Smcpowers
8223c57df7Smcpowers bcopy(datap, &((uint8_t *)ctx->ctr_remainder)
8323c57df7Smcpowers [ctx->ctr_remainder_len], need);
8423c57df7Smcpowers
8523c57df7Smcpowers blockp = (uint8_t *)ctx->ctr_remainder;
8623c57df7Smcpowers } else {
8723c57df7Smcpowers blockp = datap;
8823c57df7Smcpowers }
8923c57df7Smcpowers
9023c57df7Smcpowers /* ctr_cb is the counter block */
9123c57df7Smcpowers cipher(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb,
9223c57df7Smcpowers (uint8_t *)ctx->ctr_tmp);
9323c57df7Smcpowers
9423c57df7Smcpowers lastp = (uint8_t *)ctx->ctr_tmp;
9523c57df7Smcpowers
9623c57df7Smcpowers /*
97*16239bc8SMark Powers * Increment Counter.
9823c57df7Smcpowers */
99*16239bc8SMark Powers lower_counter = ntohll(ctx->ctr_cb[1] & ctx->ctr_lower_mask);
100*16239bc8SMark Powers lower_counter = htonll(lower_counter + 1);
101*16239bc8SMark Powers lower_counter &= ctx->ctr_lower_mask;
102*16239bc8SMark Powers ctx->ctr_cb[1] = (ctx->ctr_cb[1] & ~(ctx->ctr_lower_mask)) |
103*16239bc8SMark Powers lower_counter;
104*16239bc8SMark Powers
105*16239bc8SMark Powers /* wrap around */
106*16239bc8SMark Powers if (lower_counter == 0) {
107*16239bc8SMark Powers upper_counter =
108*16239bc8SMark Powers ntohll(ctx->ctr_cb[0] & ctx->ctr_upper_mask);
109*16239bc8SMark Powers upper_counter = htonll(upper_counter + 1);
110*16239bc8SMark Powers upper_counter &= ctx->ctr_upper_mask;
111*16239bc8SMark Powers ctx->ctr_cb[0] =
112*16239bc8SMark Powers (ctx->ctr_cb[0] & ~(ctx->ctr_upper_mask)) |
113*16239bc8SMark Powers upper_counter;
114*16239bc8SMark Powers }
11523c57df7Smcpowers
11623c57df7Smcpowers /*
117*16239bc8SMark Powers * XOR encrypted counter block with the current clear block.
11823c57df7Smcpowers */
11923c57df7Smcpowers xor_block(blockp, lastp);
12023c57df7Smcpowers
12123c57df7Smcpowers if (out == NULL) {
12223c57df7Smcpowers if (ctx->ctr_remainder_len > 0) {
12323c57df7Smcpowers bcopy(lastp, ctx->ctr_copy_to,
12423c57df7Smcpowers ctx->ctr_remainder_len);
12523c57df7Smcpowers bcopy(lastp + ctx->ctr_remainder_len, datap,
12623c57df7Smcpowers need);
12723c57df7Smcpowers }
12823c57df7Smcpowers } else {
12923c57df7Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
13023c57df7Smcpowers &out_data_1_len, &out_data_2, block_size);
13123c57df7Smcpowers
13223c57df7Smcpowers /* copy block to where it belongs */
13323c57df7Smcpowers bcopy(lastp, out_data_1, out_data_1_len);
13423c57df7Smcpowers if (out_data_2 != NULL) {
13523c57df7Smcpowers bcopy(lastp + out_data_1_len, out_data_2,
13623c57df7Smcpowers block_size - out_data_1_len);
13723c57df7Smcpowers }
13823c57df7Smcpowers /* update offset */
13923c57df7Smcpowers out->cd_offset += block_size;
14023c57df7Smcpowers }
14123c57df7Smcpowers
14223c57df7Smcpowers /* Update pointer to next block of data to be processed. */
14323c57df7Smcpowers if (ctx->ctr_remainder_len != 0) {
14423c57df7Smcpowers datap += need;
14523c57df7Smcpowers ctx->ctr_remainder_len = 0;
14623c57df7Smcpowers } else {
14723c57df7Smcpowers datap += block_size;
14823c57df7Smcpowers }
14923c57df7Smcpowers
15023c57df7Smcpowers remainder = (size_t)&data[length] - (size_t)datap;
15123c57df7Smcpowers
15223c57df7Smcpowers /* Incomplete last block. */
15323c57df7Smcpowers if (remainder > 0 && remainder < block_size) {
15423c57df7Smcpowers bcopy(datap, ctx->ctr_remainder, remainder);
15523c57df7Smcpowers ctx->ctr_remainder_len = remainder;
15623c57df7Smcpowers ctx->ctr_copy_to = datap;
15723c57df7Smcpowers goto out;
15823c57df7Smcpowers }
15923c57df7Smcpowers ctx->ctr_copy_to = NULL;
16023c57df7Smcpowers
16123c57df7Smcpowers } while (remainder > 0);
16223c57df7Smcpowers
16323c57df7Smcpowers out:
16423c57df7Smcpowers return (CRYPTO_SUCCESS);
16523c57df7Smcpowers }
16623c57df7Smcpowers
16723c57df7Smcpowers int
ctr_mode_final(ctr_ctx_t * ctx,crypto_data_t * out,int (* encrypt_block)(const void *,const uint8_t *,uint8_t *))16823c57df7Smcpowers ctr_mode_final(ctr_ctx_t *ctx, crypto_data_t *out,
16923c57df7Smcpowers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))
17023c57df7Smcpowers {
17123c57df7Smcpowers uint8_t *lastp;
17223c57df7Smcpowers void *iov_or_mp;
17323c57df7Smcpowers offset_t offset;
17423c57df7Smcpowers uint8_t *out_data_1;
17523c57df7Smcpowers uint8_t *out_data_2;
17623c57df7Smcpowers size_t out_data_1_len;
17723c57df7Smcpowers uint8_t *p;
17823c57df7Smcpowers int i;
17923c57df7Smcpowers
18023c57df7Smcpowers if (out->cd_length < ctx->ctr_remainder_len)
18123c57df7Smcpowers return (CRYPTO_DATA_LEN_RANGE);
18223c57df7Smcpowers
18323c57df7Smcpowers encrypt_block(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb,
18423c57df7Smcpowers (uint8_t *)ctx->ctr_tmp);
18523c57df7Smcpowers
18623c57df7Smcpowers lastp = (uint8_t *)ctx->ctr_tmp;
18723c57df7Smcpowers p = (uint8_t *)ctx->ctr_remainder;
18823c57df7Smcpowers for (i = 0; i < ctx->ctr_remainder_len; i++) {
18923c57df7Smcpowers p[i] ^= lastp[i];
19023c57df7Smcpowers }
19123c57df7Smcpowers
19223c57df7Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset);
19323c57df7Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
19423c57df7Smcpowers &out_data_1_len, &out_data_2, ctx->ctr_remainder_len);
19523c57df7Smcpowers
19623c57df7Smcpowers bcopy(p, out_data_1, out_data_1_len);
19723c57df7Smcpowers if (out_data_2 != NULL) {
19823c57df7Smcpowers bcopy((uint8_t *)p + out_data_1_len,
19923c57df7Smcpowers out_data_2, ctx->ctr_remainder_len - out_data_1_len);
20023c57df7Smcpowers }
20123c57df7Smcpowers out->cd_offset += ctx->ctr_remainder_len;
20223c57df7Smcpowers ctx->ctr_remainder_len = 0;
20323c57df7Smcpowers return (CRYPTO_SUCCESS);
20423c57df7Smcpowers }
20523c57df7Smcpowers
20623c57df7Smcpowers int
ctr_init_ctx(ctr_ctx_t * ctr_ctx,ulong_t count,uint8_t * cb,void (* copy_block)(uint8_t *,uint8_t *))20723c57df7Smcpowers ctr_init_ctx(ctr_ctx_t *ctr_ctx, ulong_t count, uint8_t *cb,
20823c57df7Smcpowers void (*copy_block)(uint8_t *, uint8_t *))
20923c57df7Smcpowers {
210*16239bc8SMark Powers uint64_t upper_mask = 0;
211*16239bc8SMark Powers uint64_t lower_mask = 0;
21223c57df7Smcpowers
213*16239bc8SMark Powers if (count == 0 || count > 128) {
21423c57df7Smcpowers return (CRYPTO_MECHANISM_PARAM_INVALID);
21523c57df7Smcpowers }
216*16239bc8SMark Powers /* upper 64 bits of the mask */
217*16239bc8SMark Powers if (count >= 64) {
218*16239bc8SMark Powers count -= 64;
219*16239bc8SMark Powers upper_mask = (count == 64) ? UINT64_MAX : (1ULL << count) - 1;
220*16239bc8SMark Powers lower_mask = UINT64_MAX;
221*16239bc8SMark Powers } else {
222*16239bc8SMark Powers /* now the lower 63 bits */
223*16239bc8SMark Powers lower_mask = (1ULL << count) - 1;
224*16239bc8SMark Powers }
225*16239bc8SMark Powers ctr_ctx->ctr_lower_mask = htonll(lower_mask);
226*16239bc8SMark Powers ctr_ctx->ctr_upper_mask = htonll(upper_mask);
2274b56a003SDaniel Anderson
22823c57df7Smcpowers copy_block(cb, (uchar_t *)ctr_ctx->ctr_cb);
22923c57df7Smcpowers ctr_ctx->ctr_lastp = (uint8_t *)&ctr_ctx->ctr_cb[0];
23023c57df7Smcpowers ctr_ctx->ctr_flags |= CTR_MODE;
23123c57df7Smcpowers return (CRYPTO_SUCCESS);
23223c57df7Smcpowers }
23323c57df7Smcpowers
23423c57df7Smcpowers /* ARGSUSED */
23523c57df7Smcpowers void *
ctr_alloc_ctx(int kmflag)23623c57df7Smcpowers ctr_alloc_ctx(int kmflag)
23723c57df7Smcpowers {
23823c57df7Smcpowers ctr_ctx_t *ctr_ctx;
23923c57df7Smcpowers
24023c57df7Smcpowers #ifdef _KERNEL
24123c57df7Smcpowers if ((ctr_ctx = kmem_zalloc(sizeof (ctr_ctx_t), kmflag)) == NULL)
24223c57df7Smcpowers #else
24323c57df7Smcpowers if ((ctr_ctx = calloc(1, sizeof (ctr_ctx_t))) == NULL)
24423c57df7Smcpowers #endif
24523c57df7Smcpowers return (NULL);
24623c57df7Smcpowers
24723c57df7Smcpowers ctr_ctx->ctr_flags = CTR_MODE;
24823c57df7Smcpowers return (ctr_ctx);
24923c57df7Smcpowers }
250