xref: /titanic_44/usr/src/common/crypto/modes/ctr.c (revision 16239bc82c111618343e0a5b1a70e0fc702d00e0)
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