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.
24*cd964fceSMatt Barden * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
2523c57df7Smcpowers */
2623c57df7Smcpowers
2723c57df7Smcpowers #ifndef _KERNEL
2823c57df7Smcpowers #include <strings.h>
2923c57df7Smcpowers #include <limits.h>
3023c57df7Smcpowers #include <assert.h>
3123c57df7Smcpowers #include <security/cryptoki.h>
3223c57df7Smcpowers #endif
3323c57df7Smcpowers
34*cd964fceSMatt Barden #include <sys/debug.h>
3523c57df7Smcpowers #include <sys/types.h>
3623c57df7Smcpowers #include <modes/modes.h>
3723c57df7Smcpowers #include <sys/crypto/common.h>
3823c57df7Smcpowers #include <sys/crypto/impl.h>
39*cd964fceSMatt Barden #include <aes/aes_impl.h>
40*cd964fceSMatt Barden
41*cd964fceSMatt Barden /* These are the CMAC Rb constants from NIST SP 800-38B */
42*cd964fceSMatt Barden #define CONST_RB_128 0x87
43*cd964fceSMatt Barden #define CONST_RB_64 0x1B
4423c57df7Smcpowers
4523c57df7Smcpowers /*
4623c57df7Smcpowers * Algorithm independent CBC functions.
4723c57df7Smcpowers */
4823c57df7Smcpowers int
cbc_encrypt_contiguous_blocks(cbc_ctx_t * ctx,char * data,size_t length,crypto_data_t * out,size_t block_size,int (* encrypt)(const void *,const uint8_t *,uint8_t *),void (* copy_block)(uint8_t *,uint8_t *),void (* xor_block)(uint8_t *,uint8_t *))4923c57df7Smcpowers cbc_encrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
5023c57df7Smcpowers crypto_data_t *out, size_t block_size,
5123c57df7Smcpowers int (*encrypt)(const void *, const uint8_t *, uint8_t *),
5223c57df7Smcpowers void (*copy_block)(uint8_t *, uint8_t *),
5323c57df7Smcpowers void (*xor_block)(uint8_t *, uint8_t *))
5423c57df7Smcpowers {
5523c57df7Smcpowers size_t remainder = length;
5623c57df7Smcpowers size_t need;
5723c57df7Smcpowers uint8_t *datap = (uint8_t *)data;
5823c57df7Smcpowers uint8_t *blockp;
5923c57df7Smcpowers uint8_t *lastp;
6023c57df7Smcpowers void *iov_or_mp;
6123c57df7Smcpowers offset_t offset;
6223c57df7Smcpowers uint8_t *out_data_1;
6323c57df7Smcpowers uint8_t *out_data_2;
6423c57df7Smcpowers size_t out_data_1_len;
6523c57df7Smcpowers
66*cd964fceSMatt Barden if (length + ctx->cbc_remainder_len < ctx->max_remain) {
6723c57df7Smcpowers /* accumulate bytes here and return */
6823c57df7Smcpowers bcopy(datap,
6916239bc8SMark Powers (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len,
7023c57df7Smcpowers length);
7116239bc8SMark Powers ctx->cbc_remainder_len += length;
7216239bc8SMark Powers ctx->cbc_copy_to = datap;
7323c57df7Smcpowers return (CRYPTO_SUCCESS);
7423c57df7Smcpowers }
7523c57df7Smcpowers
7616239bc8SMark Powers lastp = (uint8_t *)ctx->cbc_iv;
7723c57df7Smcpowers if (out != NULL)
7823c57df7Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset);
7923c57df7Smcpowers
8023c57df7Smcpowers do {
8123c57df7Smcpowers /* Unprocessed data from last call. */
8216239bc8SMark Powers if (ctx->cbc_remainder_len > 0) {
8316239bc8SMark Powers need = block_size - ctx->cbc_remainder_len;
8423c57df7Smcpowers
8523c57df7Smcpowers if (need > remainder)
8623c57df7Smcpowers return (CRYPTO_DATA_LEN_RANGE);
8723c57df7Smcpowers
8816239bc8SMark Powers bcopy(datap, &((uint8_t *)ctx->cbc_remainder)
8916239bc8SMark Powers [ctx->cbc_remainder_len], need);
9023c57df7Smcpowers
9116239bc8SMark Powers blockp = (uint8_t *)ctx->cbc_remainder;
9223c57df7Smcpowers } else {
9323c57df7Smcpowers blockp = datap;
9423c57df7Smcpowers }
9523c57df7Smcpowers
9623c57df7Smcpowers if (out == NULL) {
9723c57df7Smcpowers /*
9823c57df7Smcpowers * XOR the previous cipher block or IV with the
9923c57df7Smcpowers * current clear block.
10023c57df7Smcpowers */
10123c57df7Smcpowers xor_block(lastp, blockp);
10216239bc8SMark Powers encrypt(ctx->cbc_keysched, blockp, blockp);
10323c57df7Smcpowers
10416239bc8SMark Powers ctx->cbc_lastp = blockp;
10523c57df7Smcpowers lastp = blockp;
10623c57df7Smcpowers
107*cd964fceSMatt Barden if ((ctx->cbc_flags & CMAC_MODE) == 0 &&
108*cd964fceSMatt Barden ctx->cbc_remainder_len > 0) {
10916239bc8SMark Powers bcopy(blockp, ctx->cbc_copy_to,
11016239bc8SMark Powers ctx->cbc_remainder_len);
11116239bc8SMark Powers bcopy(blockp + ctx->cbc_remainder_len, datap,
11223c57df7Smcpowers need);
11323c57df7Smcpowers }
11423c57df7Smcpowers } else {
11523c57df7Smcpowers /*
11623c57df7Smcpowers * XOR the previous cipher block or IV with the
11723c57df7Smcpowers * current clear block.
11823c57df7Smcpowers */
11923c57df7Smcpowers xor_block(blockp, lastp);
12016239bc8SMark Powers encrypt(ctx->cbc_keysched, lastp, lastp);
12123c57df7Smcpowers
122*cd964fceSMatt Barden /*
123*cd964fceSMatt Barden * CMAC doesn't output until encrypt_final
124*cd964fceSMatt Barden */
125*cd964fceSMatt Barden if ((ctx->cbc_flags & CMAC_MODE) == 0) {
126*cd964fceSMatt Barden crypto_get_ptrs(out, &iov_or_mp, &offset,
127*cd964fceSMatt Barden &out_data_1, &out_data_1_len,
128*cd964fceSMatt Barden &out_data_2, block_size);
129*cd964fceSMatt Barden
130*cd964fceSMatt Barden /* copy block to where it belongs */
131*cd964fceSMatt Barden if (out_data_1_len == block_size) {
132*cd964fceSMatt Barden copy_block(lastp, out_data_1);
133*cd964fceSMatt Barden } else {
134*cd964fceSMatt Barden bcopy(lastp, out_data_1,
135*cd964fceSMatt Barden out_data_1_len);
136*cd964fceSMatt Barden if (out_data_2 != NULL) {
137*cd964fceSMatt Barden bcopy(lastp + out_data_1_len,
138*cd964fceSMatt Barden out_data_2,
139*cd964fceSMatt Barden block_size -
140*cd964fceSMatt Barden out_data_1_len);
141*cd964fceSMatt Barden }
14223c57df7Smcpowers }
143*cd964fceSMatt Barden /* update offset */
144*cd964fceSMatt Barden out->cd_offset += block_size;
14523c57df7Smcpowers }
14623c57df7Smcpowers }
14723c57df7Smcpowers
14823c57df7Smcpowers /* Update pointer to next block of data to be processed. */
14916239bc8SMark Powers if (ctx->cbc_remainder_len != 0) {
15023c57df7Smcpowers datap += need;
15116239bc8SMark Powers ctx->cbc_remainder_len = 0;
15223c57df7Smcpowers } else {
15323c57df7Smcpowers datap += block_size;
15423c57df7Smcpowers }
15523c57df7Smcpowers
15623c57df7Smcpowers remainder = (size_t)&data[length] - (size_t)datap;
15723c57df7Smcpowers
15823c57df7Smcpowers /* Incomplete last block. */
159*cd964fceSMatt Barden if (remainder > 0 && remainder < ctx->max_remain) {
16016239bc8SMark Powers bcopy(datap, ctx->cbc_remainder, remainder);
16116239bc8SMark Powers ctx->cbc_remainder_len = remainder;
16216239bc8SMark Powers ctx->cbc_copy_to = datap;
16323c57df7Smcpowers goto out;
16423c57df7Smcpowers }
16516239bc8SMark Powers ctx->cbc_copy_to = NULL;
16623c57df7Smcpowers
16723c57df7Smcpowers } while (remainder > 0);
16823c57df7Smcpowers
16923c57df7Smcpowers out:
17023c57df7Smcpowers /*
17123c57df7Smcpowers * Save the last encrypted block in the context.
17223c57df7Smcpowers */
17316239bc8SMark Powers if (ctx->cbc_lastp != NULL) {
17416239bc8SMark Powers copy_block((uint8_t *)ctx->cbc_lastp, (uint8_t *)ctx->cbc_iv);
17516239bc8SMark Powers ctx->cbc_lastp = (uint8_t *)ctx->cbc_iv;
17623c57df7Smcpowers }
17723c57df7Smcpowers
17823c57df7Smcpowers return (CRYPTO_SUCCESS);
17923c57df7Smcpowers }
18023c57df7Smcpowers
18123c57df7Smcpowers #define OTHER(a, ctx) \
18216239bc8SMark Powers (((a) == (ctx)->cbc_lastblock) ? (ctx)->cbc_iv : (ctx)->cbc_lastblock)
18323c57df7Smcpowers
18423c57df7Smcpowers /* ARGSUSED */
18523c57df7Smcpowers int
cbc_decrypt_contiguous_blocks(cbc_ctx_t * ctx,char * data,size_t length,crypto_data_t * out,size_t block_size,int (* decrypt)(const void *,const uint8_t *,uint8_t *),void (* copy_block)(uint8_t *,uint8_t *),void (* xor_block)(uint8_t *,uint8_t *))18623c57df7Smcpowers cbc_decrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
18723c57df7Smcpowers crypto_data_t *out, size_t block_size,
18823c57df7Smcpowers int (*decrypt)(const void *, const uint8_t *, uint8_t *),
18923c57df7Smcpowers void (*copy_block)(uint8_t *, uint8_t *),
19023c57df7Smcpowers void (*xor_block)(uint8_t *, uint8_t *))
19123c57df7Smcpowers {
19223c57df7Smcpowers size_t remainder = length;
19323c57df7Smcpowers size_t need;
19423c57df7Smcpowers uint8_t *datap = (uint8_t *)data;
19523c57df7Smcpowers uint8_t *blockp;
19623c57df7Smcpowers uint8_t *lastp;
19723c57df7Smcpowers void *iov_or_mp;
19823c57df7Smcpowers offset_t offset;
19923c57df7Smcpowers uint8_t *out_data_1;
20023c57df7Smcpowers uint8_t *out_data_2;
20123c57df7Smcpowers size_t out_data_1_len;
20223c57df7Smcpowers
20316239bc8SMark Powers if (length + ctx->cbc_remainder_len < block_size) {
20423c57df7Smcpowers /* accumulate bytes here and return */
20523c57df7Smcpowers bcopy(datap,
20616239bc8SMark Powers (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len,
20723c57df7Smcpowers length);
20816239bc8SMark Powers ctx->cbc_remainder_len += length;
20916239bc8SMark Powers ctx->cbc_copy_to = datap;
21023c57df7Smcpowers return (CRYPTO_SUCCESS);
21123c57df7Smcpowers }
21223c57df7Smcpowers
21316239bc8SMark Powers lastp = ctx->cbc_lastp;
21423c57df7Smcpowers if (out != NULL)
21523c57df7Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset);
21623c57df7Smcpowers
21723c57df7Smcpowers do {
21823c57df7Smcpowers /* Unprocessed data from last call. */
21916239bc8SMark Powers if (ctx->cbc_remainder_len > 0) {
22016239bc8SMark Powers need = block_size - ctx->cbc_remainder_len;
22123c57df7Smcpowers
22223c57df7Smcpowers if (need > remainder)
22323c57df7Smcpowers return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
22423c57df7Smcpowers
22516239bc8SMark Powers bcopy(datap, &((uint8_t *)ctx->cbc_remainder)
22616239bc8SMark Powers [ctx->cbc_remainder_len], need);
22723c57df7Smcpowers
22816239bc8SMark Powers blockp = (uint8_t *)ctx->cbc_remainder;
22923c57df7Smcpowers } else {
23023c57df7Smcpowers blockp = datap;
23123c57df7Smcpowers }
23223c57df7Smcpowers
23323c57df7Smcpowers /* LINTED: pointer alignment */
23423c57df7Smcpowers copy_block(blockp, (uint8_t *)OTHER((uint64_t *)lastp, ctx));
23523c57df7Smcpowers
23623c57df7Smcpowers if (out != NULL) {
23716239bc8SMark Powers decrypt(ctx->cbc_keysched, blockp,
23816239bc8SMark Powers (uint8_t *)ctx->cbc_remainder);
23916239bc8SMark Powers blockp = (uint8_t *)ctx->cbc_remainder;
24023c57df7Smcpowers } else {
24116239bc8SMark Powers decrypt(ctx->cbc_keysched, blockp, blockp);
24223c57df7Smcpowers }
24323c57df7Smcpowers
24423c57df7Smcpowers /*
24523c57df7Smcpowers * XOR the previous cipher block or IV with the
24623c57df7Smcpowers * currently decrypted block.
24723c57df7Smcpowers */
24823c57df7Smcpowers xor_block(lastp, blockp);
24923c57df7Smcpowers
25023c57df7Smcpowers /* LINTED: pointer alignment */
25123c57df7Smcpowers lastp = (uint8_t *)OTHER((uint64_t *)lastp, ctx);
25223c57df7Smcpowers
25323c57df7Smcpowers if (out != NULL) {
25423c57df7Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
25523c57df7Smcpowers &out_data_1_len, &out_data_2, block_size);
25623c57df7Smcpowers
25723c57df7Smcpowers bcopy(blockp, out_data_1, out_data_1_len);
25823c57df7Smcpowers if (out_data_2 != NULL) {
25923c57df7Smcpowers bcopy(blockp + out_data_1_len, out_data_2,
26023c57df7Smcpowers block_size - out_data_1_len);
26123c57df7Smcpowers }
26223c57df7Smcpowers
26323c57df7Smcpowers /* update offset */
26423c57df7Smcpowers out->cd_offset += block_size;
26523c57df7Smcpowers
26616239bc8SMark Powers } else if (ctx->cbc_remainder_len > 0) {
26723c57df7Smcpowers /* copy temporary block to where it belongs */
26816239bc8SMark Powers bcopy(blockp, ctx->cbc_copy_to, ctx->cbc_remainder_len);
26916239bc8SMark Powers bcopy(blockp + ctx->cbc_remainder_len, datap, need);
27023c57df7Smcpowers }
27123c57df7Smcpowers
27223c57df7Smcpowers /* Update pointer to next block of data to be processed. */
27316239bc8SMark Powers if (ctx->cbc_remainder_len != 0) {
27423c57df7Smcpowers datap += need;
27516239bc8SMark Powers ctx->cbc_remainder_len = 0;
27623c57df7Smcpowers } else {
27723c57df7Smcpowers datap += block_size;
27823c57df7Smcpowers }
27923c57df7Smcpowers
28023c57df7Smcpowers remainder = (size_t)&data[length] - (size_t)datap;
28123c57df7Smcpowers
28223c57df7Smcpowers /* Incomplete last block. */
28323c57df7Smcpowers if (remainder > 0 && remainder < block_size) {
28416239bc8SMark Powers bcopy(datap, ctx->cbc_remainder, remainder);
28516239bc8SMark Powers ctx->cbc_remainder_len = remainder;
28616239bc8SMark Powers ctx->cbc_lastp = lastp;
28716239bc8SMark Powers ctx->cbc_copy_to = datap;
28823c57df7Smcpowers return (CRYPTO_SUCCESS);
28923c57df7Smcpowers }
29016239bc8SMark Powers ctx->cbc_copy_to = NULL;
29123c57df7Smcpowers
29223c57df7Smcpowers } while (remainder > 0);
29323c57df7Smcpowers
29416239bc8SMark Powers ctx->cbc_lastp = lastp;
29523c57df7Smcpowers return (CRYPTO_SUCCESS);
29623c57df7Smcpowers }
29723c57df7Smcpowers
29823c57df7Smcpowers int
cbc_init_ctx(cbc_ctx_t * cbc_ctx,char * param,size_t param_len,size_t block_size,void (* copy_block)(uint8_t *,uint64_t *))29923c57df7Smcpowers cbc_init_ctx(cbc_ctx_t *cbc_ctx, char *param, size_t param_len,
30023c57df7Smcpowers size_t block_size, void (*copy_block)(uint8_t *, uint64_t *))
30123c57df7Smcpowers {
30223c57df7Smcpowers /*
30323c57df7Smcpowers * Copy IV into context.
30423c57df7Smcpowers *
30523c57df7Smcpowers * If cm_param == NULL then the IV comes from the
30623c57df7Smcpowers * cd_miscdata field in the crypto_data structure.
30723c57df7Smcpowers */
30823c57df7Smcpowers if (param != NULL) {
30923c57df7Smcpowers #ifdef _KERNEL
31023c57df7Smcpowers ASSERT(param_len == block_size);
31123c57df7Smcpowers #else
31223c57df7Smcpowers assert(param_len == block_size);
31323c57df7Smcpowers #endif
31416239bc8SMark Powers copy_block((uchar_t *)param, cbc_ctx->cbc_iv);
31523c57df7Smcpowers }
31623c57df7Smcpowers
31716239bc8SMark Powers cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0];
31816239bc8SMark Powers cbc_ctx->cbc_flags |= CBC_MODE;
319*cd964fceSMatt Barden cbc_ctx->max_remain = block_size;
32023c57df7Smcpowers return (CRYPTO_SUCCESS);
32123c57df7Smcpowers }
32223c57df7Smcpowers
32323c57df7Smcpowers /* ARGSUSED */
324*cd964fceSMatt Barden static void *
cbc_cmac_alloc_ctx(int kmflag,uint32_t mode)325*cd964fceSMatt Barden cbc_cmac_alloc_ctx(int kmflag, uint32_t mode)
32623c57df7Smcpowers {
32723c57df7Smcpowers cbc_ctx_t *cbc_ctx;
328*cd964fceSMatt Barden uint32_t modeval = mode & (CBC_MODE|CMAC_MODE);
329*cd964fceSMatt Barden
330*cd964fceSMatt Barden /* Only one of the two modes can be set */
331*cd964fceSMatt Barden VERIFY(modeval == CBC_MODE || modeval == CMAC_MODE);
33223c57df7Smcpowers
33323c57df7Smcpowers #ifdef _KERNEL
33423c57df7Smcpowers if ((cbc_ctx = kmem_zalloc(sizeof (cbc_ctx_t), kmflag)) == NULL)
33523c57df7Smcpowers #else
33623c57df7Smcpowers if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
33723c57df7Smcpowers #endif
33823c57df7Smcpowers return (NULL);
33923c57df7Smcpowers
340*cd964fceSMatt Barden cbc_ctx->cbc_flags = mode;
34123c57df7Smcpowers return (cbc_ctx);
34223c57df7Smcpowers }
343*cd964fceSMatt Barden
344*cd964fceSMatt Barden void *
cbc_alloc_ctx(int kmflag)345*cd964fceSMatt Barden cbc_alloc_ctx(int kmflag)
346*cd964fceSMatt Barden {
347*cd964fceSMatt Barden return (cbc_cmac_alloc_ctx(kmflag, CBC_MODE));
348*cd964fceSMatt Barden }
349*cd964fceSMatt Barden
350*cd964fceSMatt Barden /*
351*cd964fceSMatt Barden * Algorithms for supporting AES-CMAC
352*cd964fceSMatt Barden * NOTE: CMAC is generally just a wrapper for CBC
353*cd964fceSMatt Barden */
354*cd964fceSMatt Barden
355*cd964fceSMatt Barden void *
cmac_alloc_ctx(int kmflag)356*cd964fceSMatt Barden cmac_alloc_ctx(int kmflag)
357*cd964fceSMatt Barden {
358*cd964fceSMatt Barden return (cbc_cmac_alloc_ctx(kmflag, CMAC_MODE));
359*cd964fceSMatt Barden }
360*cd964fceSMatt Barden
361*cd964fceSMatt Barden
362*cd964fceSMatt Barden /*
363*cd964fceSMatt Barden * Typically max_remain is set to block_size - 1, since we usually
364*cd964fceSMatt Barden * will process the data once we have a full block. However with CMAC,
365*cd964fceSMatt Barden * we must preprocess the final block of data. Since we cannot know
366*cd964fceSMatt Barden * when we've received the final block of data until the _final() method
367*cd964fceSMatt Barden * is called, we must not process the last block of data until we know
368*cd964fceSMatt Barden * it is the last block, or we receive a new block of data. As such,
369*cd964fceSMatt Barden * max_remain for CMAC is block_size + 1.
370*cd964fceSMatt Barden */
371*cd964fceSMatt Barden int
cmac_init_ctx(cbc_ctx_t * cbc_ctx,size_t block_size)372*cd964fceSMatt Barden cmac_init_ctx(cbc_ctx_t *cbc_ctx, size_t block_size)
373*cd964fceSMatt Barden {
374*cd964fceSMatt Barden /*
375*cd964fceSMatt Barden * CMAC is only approved for block sizes 64 and 128 bits /
376*cd964fceSMatt Barden * 8 and 16 bytes.
377*cd964fceSMatt Barden */
378*cd964fceSMatt Barden
379*cd964fceSMatt Barden if (block_size != 16 && block_size != 8)
380*cd964fceSMatt Barden return (CRYPTO_INVALID_CONTEXT);
381*cd964fceSMatt Barden
382*cd964fceSMatt Barden /*
383*cd964fceSMatt Barden * For CMAC, cbc_iv is always 0.
384*cd964fceSMatt Barden */
385*cd964fceSMatt Barden
386*cd964fceSMatt Barden cbc_ctx->cbc_iv[0] = 0;
387*cd964fceSMatt Barden cbc_ctx->cbc_iv[1] = 0;
388*cd964fceSMatt Barden
389*cd964fceSMatt Barden cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0];
390*cd964fceSMatt Barden cbc_ctx->cbc_flags |= CMAC_MODE;
391*cd964fceSMatt Barden
392*cd964fceSMatt Barden cbc_ctx->max_remain = block_size + 1;
393*cd964fceSMatt Barden return (CRYPTO_SUCCESS);
394*cd964fceSMatt Barden }
395*cd964fceSMatt Barden
396*cd964fceSMatt Barden /*
397*cd964fceSMatt Barden * Left shifts blocks by one and returns the leftmost bit
398*cd964fceSMatt Barden */
399*cd964fceSMatt Barden static uint8_t
cmac_left_shift_block_by1(uint8_t * block,size_t block_size)400*cd964fceSMatt Barden cmac_left_shift_block_by1(uint8_t *block, size_t block_size)
401*cd964fceSMatt Barden {
402*cd964fceSMatt Barden uint8_t carry = 0, old;
403*cd964fceSMatt Barden size_t i;
404*cd964fceSMatt Barden for (i = block_size; i > 0; i--) {
405*cd964fceSMatt Barden old = carry;
406*cd964fceSMatt Barden carry = (block[i - 1] & 0x80) ? 1 : 0;
407*cd964fceSMatt Barden block[i - 1] = (block[i - 1] << 1) | old;
408*cd964fceSMatt Barden }
409*cd964fceSMatt Barden return (carry);
410*cd964fceSMatt Barden }
411*cd964fceSMatt Barden
412*cd964fceSMatt Barden /*
413*cd964fceSMatt Barden * Generate subkeys to preprocess the last block according to RFC 4493.
414*cd964fceSMatt Barden * Store the final block_size MAC generated in 'out'.
415*cd964fceSMatt Barden */
416*cd964fceSMatt Barden int
cmac_mode_final(cbc_ctx_t * cbc_ctx,crypto_data_t * out,int (* encrypt_block)(const void *,const uint8_t *,uint8_t *),void (* xor_block)(uint8_t *,uint8_t *))417*cd964fceSMatt Barden cmac_mode_final(cbc_ctx_t *cbc_ctx, crypto_data_t *out,
418*cd964fceSMatt Barden int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
419*cd964fceSMatt Barden void (*xor_block)(uint8_t *, uint8_t *))
420*cd964fceSMatt Barden {
421*cd964fceSMatt Barden uint8_t buf[AES_BLOCK_LEN] = {0};
422*cd964fceSMatt Barden uint8_t *M_last = (uint8_t *)cbc_ctx->cbc_remainder;
423*cd964fceSMatt Barden size_t length = cbc_ctx->cbc_remainder_len;
424*cd964fceSMatt Barden size_t block_size = cbc_ctx->max_remain - 1;
425*cd964fceSMatt Barden uint8_t const_rb;
426*cd964fceSMatt Barden
427*cd964fceSMatt Barden if (length > block_size)
428*cd964fceSMatt Barden return (CRYPTO_INVALID_CONTEXT);
429*cd964fceSMatt Barden
430*cd964fceSMatt Barden if (out->cd_length < block_size)
431*cd964fceSMatt Barden return (CRYPTO_DATA_LEN_RANGE);
432*cd964fceSMatt Barden
433*cd964fceSMatt Barden if (block_size == 16)
434*cd964fceSMatt Barden const_rb = CONST_RB_128;
435*cd964fceSMatt Barden else if (block_size == 8)
436*cd964fceSMatt Barden const_rb = CONST_RB_64;
437*cd964fceSMatt Barden else
438*cd964fceSMatt Barden return (CRYPTO_INVALID_CONTEXT);
439*cd964fceSMatt Barden
440*cd964fceSMatt Barden /* k_0 = E_k(0) */
441*cd964fceSMatt Barden encrypt_block(cbc_ctx->cbc_keysched, buf, buf);
442*cd964fceSMatt Barden
443*cd964fceSMatt Barden if (cmac_left_shift_block_by1(buf, block_size))
444*cd964fceSMatt Barden buf[block_size - 1] ^= const_rb;
445*cd964fceSMatt Barden
446*cd964fceSMatt Barden if (length == block_size) {
447*cd964fceSMatt Barden /* Last block complete, so m_n = k_1 + m_n' */
448*cd964fceSMatt Barden xor_block(buf, M_last);
449*cd964fceSMatt Barden xor_block(cbc_ctx->cbc_lastp, M_last);
450*cd964fceSMatt Barden encrypt_block(cbc_ctx->cbc_keysched, M_last, M_last);
451*cd964fceSMatt Barden } else {
452*cd964fceSMatt Barden /* Last block incomplete, so m_n = k_2 + (m_n' | 100...0_bin) */
453*cd964fceSMatt Barden if (cmac_left_shift_block_by1(buf, block_size))
454*cd964fceSMatt Barden buf[block_size - 1] ^= const_rb;
455*cd964fceSMatt Barden
456*cd964fceSMatt Barden M_last[length] = 0x80;
457*cd964fceSMatt Barden bzero(M_last + length + 1, block_size - length - 1);
458*cd964fceSMatt Barden xor_block(buf, M_last);
459*cd964fceSMatt Barden xor_block(cbc_ctx->cbc_lastp, M_last);
460*cd964fceSMatt Barden encrypt_block(cbc_ctx->cbc_keysched, M_last, M_last);
461*cd964fceSMatt Barden }
462*cd964fceSMatt Barden
463*cd964fceSMatt Barden /*
464*cd964fceSMatt Barden * zero out the sub-key.
465*cd964fceSMatt Barden */
466*cd964fceSMatt Barden #ifndef _KERNEL
467*cd964fceSMatt Barden explicit_bzero(&buf, sizeof (buf));
468*cd964fceSMatt Barden #else
469*cd964fceSMatt Barden bzero(&buf, sizeof (buf));
470*cd964fceSMatt Barden #endif
471*cd964fceSMatt Barden return (crypto_put_output_data(M_last, out, block_size));
472*cd964fceSMatt Barden }
473