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