xref: /titanic_44/usr/src/common/crypto/modes/ccm.c (revision f02d27993f61b34e5e11f2258f18f8e64081034a)
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 <sys/kmem.h>
3523c57df7Smcpowers #include <modes/modes.h>
3623c57df7Smcpowers #include <sys/crypto/common.h>
3723c57df7Smcpowers #include <sys/crypto/impl.h>
3823c57df7Smcpowers 
3923c57df7Smcpowers /*
4023c57df7Smcpowers  * Encrypt multiple blocks of data in CCM mode.  Decrypt for CCM mode
4123c57df7Smcpowers  * is done in another function.
4223c57df7Smcpowers  */
4323c57df7Smcpowers int
4423c57df7Smcpowers ccm_mode_encrypt_contiguous_blocks(ccm_ctx_t *ctx, char *data, size_t length,
4523c57df7Smcpowers     crypto_data_t *out, size_t block_size,
4623c57df7Smcpowers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
4723c57df7Smcpowers     void (*copy_block)(uint8_t *, uint8_t *),
4823c57df7Smcpowers     void (*xor_block)(uint8_t *, uint8_t *))
4923c57df7Smcpowers {
5023c57df7Smcpowers 	size_t remainder = length;
5123c57df7Smcpowers 	size_t need;
5223c57df7Smcpowers 	uint8_t *datap = (uint8_t *)data;
5323c57df7Smcpowers 	uint8_t *blockp;
5423c57df7Smcpowers 	uint8_t *lastp;
5523c57df7Smcpowers 	void *iov_or_mp;
5623c57df7Smcpowers 	offset_t offset;
5723c57df7Smcpowers 	uint8_t *out_data_1;
5823c57df7Smcpowers 	uint8_t *out_data_2;
5923c57df7Smcpowers 	size_t out_data_1_len;
6023c57df7Smcpowers 	uint64_t counter;
6123c57df7Smcpowers 	uint8_t *mac_buf;
6223c57df7Smcpowers #ifdef _LITTLE_ENDIAN
6323c57df7Smcpowers 	uint8_t *p;
6423c57df7Smcpowers #endif
6523c57df7Smcpowers 
6623c57df7Smcpowers 	if (length + ctx->ccm_remainder_len < block_size) {
6723c57df7Smcpowers 		/* accumulate bytes here and return */
6823c57df7Smcpowers 		bcopy(datap,
6923c57df7Smcpowers 		    (uint8_t *)ctx->ccm_remainder + ctx->ccm_remainder_len,
7023c57df7Smcpowers 		    length);
7123c57df7Smcpowers 		ctx->ccm_remainder_len += length;
7223c57df7Smcpowers 		ctx->ccm_copy_to = datap;
7323c57df7Smcpowers 		return (CRYPTO_SUCCESS);
7423c57df7Smcpowers 	}
7523c57df7Smcpowers 
7623c57df7Smcpowers 	lastp = (uint8_t *)ctx->ccm_cb;
7723c57df7Smcpowers 	if (out != NULL)
7823c57df7Smcpowers 		crypto_init_ptrs(out, &iov_or_mp, &offset);
7923c57df7Smcpowers 
8023c57df7Smcpowers 	mac_buf = (uint8_t *)ctx->ccm_mac_buf;
8123c57df7Smcpowers 
8223c57df7Smcpowers 	do {
8323c57df7Smcpowers 		/* Unprocessed data from last call. */
8423c57df7Smcpowers 		if (ctx->ccm_remainder_len > 0) {
8523c57df7Smcpowers 			need = block_size - ctx->ccm_remainder_len;
8623c57df7Smcpowers 
8723c57df7Smcpowers 			if (need > remainder)
8823c57df7Smcpowers 				return (CRYPTO_DATA_LEN_RANGE);
8923c57df7Smcpowers 
9023c57df7Smcpowers 			bcopy(datap, &((uint8_t *)ctx->ccm_remainder)
9123c57df7Smcpowers 			    [ctx->ccm_remainder_len], need);
9223c57df7Smcpowers 
9323c57df7Smcpowers 			blockp = (uint8_t *)ctx->ccm_remainder;
9423c57df7Smcpowers 		} else {
9523c57df7Smcpowers 			blockp = datap;
9623c57df7Smcpowers 		}
9723c57df7Smcpowers 
9823c57df7Smcpowers 		/*
9923c57df7Smcpowers 		 * do CBC MAC
10023c57df7Smcpowers 		 *
10123c57df7Smcpowers 		 * XOR the previous cipher block current clear block.
10223c57df7Smcpowers 		 * mac_buf always contain previous cipher block.
10323c57df7Smcpowers 		 */
10423c57df7Smcpowers 		xor_block(blockp, mac_buf);
10523c57df7Smcpowers 		encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
10623c57df7Smcpowers 
10723c57df7Smcpowers 		/* ccm_cb is the counter block */
10823c57df7Smcpowers 		encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb,
10923c57df7Smcpowers 		    (uint8_t *)ctx->ccm_tmp);
11023c57df7Smcpowers 
11123c57df7Smcpowers 		lastp = (uint8_t *)ctx->ccm_tmp;
11223c57df7Smcpowers 
11323c57df7Smcpowers 		/*
11423c57df7Smcpowers 		 * Increment counter. Counter bits are confined
11523c57df7Smcpowers 		 * to the bottom 64 bits of the counter block.
11623c57df7Smcpowers 		 */
11723c57df7Smcpowers 		counter = ctx->ccm_cb[1] & ctx->ccm_counter_mask;
11823c57df7Smcpowers #ifdef _LITTLE_ENDIAN
11923c57df7Smcpowers 		p = (uint8_t *)&counter;
12023c57df7Smcpowers 		counter = (((uint64_t)p[0] << 56) |
12123c57df7Smcpowers 		    ((uint64_t)p[1] << 48) |
12223c57df7Smcpowers 		    ((uint64_t)p[2] << 40) |
12323c57df7Smcpowers 		    ((uint64_t)p[3] << 32) |
12423c57df7Smcpowers 		    ((uint64_t)p[4] << 24) |
12523c57df7Smcpowers 		    ((uint64_t)p[5] << 16) |
12623c57df7Smcpowers 		    ((uint64_t)p[6] << 8) |
12723c57df7Smcpowers 		    (uint64_t)p[7]);
12823c57df7Smcpowers #endif
12923c57df7Smcpowers 		counter++;
13023c57df7Smcpowers #ifdef _LITTLE_ENDIAN
13123c57df7Smcpowers 		counter = (((uint64_t)p[0] << 56) |
13223c57df7Smcpowers 		    ((uint64_t)p[1] << 48) |
13323c57df7Smcpowers 		    ((uint64_t)p[2] << 40) |
13423c57df7Smcpowers 		    ((uint64_t)p[3] << 32) |
13523c57df7Smcpowers 		    ((uint64_t)p[4] << 24) |
13623c57df7Smcpowers 		    ((uint64_t)p[5] << 16) |
13723c57df7Smcpowers 		    ((uint64_t)p[6] << 8) |
13823c57df7Smcpowers 		    (uint64_t)p[7]);
13923c57df7Smcpowers #endif
14023c57df7Smcpowers 		counter &= ctx->ccm_counter_mask;
14123c57df7Smcpowers 		ctx->ccm_cb[1] =
14223c57df7Smcpowers 		    (ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;
14323c57df7Smcpowers 
14423c57df7Smcpowers 		/*
145*f02d2799SMark Powers 		 * XOR encrypted counter block with the current clear block.
14623c57df7Smcpowers 		 */
147*f02d2799SMark Powers 		xor_block(blockp, lastp);
14823c57df7Smcpowers 
14923c57df7Smcpowers 		ctx->ccm_processed_data_len += block_size;
15023c57df7Smcpowers 
15123c57df7Smcpowers 		if (out == NULL) {
15223c57df7Smcpowers 			if (ctx->ccm_remainder_len > 0) {
15323c57df7Smcpowers 				bcopy(blockp, ctx->ccm_copy_to,
15423c57df7Smcpowers 				    ctx->ccm_remainder_len);
15523c57df7Smcpowers 				bcopy(blockp + ctx->ccm_remainder_len, datap,
15623c57df7Smcpowers 				    need);
15723c57df7Smcpowers 			}
15823c57df7Smcpowers 		} else {
15923c57df7Smcpowers 			crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
16023c57df7Smcpowers 			    &out_data_1_len, &out_data_2, block_size);
16123c57df7Smcpowers 
16223c57df7Smcpowers 			/* copy block to where it belongs */
16323c57df7Smcpowers 			if (out_data_1_len == block_size) {
16423c57df7Smcpowers 				copy_block(lastp, out_data_1);
16523c57df7Smcpowers 			} else {
16623c57df7Smcpowers 				bcopy(lastp, out_data_1, out_data_1_len);
16723c57df7Smcpowers 				if (out_data_2 != NULL) {
16823c57df7Smcpowers 					bcopy(lastp + out_data_1_len,
16923c57df7Smcpowers 					    out_data_2,
17023c57df7Smcpowers 					    block_size - out_data_1_len);
17123c57df7Smcpowers 				}
17223c57df7Smcpowers 			}
17323c57df7Smcpowers 			/* update offset */
17423c57df7Smcpowers 			out->cd_offset += block_size;
17523c57df7Smcpowers 		}
17623c57df7Smcpowers 
17723c57df7Smcpowers 		/* Update pointer to next block of data to be processed. */
17823c57df7Smcpowers 		if (ctx->ccm_remainder_len != 0) {
17923c57df7Smcpowers 			datap += need;
18023c57df7Smcpowers 			ctx->ccm_remainder_len = 0;
18123c57df7Smcpowers 		} else {
18223c57df7Smcpowers 			datap += block_size;
18323c57df7Smcpowers 		}
18423c57df7Smcpowers 
18523c57df7Smcpowers 		remainder = (size_t)&data[length] - (size_t)datap;
18623c57df7Smcpowers 
18723c57df7Smcpowers 		/* Incomplete last block. */
18823c57df7Smcpowers 		if (remainder > 0 && remainder < block_size) {
18923c57df7Smcpowers 			bcopy(datap, ctx->ccm_remainder, remainder);
19023c57df7Smcpowers 			ctx->ccm_remainder_len = remainder;
19123c57df7Smcpowers 			ctx->ccm_copy_to = datap;
19223c57df7Smcpowers 			goto out;
19323c57df7Smcpowers 		}
19423c57df7Smcpowers 		ctx->ccm_copy_to = NULL;
19523c57df7Smcpowers 
19623c57df7Smcpowers 	} while (remainder > 0);
19723c57df7Smcpowers 
19823c57df7Smcpowers out:
19923c57df7Smcpowers 	return (CRYPTO_SUCCESS);
20023c57df7Smcpowers }
20123c57df7Smcpowers 
20223c57df7Smcpowers void
20323c57df7Smcpowers calculate_ccm_mac(ccm_ctx_t *ctx, uint8_t *ccm_mac,
20423c57df7Smcpowers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))
20523c57df7Smcpowers {
20623c57df7Smcpowers 	uint64_t counter;
20723c57df7Smcpowers 	uint8_t *counterp, *mac_buf;
20823c57df7Smcpowers 	int i;
20923c57df7Smcpowers 
21023c57df7Smcpowers 	mac_buf = (uint8_t *)ctx->ccm_mac_buf;
21123c57df7Smcpowers 
21223c57df7Smcpowers 	/* first counter block start with index 0 */
21323c57df7Smcpowers 	counter = 0;
21423c57df7Smcpowers 	ctx->ccm_cb[1] = (ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;
21523c57df7Smcpowers 
21623c57df7Smcpowers 	counterp = (uint8_t *)ctx->ccm_tmp;
21723c57df7Smcpowers 	encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, counterp);
21823c57df7Smcpowers 
21923c57df7Smcpowers 	/* calculate XOR of MAC with first counter block */
22023c57df7Smcpowers 	for (i = 0; i < ctx->ccm_mac_len; i++) {
22123c57df7Smcpowers 		ccm_mac[i] = mac_buf[i] ^ counterp[i];
22223c57df7Smcpowers 	}
22323c57df7Smcpowers }
22423c57df7Smcpowers 
22523c57df7Smcpowers /* ARGSUSED */
22623c57df7Smcpowers int
22723c57df7Smcpowers ccm_encrypt_final(ccm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
22823c57df7Smcpowers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
22923c57df7Smcpowers     void (*xor_block)(uint8_t *, uint8_t *))
23023c57df7Smcpowers {
23123c57df7Smcpowers 	uint8_t *lastp, *mac_buf, *ccm_mac_p, *macp;
23223c57df7Smcpowers 	void *iov_or_mp;
23323c57df7Smcpowers 	offset_t offset;
23423c57df7Smcpowers 	uint8_t *out_data_1;
23523c57df7Smcpowers 	uint8_t *out_data_2;
23623c57df7Smcpowers 	size_t out_data_1_len;
23723c57df7Smcpowers 	int i;
23823c57df7Smcpowers 
23923c57df7Smcpowers 	if (out->cd_length < (ctx->ccm_remainder_len + ctx->ccm_mac_len)) {
24023c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
24123c57df7Smcpowers 	}
24223c57df7Smcpowers 
24323c57df7Smcpowers 	/*
24423c57df7Smcpowers 	 * When we get here, the number of bytes of payload processed
24523c57df7Smcpowers 	 * plus whatever data remains, if any,
24623c57df7Smcpowers 	 * should be the same as the number of bytes that's being
24723c57df7Smcpowers 	 * passed in the argument during init time.
24823c57df7Smcpowers 	 */
24923c57df7Smcpowers 	if ((ctx->ccm_processed_data_len + ctx->ccm_remainder_len)
25023c57df7Smcpowers 	    != (ctx->ccm_data_len)) {
25123c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
25223c57df7Smcpowers 	}
25323c57df7Smcpowers 
25423c57df7Smcpowers 	mac_buf = (uint8_t *)ctx->ccm_mac_buf;
25523c57df7Smcpowers 
25623c57df7Smcpowers 	if (ctx->ccm_remainder_len > 0) {
25723c57df7Smcpowers 
25823c57df7Smcpowers 		/* ccm_mac_input_buf is not used for encryption */
25923c57df7Smcpowers 		macp = (uint8_t *)ctx->ccm_mac_input_buf;
26023c57df7Smcpowers 		bzero(macp, block_size);
26123c57df7Smcpowers 
26223c57df7Smcpowers 		/* copy remainder to temporary buffer */
26323c57df7Smcpowers 		bcopy(ctx->ccm_remainder, macp, ctx->ccm_remainder_len);
26423c57df7Smcpowers 
26523c57df7Smcpowers 		/* calculate the CBC MAC */
26623c57df7Smcpowers 		xor_block(macp, mac_buf);
26723c57df7Smcpowers 		encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
26823c57df7Smcpowers 
26923c57df7Smcpowers 		/* calculate the counter mode */
27023c57df7Smcpowers 		lastp = (uint8_t *)ctx->ccm_tmp;
27123c57df7Smcpowers 		encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, lastp);
27223c57df7Smcpowers 
27323c57df7Smcpowers 		/* XOR with counter block */
27423c57df7Smcpowers 		for (i = 0; i < ctx->ccm_remainder_len; i++) {
27523c57df7Smcpowers 			macp[i] ^= lastp[i];
27623c57df7Smcpowers 		}
27723c57df7Smcpowers 		ctx->ccm_processed_data_len += ctx->ccm_remainder_len;
27823c57df7Smcpowers 	}
27923c57df7Smcpowers 
28023c57df7Smcpowers 	/* Calculate the CCM MAC */
28123c57df7Smcpowers 	ccm_mac_p = (uint8_t *)ctx->ccm_tmp;
28223c57df7Smcpowers 	calculate_ccm_mac(ctx, ccm_mac_p, encrypt_block);
28323c57df7Smcpowers 
28423c57df7Smcpowers 	crypto_init_ptrs(out, &iov_or_mp, &offset);
28523c57df7Smcpowers 	crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
28623c57df7Smcpowers 	    &out_data_1_len, &out_data_2,
28723c57df7Smcpowers 	    ctx->ccm_remainder_len + ctx->ccm_mac_len);
28823c57df7Smcpowers 
28923c57df7Smcpowers 	if (ctx->ccm_remainder_len > 0) {
29023c57df7Smcpowers 
29123c57df7Smcpowers 		/* copy temporary block to where it belongs */
29223c57df7Smcpowers 		if (out_data_2 == NULL) {
29323c57df7Smcpowers 			/* everything will fit in out_data_1 */
29423c57df7Smcpowers 			bcopy(macp, out_data_1, ctx->ccm_remainder_len);
29523c57df7Smcpowers 			bcopy(ccm_mac_p, out_data_1 + ctx->ccm_remainder_len,
29623c57df7Smcpowers 			    ctx->ccm_mac_len);
29723c57df7Smcpowers 		} else {
29823c57df7Smcpowers 
29923c57df7Smcpowers 			if (out_data_1_len < ctx->ccm_remainder_len) {
30023c57df7Smcpowers 
30123c57df7Smcpowers 				size_t data_2_len_used;
30223c57df7Smcpowers 
30323c57df7Smcpowers 				bcopy(macp, out_data_1, out_data_1_len);
30423c57df7Smcpowers 
30523c57df7Smcpowers 				data_2_len_used = ctx->ccm_remainder_len
30623c57df7Smcpowers 				    - out_data_1_len;
30723c57df7Smcpowers 
30823c57df7Smcpowers 				bcopy((uint8_t *)macp + out_data_1_len,
30923c57df7Smcpowers 				    out_data_2, data_2_len_used);
31023c57df7Smcpowers 				bcopy(ccm_mac_p, out_data_2 + data_2_len_used,
31123c57df7Smcpowers 				    ctx->ccm_mac_len);
31223c57df7Smcpowers 			} else {
31323c57df7Smcpowers 				bcopy(macp, out_data_1, out_data_1_len);
31423c57df7Smcpowers 				if (out_data_1_len == ctx->ccm_remainder_len) {
31523c57df7Smcpowers 					/* mac will be in out_data_2 */
31623c57df7Smcpowers 					bcopy(ccm_mac_p, out_data_2,
31723c57df7Smcpowers 					    ctx->ccm_mac_len);
31823c57df7Smcpowers 				} else {
31923c57df7Smcpowers 					size_t len_not_used
32023c57df7Smcpowers 					    = out_data_1_len -
32123c57df7Smcpowers 					    ctx->ccm_remainder_len;
32223c57df7Smcpowers 					/*
32323c57df7Smcpowers 					 * part of mac in will be in
32423c57df7Smcpowers 					 * out_data_1, part of the mac will be
32523c57df7Smcpowers 					 * in out_data_2
32623c57df7Smcpowers 					 */
32723c57df7Smcpowers 					bcopy(ccm_mac_p,
32823c57df7Smcpowers 					    out_data_1 + ctx->ccm_remainder_len,
32923c57df7Smcpowers 					    len_not_used);
33023c57df7Smcpowers 					bcopy(ccm_mac_p + len_not_used,
33123c57df7Smcpowers 					    out_data_2,
33223c57df7Smcpowers 					    ctx->ccm_mac_len - len_not_used);
33323c57df7Smcpowers 
33423c57df7Smcpowers 				}
33523c57df7Smcpowers 			}
33623c57df7Smcpowers 		}
33723c57df7Smcpowers 	} else {
33823c57df7Smcpowers 		/* copy block to where it belongs */
33923c57df7Smcpowers 		bcopy(ccm_mac_p, out_data_1, out_data_1_len);
34023c57df7Smcpowers 		if (out_data_2 != NULL) {
34123c57df7Smcpowers 			bcopy(ccm_mac_p + out_data_1_len, out_data_2,
34223c57df7Smcpowers 			    block_size - out_data_1_len);
34323c57df7Smcpowers 		}
34423c57df7Smcpowers 	}
34523c57df7Smcpowers 	out->cd_offset += ctx->ccm_remainder_len + ctx->ccm_mac_len;
34623c57df7Smcpowers 	ctx->ccm_remainder_len = 0;
34723c57df7Smcpowers 	return (CRYPTO_SUCCESS);
34823c57df7Smcpowers }
34923c57df7Smcpowers 
35023c57df7Smcpowers /*
35123c57df7Smcpowers  * This will only deal with decrypting the last block of the input that
35223c57df7Smcpowers  * might not be a multiple of block length.
35323c57df7Smcpowers  */
35423c57df7Smcpowers void
35523c57df7Smcpowers ccm_decrypt_incomplete_block(ccm_ctx_t *ctx,
35623c57df7Smcpowers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))
35723c57df7Smcpowers {
35823c57df7Smcpowers 	uint8_t *datap, *outp, *counterp;
35923c57df7Smcpowers 	int i;
36023c57df7Smcpowers 
36123c57df7Smcpowers 	datap = (uint8_t *)ctx->ccm_remainder;
36223c57df7Smcpowers 	outp = &((ctx->ccm_pt_buf)[ctx->ccm_processed_data_len]);
36323c57df7Smcpowers 
36423c57df7Smcpowers 	counterp = (uint8_t *)ctx->ccm_tmp;
36523c57df7Smcpowers 	encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, counterp);
36623c57df7Smcpowers 
36723c57df7Smcpowers 	/* XOR with counter block */
36823c57df7Smcpowers 	for (i = 0; i < ctx->ccm_remainder_len; i++) {
36923c57df7Smcpowers 		outp[i] = datap[i] ^ counterp[i];
37023c57df7Smcpowers 	}
37123c57df7Smcpowers }
37223c57df7Smcpowers 
37323c57df7Smcpowers /*
37423c57df7Smcpowers  * This will decrypt the cipher text.  However, the plaintext won't be
37523c57df7Smcpowers  * returned to the caller.  It will be returned when decrypt_final() is
37623c57df7Smcpowers  * called if the MAC matches
37723c57df7Smcpowers  */
37823c57df7Smcpowers /* ARGSUSED */
37923c57df7Smcpowers int
38023c57df7Smcpowers ccm_mode_decrypt_contiguous_blocks(ccm_ctx_t *ctx, char *data, size_t length,
38123c57df7Smcpowers     crypto_data_t *out, size_t block_size,
38223c57df7Smcpowers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
38323c57df7Smcpowers     void (*copy_block)(uint8_t *, uint8_t *),
38423c57df7Smcpowers     void (*xor_block)(uint8_t *, uint8_t *))
38523c57df7Smcpowers {
38623c57df7Smcpowers 	size_t remainder = length;
38723c57df7Smcpowers 	size_t need;
38823c57df7Smcpowers 	uint8_t *datap = (uint8_t *)data;
38923c57df7Smcpowers 	uint8_t *blockp;
39023c57df7Smcpowers 	uint8_t *cbp;
39123c57df7Smcpowers 	uint64_t counter;
39223c57df7Smcpowers 	size_t pt_len, total_decrypted_len, mac_len, pm_len, pd_len;
39323c57df7Smcpowers 	uint8_t *resultp;
39423c57df7Smcpowers #ifdef _LITTLE_ENDIAN
39523c57df7Smcpowers 	uint8_t *p;
39623c57df7Smcpowers #endif	/* _LITTLE_ENDIAN */
39723c57df7Smcpowers 
39823c57df7Smcpowers 
39923c57df7Smcpowers 	pm_len = ctx->ccm_processed_mac_len;
40023c57df7Smcpowers 
40123c57df7Smcpowers 	if (pm_len > 0) {
40223c57df7Smcpowers 		uint8_t *tmp;
40323c57df7Smcpowers 		/*
40423c57df7Smcpowers 		 * all ciphertext has been processed, just waiting for
40523c57df7Smcpowers 		 * part of the value of the mac
40623c57df7Smcpowers 		 */
40723c57df7Smcpowers 		if ((pm_len + length) > ctx->ccm_mac_len) {
40823c57df7Smcpowers 			return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
40923c57df7Smcpowers 		}
41023c57df7Smcpowers 		tmp = (uint8_t *)ctx->ccm_mac_input_buf;
41123c57df7Smcpowers 
41223c57df7Smcpowers 		bcopy(datap, tmp + pm_len, length);
41323c57df7Smcpowers 
41423c57df7Smcpowers 		ctx->ccm_processed_mac_len += length;
41523c57df7Smcpowers 		return (CRYPTO_SUCCESS);
41623c57df7Smcpowers 	}
41723c57df7Smcpowers 
41823c57df7Smcpowers 	/*
41923c57df7Smcpowers 	 * If we decrypt the given data, what total amount of data would
42023c57df7Smcpowers 	 * have been decrypted?
42123c57df7Smcpowers 	 */
42223c57df7Smcpowers 	pd_len = ctx->ccm_processed_data_len;
42323c57df7Smcpowers 	total_decrypted_len = pd_len + length + ctx->ccm_remainder_len;
42423c57df7Smcpowers 
42523c57df7Smcpowers 	if (total_decrypted_len >
42623c57df7Smcpowers 	    (ctx->ccm_data_len + ctx->ccm_mac_len)) {
42723c57df7Smcpowers 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
42823c57df7Smcpowers 	}
42923c57df7Smcpowers 
43023c57df7Smcpowers 	pt_len = ctx->ccm_data_len;
43123c57df7Smcpowers 
43223c57df7Smcpowers 	if (total_decrypted_len > pt_len) {
43323c57df7Smcpowers 		/*
43423c57df7Smcpowers 		 * part of the input will be the MAC, need to isolate that
43523c57df7Smcpowers 		 * to be dealt with later.  The left-over data in
43623c57df7Smcpowers 		 * ccm_remainder_len from last time will not be part of the
43723c57df7Smcpowers 		 * MAC.  Otherwise, it would have already been taken out
43823c57df7Smcpowers 		 * when this call is made last time.
43923c57df7Smcpowers 		 */
44023c57df7Smcpowers 		size_t pt_part = pt_len - pd_len - ctx->ccm_remainder_len;
44123c57df7Smcpowers 
44223c57df7Smcpowers 		mac_len = length - pt_part;
44323c57df7Smcpowers 
44423c57df7Smcpowers 		ctx->ccm_processed_mac_len = mac_len;
44523c57df7Smcpowers 		bcopy(data + pt_part, ctx->ccm_mac_input_buf, mac_len);
44623c57df7Smcpowers 
44723c57df7Smcpowers 		if (pt_part + ctx->ccm_remainder_len < block_size) {
44823c57df7Smcpowers 			/*
44923c57df7Smcpowers 			 * since this is last of the ciphertext, will
45023c57df7Smcpowers 			 * just decrypt with it here
45123c57df7Smcpowers 			 */
45223c57df7Smcpowers 			bcopy(datap, &((uint8_t *)ctx->ccm_remainder)
45323c57df7Smcpowers 			    [ctx->ccm_remainder_len], pt_part);
45423c57df7Smcpowers 			ctx->ccm_remainder_len += pt_part;
45523c57df7Smcpowers 			ccm_decrypt_incomplete_block(ctx, encrypt_block);
45623c57df7Smcpowers 			ctx->ccm_remainder_len = 0;
45723c57df7Smcpowers 			ctx->ccm_processed_data_len += pt_part;
45823c57df7Smcpowers 			return (CRYPTO_SUCCESS);
45923c57df7Smcpowers 		} else {
46023c57df7Smcpowers 			/* let rest of the code handle this */
46123c57df7Smcpowers 			length = pt_part;
46223c57df7Smcpowers 		}
46323c57df7Smcpowers 	} else if (length + ctx->ccm_remainder_len < block_size) {
46423c57df7Smcpowers 			/* accumulate bytes here and return */
46523c57df7Smcpowers 		bcopy(datap,
46623c57df7Smcpowers 		    (uint8_t *)ctx->ccm_remainder + ctx->ccm_remainder_len,
46723c57df7Smcpowers 		    length);
46823c57df7Smcpowers 		ctx->ccm_remainder_len += length;
46923c57df7Smcpowers 		ctx->ccm_copy_to = datap;
47023c57df7Smcpowers 		return (CRYPTO_SUCCESS);
47123c57df7Smcpowers 	}
47223c57df7Smcpowers 
47323c57df7Smcpowers 	do {
47423c57df7Smcpowers 		/* Unprocessed data from last call. */
47523c57df7Smcpowers 		if (ctx->ccm_remainder_len > 0) {
47623c57df7Smcpowers 			need = block_size - ctx->ccm_remainder_len;
47723c57df7Smcpowers 
47823c57df7Smcpowers 			if (need > remainder)
47923c57df7Smcpowers 				return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
48023c57df7Smcpowers 
48123c57df7Smcpowers 			bcopy(datap, &((uint8_t *)ctx->ccm_remainder)
48223c57df7Smcpowers 			    [ctx->ccm_remainder_len], need);
48323c57df7Smcpowers 
48423c57df7Smcpowers 			blockp = (uint8_t *)ctx->ccm_remainder;
48523c57df7Smcpowers 		} else {
48623c57df7Smcpowers 			blockp = datap;
48723c57df7Smcpowers 		}
48823c57df7Smcpowers 
48923c57df7Smcpowers 		/* Calculate the counter mode, ccm_cb is the counter block */
49023c57df7Smcpowers 		cbp = (uint8_t *)ctx->ccm_tmp;
49123c57df7Smcpowers 		encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, cbp);
49223c57df7Smcpowers 
49323c57df7Smcpowers 		/*
49423c57df7Smcpowers 		 * Increment counter.
49523c57df7Smcpowers 		 * Counter bits are confined to the bottom 64 bits
49623c57df7Smcpowers 		 */
49723c57df7Smcpowers 		counter = ctx->ccm_cb[1] & ctx->ccm_counter_mask;
49823c57df7Smcpowers #ifdef _LITTLE_ENDIAN
49923c57df7Smcpowers 		p = (uint8_t *)&counter;
50023c57df7Smcpowers 		counter = (((uint64_t)p[0] << 56) |
50123c57df7Smcpowers 		    ((uint64_t)p[1] << 48) |
50223c57df7Smcpowers 		    ((uint64_t)p[2] << 40) |
50323c57df7Smcpowers 		    ((uint64_t)p[3] << 32) |
50423c57df7Smcpowers 		    ((uint64_t)p[4] << 24) |
50523c57df7Smcpowers 		    ((uint64_t)p[5] << 16) |
50623c57df7Smcpowers 		    ((uint64_t)p[6] << 8) |
50723c57df7Smcpowers 		    (uint64_t)p[7]);
50823c57df7Smcpowers #endif
50923c57df7Smcpowers 		counter++;
51023c57df7Smcpowers #ifdef _LITTLE_ENDIAN
51123c57df7Smcpowers 		counter = (((uint64_t)p[0] << 56) |
51223c57df7Smcpowers 		    ((uint64_t)p[1] << 48) |
51323c57df7Smcpowers 		    ((uint64_t)p[2] << 40) |
51423c57df7Smcpowers 		    ((uint64_t)p[3] << 32) |
51523c57df7Smcpowers 		    ((uint64_t)p[4] << 24) |
51623c57df7Smcpowers 		    ((uint64_t)p[5] << 16) |
51723c57df7Smcpowers 		    ((uint64_t)p[6] << 8) |
51823c57df7Smcpowers 		    (uint64_t)p[7]);
51923c57df7Smcpowers #endif
52023c57df7Smcpowers 		counter &= ctx->ccm_counter_mask;
52123c57df7Smcpowers 		ctx->ccm_cb[1] =
52223c57df7Smcpowers 		    (ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;
52323c57df7Smcpowers 
52423c57df7Smcpowers 		/* XOR with the ciphertext */
52523c57df7Smcpowers 		xor_block(blockp, cbp);
52623c57df7Smcpowers 
52723c57df7Smcpowers 		/* Copy the plaintext to the "holding buffer" */
52823c57df7Smcpowers 		resultp = (uint8_t *)ctx->ccm_pt_buf +
52923c57df7Smcpowers 		    ctx->ccm_processed_data_len;
53023c57df7Smcpowers 		copy_block(cbp, resultp);
53123c57df7Smcpowers 
53223c57df7Smcpowers 		ctx->ccm_processed_data_len += block_size;
53323c57df7Smcpowers 
53423c57df7Smcpowers 		ctx->ccm_lastp = blockp;
53523c57df7Smcpowers 
53623c57df7Smcpowers 		/* Update pointer to next block of data to be processed. */
53723c57df7Smcpowers 		if (ctx->ccm_remainder_len != 0) {
53823c57df7Smcpowers 			datap += need;
53923c57df7Smcpowers 			ctx->ccm_remainder_len = 0;
54023c57df7Smcpowers 		} else {
54123c57df7Smcpowers 			datap += block_size;
54223c57df7Smcpowers 		}
54323c57df7Smcpowers 
54423c57df7Smcpowers 		remainder = (size_t)&data[length] - (size_t)datap;
54523c57df7Smcpowers 
54623c57df7Smcpowers 		/* Incomplete last block */
54723c57df7Smcpowers 		if (remainder > 0 && remainder < block_size) {
54823c57df7Smcpowers 			bcopy(datap, ctx->ccm_remainder, remainder);
54923c57df7Smcpowers 			ctx->ccm_remainder_len = remainder;
55023c57df7Smcpowers 			ctx->ccm_copy_to = datap;
55123c57df7Smcpowers 			if (ctx->ccm_processed_mac_len > 0) {
55223c57df7Smcpowers 				/*
55323c57df7Smcpowers 				 * not expecting anymore ciphertext, just
55423c57df7Smcpowers 				 * compute plaintext for the remaining input
55523c57df7Smcpowers 				 */
55623c57df7Smcpowers 				ccm_decrypt_incomplete_block(ctx,
55723c57df7Smcpowers 				    encrypt_block);
55823c57df7Smcpowers 				ctx->ccm_processed_data_len += remainder;
55923c57df7Smcpowers 				ctx->ccm_remainder_len = 0;
56023c57df7Smcpowers 			}
56123c57df7Smcpowers 			goto out;
56223c57df7Smcpowers 		}
56323c57df7Smcpowers 		ctx->ccm_copy_to = NULL;
56423c57df7Smcpowers 
56523c57df7Smcpowers 	} while (remainder > 0);
56623c57df7Smcpowers 
56723c57df7Smcpowers out:
56823c57df7Smcpowers 	return (CRYPTO_SUCCESS);
56923c57df7Smcpowers }
57023c57df7Smcpowers 
57123c57df7Smcpowers int
57223c57df7Smcpowers ccm_decrypt_final(ccm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
57323c57df7Smcpowers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
57423c57df7Smcpowers     void (*copy_block)(uint8_t *, uint8_t *),
57523c57df7Smcpowers     void (*xor_block)(uint8_t *, uint8_t *))
57623c57df7Smcpowers {
57723c57df7Smcpowers 	size_t mac_remain, pt_len;
57823c57df7Smcpowers 	uint8_t *pt, *mac_buf, *macp, *ccm_mac_p;
57923c57df7Smcpowers 	void *iov_or_mp;
58023c57df7Smcpowers 	offset_t offset;
58123c57df7Smcpowers 	uint8_t *out_data_1, *out_data_2;
58223c57df7Smcpowers 	size_t out_data_1_len;
58323c57df7Smcpowers 
58423c57df7Smcpowers 	pt_len = ctx->ccm_data_len;
58523c57df7Smcpowers 
58623c57df7Smcpowers 	/* Make sure output buffer can fit all of the plaintext */
58723c57df7Smcpowers 	if (out->cd_length < pt_len) {
58823c57df7Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
58923c57df7Smcpowers 	}
59023c57df7Smcpowers 
59123c57df7Smcpowers 	pt = ctx->ccm_pt_buf;
59223c57df7Smcpowers 	mac_remain = ctx->ccm_processed_data_len;
59323c57df7Smcpowers 	mac_buf = (uint8_t *)ctx->ccm_mac_buf;
59423c57df7Smcpowers 
59523c57df7Smcpowers 	macp = (uint8_t *)ctx->ccm_tmp;
59623c57df7Smcpowers 
59723c57df7Smcpowers 	while (mac_remain > 0) {
59823c57df7Smcpowers 
59923c57df7Smcpowers 		if (mac_remain < block_size) {
60023c57df7Smcpowers 			bzero(macp, block_size);
60123c57df7Smcpowers 			bcopy(pt, macp, mac_remain);
60223c57df7Smcpowers 			mac_remain = 0;
60323c57df7Smcpowers 		} else {
60423c57df7Smcpowers 			copy_block(pt, macp);
60523c57df7Smcpowers 			mac_remain -= block_size;
60623c57df7Smcpowers 			pt += block_size;
60723c57df7Smcpowers 		}
60823c57df7Smcpowers 
60923c57df7Smcpowers 		/* calculate the CBC MAC */
61023c57df7Smcpowers 		xor_block(macp, mac_buf);
61123c57df7Smcpowers 		encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
61223c57df7Smcpowers 	}
61323c57df7Smcpowers 
61423c57df7Smcpowers 	/* Calculate the CCM MAC */
61523c57df7Smcpowers 	ccm_mac_p = (uint8_t *)ctx->ccm_tmp;
61623c57df7Smcpowers 	calculate_ccm_mac((ccm_ctx_t *)ctx, ccm_mac_p, encrypt_block);
61723c57df7Smcpowers 
61823c57df7Smcpowers 	/* compare the input CCM MAC value with what we calculated */
61923c57df7Smcpowers 	if (bcmp(ctx->ccm_mac_input_buf, ccm_mac_p, ctx->ccm_mac_len)) {
62023c57df7Smcpowers 		/* They don't match */
62123c57df7Smcpowers 		return (CRYPTO_INVALID_MAC);
62223c57df7Smcpowers 	} else {
62323c57df7Smcpowers 		crypto_init_ptrs(out, &iov_or_mp, &offset);
62423c57df7Smcpowers 		crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
62523c57df7Smcpowers 		    &out_data_1_len, &out_data_2, pt_len);
62623c57df7Smcpowers 		bcopy(ctx->ccm_pt_buf, out_data_1, out_data_1_len);
62723c57df7Smcpowers 		if (out_data_2 != NULL) {
62823c57df7Smcpowers 			bcopy((ctx->ccm_pt_buf) + out_data_1_len,
62923c57df7Smcpowers 			    out_data_2, pt_len - out_data_1_len);
63023c57df7Smcpowers 		}
63123c57df7Smcpowers 		out->cd_offset += pt_len;
63223c57df7Smcpowers 	}
63323c57df7Smcpowers 	return (CRYPTO_SUCCESS);
63423c57df7Smcpowers }
63523c57df7Smcpowers 
63623c57df7Smcpowers int
63723c57df7Smcpowers ccm_validate_args(CK_AES_CCM_PARAMS *ccm_param, boolean_t is_encrypt_init)
63823c57df7Smcpowers {
63923c57df7Smcpowers 	size_t macSize, nonceSize;
64023c57df7Smcpowers 	uint8_t q;
64123c57df7Smcpowers 	uint64_t maxValue;
64223c57df7Smcpowers 
64323c57df7Smcpowers 	/*
64423c57df7Smcpowers 	 * Check the length of the MAC.  The only valid
64523c57df7Smcpowers 	 * lengths for the MAC are: 4, 6, 8, 10, 12, 14, 16
64623c57df7Smcpowers 	 */
64723c57df7Smcpowers 	macSize = ccm_param->ulMACSize;
64823c57df7Smcpowers 	if ((macSize < 4) || (macSize > 16) || ((macSize % 2) != 0)) {
64923c57df7Smcpowers 		return (CRYPTO_MECHANISM_PARAM_INVALID);
65023c57df7Smcpowers 	}
65123c57df7Smcpowers 
65223c57df7Smcpowers 	/* Check the nonce length.  Valid values are 7, 8, 9, 10, 11, 12, 13 */
65323c57df7Smcpowers 	nonceSize = ccm_param->ulNonceSize;
65423c57df7Smcpowers 	if ((nonceSize < 7) || (nonceSize > 13)) {
65523c57df7Smcpowers 		return (CRYPTO_MECHANISM_PARAM_INVALID);
65623c57df7Smcpowers 	}
65723c57df7Smcpowers 
65823c57df7Smcpowers 	/* q is the length of the field storing the length, in bytes */
65923c57df7Smcpowers 	q = (uint8_t)((15 - nonceSize) & 0xFF);
66023c57df7Smcpowers 
66123c57df7Smcpowers 
66223c57df7Smcpowers 	/*
66323c57df7Smcpowers 	 * If it is decrypt, need to make sure size of ciphertext is at least
66423c57df7Smcpowers 	 * bigger than MAC len
66523c57df7Smcpowers 	 */
66623c57df7Smcpowers 	if ((!is_encrypt_init) && (ccm_param->ulDataSize < macSize)) {
66723c57df7Smcpowers 		return (CRYPTO_MECHANISM_PARAM_INVALID);
66823c57df7Smcpowers 	}
66923c57df7Smcpowers 
67023c57df7Smcpowers 	/*
67123c57df7Smcpowers 	 * Check to make sure the length of the payload is within the
67223c57df7Smcpowers 	 * range of values allowed by q
67323c57df7Smcpowers 	 */
67423c57df7Smcpowers 	if (q < 8) {
67523c57df7Smcpowers 		maxValue = (1ULL << (q * 8)) - 1;
67623c57df7Smcpowers 	} else {
67723c57df7Smcpowers 		maxValue = ULONG_MAX;
67823c57df7Smcpowers 	}
67923c57df7Smcpowers 
68023c57df7Smcpowers 	if (ccm_param->ulDataSize > maxValue) {
68123c57df7Smcpowers 		return (CRYPTO_MECHANISM_PARAM_INVALID);
68223c57df7Smcpowers 	}
68323c57df7Smcpowers 	return (CRYPTO_SUCCESS);
68423c57df7Smcpowers }
68523c57df7Smcpowers 
68623c57df7Smcpowers /*
68723c57df7Smcpowers  * Format the first block used in CBC-MAC (B0) and the initial counter
68823c57df7Smcpowers  * block based on formatting functions and counter generation functions
68923c57df7Smcpowers  * specified in RFC 3610 and NIST publication 800-38C, appendix A
69023c57df7Smcpowers  *
69123c57df7Smcpowers  * b0 is the first block used in CBC-MAC
69223c57df7Smcpowers  * cb0 is the first counter block
69323c57df7Smcpowers  *
69423c57df7Smcpowers  * It's assumed that the arguments b0 and cb0 are preallocated AES blocks
69523c57df7Smcpowers  *
69623c57df7Smcpowers  */
69723c57df7Smcpowers static void
69823c57df7Smcpowers ccm_format_initial_blocks(uchar_t *nonce, ulong_t nonceSize,
69923c57df7Smcpowers     ulong_t authDataSize, uint8_t *b0, ccm_ctx_t *aes_ctx)
70023c57df7Smcpowers {
70123c57df7Smcpowers 	uint64_t payloadSize;
70223c57df7Smcpowers 	uint8_t t, q, have_adata = 0;
70323c57df7Smcpowers 	size_t limit;
70423c57df7Smcpowers 	int i, j, k;
70523c57df7Smcpowers 	uint64_t mask = 0;
70623c57df7Smcpowers 	uint8_t *cb;
70723c57df7Smcpowers #ifdef _LITTLE_ENDIAN
70823c57df7Smcpowers 	uint8_t *p8;
70923c57df7Smcpowers #endif	/* _LITTLE_ENDIAN */
71023c57df7Smcpowers 
71123c57df7Smcpowers 	q = (uint8_t)((15 - nonceSize) & 0xFF);
71223c57df7Smcpowers 	t = (uint8_t)((aes_ctx->ccm_mac_len) & 0xFF);
71323c57df7Smcpowers 
71423c57df7Smcpowers 	/* Construct the first octet of b0 */
71523c57df7Smcpowers 	if (authDataSize > 0) {
71623c57df7Smcpowers 		have_adata = 1;
71723c57df7Smcpowers 	}
71823c57df7Smcpowers 	b0[0] = (have_adata << 6) | (((t - 2)  / 2) << 3) | (q - 1);
71923c57df7Smcpowers 
72023c57df7Smcpowers 	/* copy the nonce value into b0 */
72123c57df7Smcpowers 	bcopy(nonce, &(b0[1]), nonceSize);
72223c57df7Smcpowers 
72323c57df7Smcpowers 	/* store the length of the payload into b0 */
72423c57df7Smcpowers 	bzero(&(b0[1+nonceSize]), q);
72523c57df7Smcpowers 
72623c57df7Smcpowers 	payloadSize = aes_ctx->ccm_data_len;
72723c57df7Smcpowers 	limit = 8 < q ? 8 : q;
72823c57df7Smcpowers 
72923c57df7Smcpowers 	for (i = 0, j = 0, k = 15; i < limit; i++, j += 8, k--) {
73023c57df7Smcpowers 		b0[k] = (uint8_t)((payloadSize >> j) & 0xFF);
73123c57df7Smcpowers 	}
73223c57df7Smcpowers 
73323c57df7Smcpowers 	/* format the counter block */
73423c57df7Smcpowers 
73523c57df7Smcpowers 	cb = (uint8_t *)aes_ctx->ccm_cb;
73623c57df7Smcpowers 
73723c57df7Smcpowers 	cb[0] = 0x07 & (q-1); /* first byte */
73823c57df7Smcpowers 
73923c57df7Smcpowers 	/* copy the nonce value into the counter block */
74023c57df7Smcpowers 	bcopy(nonce, &(cb[1]), nonceSize);
74123c57df7Smcpowers 
74223c57df7Smcpowers 	bzero(&(cb[1+nonceSize]), q);
74323c57df7Smcpowers 
74423c57df7Smcpowers 	/* Create the mask for the counter field based on the size of nonce */
74523c57df7Smcpowers 	q <<= 3;
74623c57df7Smcpowers 	while (q-- > 0) {
74723c57df7Smcpowers 		mask |= (1ULL << q);
74823c57df7Smcpowers 	}
74923c57df7Smcpowers 
75023c57df7Smcpowers #ifdef _LITTLE_ENDIAN
75123c57df7Smcpowers 	p8 = (uint8_t *)&mask;
75223c57df7Smcpowers 	mask = (((uint64_t)p8[0] << 56) |
75323c57df7Smcpowers 	    ((uint64_t)p8[1] << 48) |
75423c57df7Smcpowers 	    ((uint64_t)p8[2] << 40) |
75523c57df7Smcpowers 	    ((uint64_t)p8[3] << 32) |
75623c57df7Smcpowers 	    ((uint64_t)p8[4] << 24) |
75723c57df7Smcpowers 	    ((uint64_t)p8[5] << 16) |
75823c57df7Smcpowers 	    ((uint64_t)p8[6] << 8) |
75923c57df7Smcpowers 	    (uint64_t)p8[7]);
76023c57df7Smcpowers #endif
76123c57df7Smcpowers 	aes_ctx->ccm_counter_mask = mask;
76223c57df7Smcpowers 
76323c57df7Smcpowers 	/*
76423c57df7Smcpowers 	 * During calculation, we start using counter block 1, we will
76523c57df7Smcpowers 	 * set it up right here.
76623c57df7Smcpowers 	 * We can just set the last byte to have the value 1, because
76723c57df7Smcpowers 	 * even with the biggest nonce of 13, the last byte of the
76823c57df7Smcpowers 	 * counter block will be used for the counter value.
76923c57df7Smcpowers 	 */
77023c57df7Smcpowers 	cb[15] = 0x01;
77123c57df7Smcpowers }
77223c57df7Smcpowers 
77323c57df7Smcpowers /*
77423c57df7Smcpowers  * Encode the length of the associated data as
77523c57df7Smcpowers  * specified in RFC 3610 and NIST publication 800-38C, appendix A
77623c57df7Smcpowers  */
77723c57df7Smcpowers static void
77823c57df7Smcpowers encode_adata_len(ulong_t auth_data_len, uint8_t *encoded, size_t *encoded_len)
77923c57df7Smcpowers {
78023c57df7Smcpowers 	if (auth_data_len < ((1ULL<<16) - (1ULL<<8))) {
78123c57df7Smcpowers 		/* 0 < a < (2^16-2^8) */
78223c57df7Smcpowers 		*encoded_len = 2;
78323c57df7Smcpowers 		encoded[0] = (auth_data_len & 0xff00) >> 8;
78423c57df7Smcpowers 		encoded[1] = auth_data_len & 0xff;
78523c57df7Smcpowers 
78623c57df7Smcpowers 	} else if ((auth_data_len >= ((1ULL<<16) - (1ULL<<8))) &&
78723c57df7Smcpowers 	    (auth_data_len < (1ULL << 31))) {
78823c57df7Smcpowers 		/* (2^16-2^8) <= a < 2^32 */
78923c57df7Smcpowers 		*encoded_len = 6;
79023c57df7Smcpowers 		encoded[0] = 0xff;
79123c57df7Smcpowers 		encoded[1] = 0xfe;
79223c57df7Smcpowers 		encoded[2] = (auth_data_len & 0xff000000) >> 24;
79323c57df7Smcpowers 		encoded[3] = (auth_data_len & 0xff0000) >> 16;
79423c57df7Smcpowers 		encoded[4] = (auth_data_len & 0xff00) >> 8;
79523c57df7Smcpowers 		encoded[5] = auth_data_len & 0xff;
79623c57df7Smcpowers #ifdef _LP64
79723c57df7Smcpowers 	} else {
79823c57df7Smcpowers 		/* 2^32 <= a < 2^64 */
79923c57df7Smcpowers 		*encoded_len = 10;
80023c57df7Smcpowers 		encoded[0] = 0xff;
80123c57df7Smcpowers 		encoded[1] = 0xff;
80223c57df7Smcpowers 		encoded[2] = (auth_data_len & 0xff00000000000000) >> 56;
80323c57df7Smcpowers 		encoded[3] = (auth_data_len & 0xff000000000000) >> 48;
80423c57df7Smcpowers 		encoded[4] = (auth_data_len & 0xff0000000000) >> 40;
80523c57df7Smcpowers 		encoded[5] = (auth_data_len & 0xff00000000) >> 32;
80623c57df7Smcpowers 		encoded[6] = (auth_data_len & 0xff000000) >> 24;
80723c57df7Smcpowers 		encoded[7] = (auth_data_len & 0xff0000) >> 16;
80823c57df7Smcpowers 		encoded[8] = (auth_data_len & 0xff00) >> 8;
80923c57df7Smcpowers 		encoded[9] = auth_data_len & 0xff;
81023c57df7Smcpowers #endif	/* _LP64 */
81123c57df7Smcpowers 	}
81223c57df7Smcpowers }
81323c57df7Smcpowers 
81423c57df7Smcpowers /*
81523c57df7Smcpowers  * The following function should be call at encrypt or decrypt init time
81623c57df7Smcpowers  * for AES CCM mode.
81723c57df7Smcpowers  */
81823c57df7Smcpowers int
81923c57df7Smcpowers ccm_init(ccm_ctx_t *ctx, unsigned char *nonce, size_t nonce_len,
82023c57df7Smcpowers     unsigned char *auth_data, size_t auth_data_len, size_t block_size,
82123c57df7Smcpowers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
82223c57df7Smcpowers     void (*xor_block)(uint8_t *, uint8_t *))
82323c57df7Smcpowers {
82423c57df7Smcpowers 	uint8_t *mac_buf, *datap, *ivp, *authp;
82523c57df7Smcpowers 	size_t remainder, processed;
82623c57df7Smcpowers 	uint8_t encoded_a[10]; /* max encoded auth data length is 10 octets */
82723c57df7Smcpowers 	size_t encoded_a_len = 0;
82823c57df7Smcpowers 
82923c57df7Smcpowers 	mac_buf = (uint8_t *)&(ctx->ccm_mac_buf);
83023c57df7Smcpowers 
83123c57df7Smcpowers 	/*
83223c57df7Smcpowers 	 * Format the 1st block for CBC-MAC and construct the
83323c57df7Smcpowers 	 * 1st counter block.
83423c57df7Smcpowers 	 *
83523c57df7Smcpowers 	 * aes_ctx->ccm_iv is used for storing the counter block
83623c57df7Smcpowers 	 * mac_buf will store b0 at this time.
83723c57df7Smcpowers 	 */
83823c57df7Smcpowers 	ccm_format_initial_blocks(nonce, nonce_len,
83923c57df7Smcpowers 	    auth_data_len, mac_buf, ctx);
84023c57df7Smcpowers 
84123c57df7Smcpowers 	/* The IV for CBC MAC for AES CCM mode is always zero */
84223c57df7Smcpowers 	ivp = (uint8_t *)ctx->ccm_tmp;
84323c57df7Smcpowers 	bzero(ivp, block_size);
84423c57df7Smcpowers 
84523c57df7Smcpowers 	xor_block(ivp, mac_buf);
84623c57df7Smcpowers 
84723c57df7Smcpowers 	/* encrypt the nonce */
84823c57df7Smcpowers 	encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
84923c57df7Smcpowers 
85023c57df7Smcpowers 	/* take care of the associated data, if any */
85123c57df7Smcpowers 	if (auth_data_len == 0) {
85223c57df7Smcpowers 		return (CRYPTO_SUCCESS);
85323c57df7Smcpowers 	}
85423c57df7Smcpowers 
85523c57df7Smcpowers 	encode_adata_len(auth_data_len, encoded_a, &encoded_a_len);
85623c57df7Smcpowers 
85723c57df7Smcpowers 	remainder = auth_data_len;
85823c57df7Smcpowers 
85923c57df7Smcpowers 	/* 1st block: it contains encoded associated data, and some data */
86023c57df7Smcpowers 	authp = (uint8_t *)ctx->ccm_tmp;
86123c57df7Smcpowers 	bzero(authp, block_size);
86223c57df7Smcpowers 	bcopy(encoded_a, authp, encoded_a_len);
86323c57df7Smcpowers 	processed = block_size - encoded_a_len;
86423c57df7Smcpowers 	if (processed > auth_data_len) {
86523c57df7Smcpowers 		/* in case auth_data is very small */
86623c57df7Smcpowers 		processed = auth_data_len;
86723c57df7Smcpowers 	}
86823c57df7Smcpowers 	bcopy(auth_data, authp+encoded_a_len, processed);
86923c57df7Smcpowers 	/* xor with previous buffer */
87023c57df7Smcpowers 	xor_block(authp, mac_buf);
87123c57df7Smcpowers 	encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
87223c57df7Smcpowers 	remainder -= processed;
87323c57df7Smcpowers 	if (remainder == 0) {
87423c57df7Smcpowers 		/* a small amount of associated data, it's all done now */
87523c57df7Smcpowers 		return (CRYPTO_SUCCESS);
87623c57df7Smcpowers 	}
87723c57df7Smcpowers 
87823c57df7Smcpowers 	do {
87923c57df7Smcpowers 		if (remainder < block_size) {
88023c57df7Smcpowers 			/*
88123c57df7Smcpowers 			 * There's not a block full of data, pad rest of
88223c57df7Smcpowers 			 * buffer with zero
88323c57df7Smcpowers 			 */
88423c57df7Smcpowers 			bzero(authp, block_size);
88523c57df7Smcpowers 			bcopy(&(auth_data[processed]), authp, remainder);
88623c57df7Smcpowers 			datap = (uint8_t *)authp;
88723c57df7Smcpowers 			remainder = 0;
88823c57df7Smcpowers 		} else {
88923c57df7Smcpowers 			datap = (uint8_t *)(&(auth_data[processed]));
89023c57df7Smcpowers 			processed += block_size;
89123c57df7Smcpowers 			remainder -= block_size;
89223c57df7Smcpowers 		}
89323c57df7Smcpowers 
89423c57df7Smcpowers 		xor_block(datap, mac_buf);
89523c57df7Smcpowers 		encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
89623c57df7Smcpowers 
89723c57df7Smcpowers 	} while (remainder > 0);
89823c57df7Smcpowers 
89923c57df7Smcpowers 	return (CRYPTO_SUCCESS);
90023c57df7Smcpowers }
90123c57df7Smcpowers 
90223c57df7Smcpowers int
90323c57df7Smcpowers ccm_init_ctx(ccm_ctx_t *ccm_ctx, char *param, int kmflag,
90423c57df7Smcpowers     boolean_t is_encrypt_init, size_t block_size,
90523c57df7Smcpowers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
90623c57df7Smcpowers     void (*xor_block)(uint8_t *, uint8_t *))
90723c57df7Smcpowers {
90823c57df7Smcpowers 	int rv;
90923c57df7Smcpowers 	CK_AES_CCM_PARAMS *ccm_param;
91023c57df7Smcpowers 
91123c57df7Smcpowers 	if (param != NULL) {
91223c57df7Smcpowers 		ccm_param = (CK_AES_CCM_PARAMS *)param;
91323c57df7Smcpowers 
91423c57df7Smcpowers 		if ((rv = ccm_validate_args(ccm_param,
91523c57df7Smcpowers 		    is_encrypt_init)) != 0) {
91623c57df7Smcpowers 			return (rv);
91723c57df7Smcpowers 		}
91823c57df7Smcpowers 
91923c57df7Smcpowers 		ccm_ctx->ccm_mac_len = ccm_param->ulMACSize;
92023c57df7Smcpowers 		if (is_encrypt_init) {
92123c57df7Smcpowers 			ccm_ctx->ccm_data_len = ccm_param->ulDataSize;
92223c57df7Smcpowers 		} else {
92323c57df7Smcpowers 			ccm_ctx->ccm_data_len =
92423c57df7Smcpowers 			    ccm_param->ulDataSize - ccm_ctx->ccm_mac_len;
92523c57df7Smcpowers 			ccm_ctx->ccm_processed_mac_len = 0;
92623c57df7Smcpowers 		}
92723c57df7Smcpowers 		ccm_ctx->ccm_processed_data_len = 0;
92823c57df7Smcpowers 
92923c57df7Smcpowers 		ccm_ctx->ccm_flags |= CCM_MODE;
93023c57df7Smcpowers 	} else {
93123c57df7Smcpowers 		rv = CRYPTO_MECHANISM_PARAM_INVALID;
93223c57df7Smcpowers 		goto out;
93323c57df7Smcpowers 	}
93423c57df7Smcpowers 
93523c57df7Smcpowers 	if (ccm_init(ccm_ctx, ccm_param->nonce, ccm_param->ulNonceSize,
93623c57df7Smcpowers 	    ccm_param->authData, ccm_param->ulAuthDataSize, block_size,
93723c57df7Smcpowers 	    encrypt_block, xor_block) != 0) {
93823c57df7Smcpowers 		rv = CRYPTO_MECHANISM_PARAM_INVALID;
93923c57df7Smcpowers 		goto out;
94023c57df7Smcpowers 	}
94123c57df7Smcpowers 	if (!is_encrypt_init) {
94223c57df7Smcpowers 		/* allocate buffer for storing decrypted plaintext */
94323c57df7Smcpowers #ifdef _KERNEL
94423c57df7Smcpowers 		ccm_ctx->ccm_pt_buf = kmem_alloc(ccm_ctx->ccm_data_len,
94523c57df7Smcpowers 		    kmflag);
94623c57df7Smcpowers #else
94723c57df7Smcpowers 		ccm_ctx->ccm_pt_buf = malloc(ccm_ctx->ccm_data_len);
94823c57df7Smcpowers #endif
94923c57df7Smcpowers 		if (ccm_ctx->ccm_pt_buf == NULL) {
95023c57df7Smcpowers 			rv = CRYPTO_HOST_MEMORY;
95123c57df7Smcpowers 		}
95223c57df7Smcpowers 	}
95323c57df7Smcpowers out:
95423c57df7Smcpowers 	return (rv);
95523c57df7Smcpowers }
95623c57df7Smcpowers 
95723c57df7Smcpowers void *
95823c57df7Smcpowers ccm_alloc_ctx(int kmflag)
95923c57df7Smcpowers {
96023c57df7Smcpowers 	ccm_ctx_t *ccm_ctx;
96123c57df7Smcpowers 
96223c57df7Smcpowers #ifdef _KERNEL
96323c57df7Smcpowers 	if ((ccm_ctx = kmem_zalloc(sizeof (ccm_ctx_t), kmflag)) == NULL)
96423c57df7Smcpowers #else
96523c57df7Smcpowers 	if ((ccm_ctx = calloc(1, sizeof (ccm_ctx_t))) == NULL)
96623c57df7Smcpowers #endif
96723c57df7Smcpowers 		return (NULL);
96823c57df7Smcpowers 
96923c57df7Smcpowers 	ccm_ctx->ccm_flags = CCM_MODE;
97023c57df7Smcpowers 	return (ccm_ctx);
97123c57df7Smcpowers }
972