Path: blob/main/sys/contrib/openzfs/module/icp/algs/modes/ccm.c
48775 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/21/*22* Copyright 2008 Sun Microsystems, Inc. All rights reserved.23* Use is subject to license terms.24*/2526#include <sys/zfs_context.h>27#include <modes/modes.h>28#include <sys/crypto/common.h>29#include <sys/crypto/impl.h>3031#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS32#include <sys/byteorder.h>33#define UNALIGNED_POINTERS_PERMITTED34#endif3536/*37* Encrypt multiple blocks of data in CCM mode. Decrypt for CCM mode38* is done in another function.39*/40int41ccm_mode_encrypt_contiguous_blocks(ccm_ctx_t *ctx, char *data, size_t length,42crypto_data_t *out, size_t block_size,43int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),44void (*copy_block)(uint8_t *, uint8_t *),45void (*xor_block)(uint8_t *, uint8_t *))46{47size_t remainder = length;48size_t need = 0;49uint8_t *datap = (uint8_t *)data;50uint8_t *blockp;51uint8_t *lastp;52void *iov_or_mp;53offset_t offset;54uint8_t *out_data_1;55uint8_t *out_data_2;56size_t out_data_1_len;57uint64_t counter;58uint8_t *mac_buf;5960if (length + ctx->ccm_remainder_len < block_size) {61/* accumulate bytes here and return */62memcpy((uint8_t *)ctx->ccm_remainder + ctx->ccm_remainder_len,63datap,64length);65ctx->ccm_remainder_len += length;66ctx->ccm_copy_to = datap;67return (CRYPTO_SUCCESS);68}6970crypto_init_ptrs(out, &iov_or_mp, &offset);7172mac_buf = (uint8_t *)ctx->ccm_mac_buf;7374do {75/* Unprocessed data from last call. */76if (ctx->ccm_remainder_len > 0) {77need = block_size - ctx->ccm_remainder_len;7879if (need > remainder)80return (CRYPTO_DATA_LEN_RANGE);8182memcpy(&((uint8_t *)ctx->ccm_remainder)83[ctx->ccm_remainder_len], datap, need);8485blockp = (uint8_t *)ctx->ccm_remainder;86} else {87blockp = datap;88}8990/*91* do CBC MAC92*93* XOR the previous cipher block current clear block.94* mac_buf always contain previous cipher block.95*/96xor_block(blockp, mac_buf);97encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);9899/* ccm_cb is the counter block */100encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb,101(uint8_t *)ctx->ccm_tmp);102103lastp = (uint8_t *)ctx->ccm_tmp;104105/*106* Increment counter. Counter bits are confined107* to the bottom 64 bits of the counter block.108*/109#ifdef _ZFS_LITTLE_ENDIAN110counter = ntohll(ctx->ccm_cb[1] & ctx->ccm_counter_mask);111counter = htonll(counter + 1);112#else113counter = ctx->ccm_cb[1] & ctx->ccm_counter_mask;114counter++;115#endif /* _ZFS_LITTLE_ENDIAN */116counter &= ctx->ccm_counter_mask;117ctx->ccm_cb[1] =118(ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;119120/*121* XOR encrypted counter block with the current clear block.122*/123xor_block(blockp, lastp);124125ctx->ccm_processed_data_len += block_size;126127crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,128&out_data_1_len, &out_data_2, block_size);129130/* copy block to where it belongs */131if (out_data_1_len == block_size) {132copy_block(lastp, out_data_1);133} else {134memcpy(out_data_1, lastp, out_data_1_len);135if (out_data_2 != NULL) {136memcpy(out_data_2,137lastp + out_data_1_len,138block_size - out_data_1_len);139}140}141/* update offset */142out->cd_offset += block_size;143144/* Update pointer to next block of data to be processed. */145if (ctx->ccm_remainder_len != 0) {146datap += need;147ctx->ccm_remainder_len = 0;148} else {149datap += block_size;150}151152remainder = (size_t)&data[length] - (size_t)datap;153154/* Incomplete last block. */155if (remainder > 0 && remainder < block_size) {156memcpy(ctx->ccm_remainder, datap, remainder);157ctx->ccm_remainder_len = remainder;158ctx->ccm_copy_to = datap;159goto out;160}161ctx->ccm_copy_to = NULL;162163} while (remainder > 0);164165out:166return (CRYPTO_SUCCESS);167}168169void170calculate_ccm_mac(ccm_ctx_t *ctx, uint8_t *ccm_mac,171int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))172{173uint64_t counter;174uint8_t *counterp, *mac_buf;175int i;176177mac_buf = (uint8_t *)ctx->ccm_mac_buf;178179/* first counter block start with index 0 */180counter = 0;181ctx->ccm_cb[1] = (ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;182183counterp = (uint8_t *)ctx->ccm_tmp;184encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, counterp);185186/* calculate XOR of MAC with first counter block */187for (i = 0; i < ctx->ccm_mac_len; i++) {188ccm_mac[i] = mac_buf[i] ^ counterp[i];189}190}191192int193ccm_encrypt_final(ccm_ctx_t *ctx, crypto_data_t *out, size_t block_size,194int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),195void (*xor_block)(uint8_t *, uint8_t *))196{197uint8_t *lastp, *mac_buf, *ccm_mac_p, *macp = NULL;198void *iov_or_mp;199offset_t offset;200uint8_t *out_data_1;201uint8_t *out_data_2;202size_t out_data_1_len;203int i;204205if (out->cd_length < (ctx->ccm_remainder_len + ctx->ccm_mac_len)) {206return (CRYPTO_DATA_LEN_RANGE);207}208209/*210* When we get here, the number of bytes of payload processed211* plus whatever data remains, if any,212* should be the same as the number of bytes that's being213* passed in the argument during init time.214*/215if ((ctx->ccm_processed_data_len + ctx->ccm_remainder_len)216!= (ctx->ccm_data_len)) {217return (CRYPTO_DATA_LEN_RANGE);218}219220mac_buf = (uint8_t *)ctx->ccm_mac_buf;221222if (ctx->ccm_remainder_len > 0) {223224/* ccm_mac_input_buf is not used for encryption */225macp = (uint8_t *)ctx->ccm_mac_input_buf;226memset(macp, 0, block_size);227228/* copy remainder to temporary buffer */229memcpy(macp, ctx->ccm_remainder, ctx->ccm_remainder_len);230231/* calculate the CBC MAC */232xor_block(macp, mac_buf);233encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);234235/* calculate the counter mode */236lastp = (uint8_t *)ctx->ccm_tmp;237encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, lastp);238239/* XOR with counter block */240for (i = 0; i < ctx->ccm_remainder_len; i++) {241macp[i] ^= lastp[i];242}243ctx->ccm_processed_data_len += ctx->ccm_remainder_len;244}245246/* Calculate the CCM MAC */247ccm_mac_p = (uint8_t *)ctx->ccm_tmp;248calculate_ccm_mac(ctx, ccm_mac_p, encrypt_block);249250crypto_init_ptrs(out, &iov_or_mp, &offset);251crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,252&out_data_1_len, &out_data_2,253ctx->ccm_remainder_len + ctx->ccm_mac_len);254255if (ctx->ccm_remainder_len > 0) {256/* copy temporary block to where it belongs */257if (out_data_2 == NULL) {258/* everything will fit in out_data_1 */259memcpy(out_data_1, macp, ctx->ccm_remainder_len);260memcpy(out_data_1 + ctx->ccm_remainder_len, ccm_mac_p,261ctx->ccm_mac_len);262} else {263if (out_data_1_len < ctx->ccm_remainder_len) {264size_t data_2_len_used;265266memcpy(out_data_1, macp, out_data_1_len);267268data_2_len_used = ctx->ccm_remainder_len269- out_data_1_len;270271memcpy(out_data_2,272(uint8_t *)macp + out_data_1_len,273data_2_len_used);274memcpy(out_data_2 + data_2_len_used,275ccm_mac_p,276ctx->ccm_mac_len);277} else {278memcpy(out_data_1, macp, out_data_1_len);279if (out_data_1_len == ctx->ccm_remainder_len) {280/* mac will be in out_data_2 */281memcpy(out_data_2, ccm_mac_p,282ctx->ccm_mac_len);283} else {284size_t len_not_used = out_data_1_len -285ctx->ccm_remainder_len;286/*287* part of mac in will be in288* out_data_1, part of the mac will be289* in out_data_2290*/291memcpy(out_data_1 +292ctx->ccm_remainder_len,293ccm_mac_p, len_not_used);294memcpy(out_data_2,295ccm_mac_p + len_not_used,296ctx->ccm_mac_len - len_not_used);297298}299}300}301} else {302/* copy block to where it belongs */303memcpy(out_data_1, ccm_mac_p, out_data_1_len);304if (out_data_2 != NULL) {305memcpy(out_data_2, ccm_mac_p + out_data_1_len,306block_size - out_data_1_len);307}308}309out->cd_offset += ctx->ccm_remainder_len + ctx->ccm_mac_len;310ctx->ccm_remainder_len = 0;311return (CRYPTO_SUCCESS);312}313314/*315* This will only deal with decrypting the last block of the input that316* might not be a multiple of block length.317*/318static void319ccm_decrypt_incomplete_block(ccm_ctx_t *ctx,320int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))321{322uint8_t *datap, *outp, *counterp;323int i;324325datap = (uint8_t *)ctx->ccm_remainder;326outp = &((ctx->ccm_pt_buf)[ctx->ccm_processed_data_len]);327328counterp = (uint8_t *)ctx->ccm_tmp;329encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, counterp);330331/* XOR with counter block */332for (i = 0; i < ctx->ccm_remainder_len; i++) {333outp[i] = datap[i] ^ counterp[i];334}335}336337/*338* This will decrypt the cipher text. However, the plaintext won't be339* returned to the caller. It will be returned when decrypt_final() is340* called if the MAC matches341*/342int343ccm_mode_decrypt_contiguous_blocks(ccm_ctx_t *ctx, char *data, size_t length,344crypto_data_t *out, size_t block_size,345int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),346void (*copy_block)(uint8_t *, uint8_t *),347void (*xor_block)(uint8_t *, uint8_t *))348{349(void) out;350size_t remainder = length;351size_t need = 0;352uint8_t *datap = (uint8_t *)data;353uint8_t *blockp;354uint8_t *cbp;355uint64_t counter;356size_t pt_len, total_decrypted_len, mac_len, pm_len, pd_len;357uint8_t *resultp;358359360pm_len = ctx->ccm_processed_mac_len;361362if (pm_len > 0) {363uint8_t *tmp;364/*365* all ciphertext has been processed, just waiting for366* part of the value of the mac367*/368if ((pm_len + length) > ctx->ccm_mac_len) {369return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);370}371tmp = (uint8_t *)ctx->ccm_mac_input_buf;372373memcpy(tmp + pm_len, datap, length);374375ctx->ccm_processed_mac_len += length;376return (CRYPTO_SUCCESS);377}378379/*380* If we decrypt the given data, what total amount of data would381* have been decrypted?382*/383pd_len = ctx->ccm_processed_data_len;384total_decrypted_len = pd_len + length + ctx->ccm_remainder_len;385386if (total_decrypted_len >387(ctx->ccm_data_len + ctx->ccm_mac_len)) {388return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);389}390391pt_len = ctx->ccm_data_len;392393if (total_decrypted_len > pt_len) {394/*395* part of the input will be the MAC, need to isolate that396* to be dealt with later. The left-over data in397* ccm_remainder_len from last time will not be part of the398* MAC. Otherwise, it would have already been taken out399* when this call is made last time.400*/401size_t pt_part = pt_len - pd_len - ctx->ccm_remainder_len;402403mac_len = length - pt_part;404405ctx->ccm_processed_mac_len = mac_len;406memcpy(ctx->ccm_mac_input_buf, data + pt_part, mac_len);407408if (pt_part + ctx->ccm_remainder_len < block_size) {409/*410* since this is last of the ciphertext, will411* just decrypt with it here412*/413memcpy(&((uint8_t *)ctx->ccm_remainder)414[ctx->ccm_remainder_len], datap, pt_part);415ctx->ccm_remainder_len += pt_part;416ccm_decrypt_incomplete_block(ctx, encrypt_block);417ctx->ccm_processed_data_len += ctx->ccm_remainder_len;418ctx->ccm_remainder_len = 0;419return (CRYPTO_SUCCESS);420} else {421/* let rest of the code handle this */422length = pt_part;423}424} else if (length + ctx->ccm_remainder_len < block_size) {425/* accumulate bytes here and return */426memcpy((uint8_t *)ctx->ccm_remainder + ctx->ccm_remainder_len,427datap,428length);429ctx->ccm_remainder_len += length;430ctx->ccm_copy_to = datap;431return (CRYPTO_SUCCESS);432}433434do {435/* Unprocessed data from last call. */436if (ctx->ccm_remainder_len > 0) {437need = block_size - ctx->ccm_remainder_len;438439if (need > remainder)440return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);441442memcpy(&((uint8_t *)ctx->ccm_remainder)443[ctx->ccm_remainder_len], datap, need);444445blockp = (uint8_t *)ctx->ccm_remainder;446} else {447blockp = datap;448}449450/* Calculate the counter mode, ccm_cb is the counter block */451cbp = (uint8_t *)ctx->ccm_tmp;452encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, cbp);453454/*455* Increment counter.456* Counter bits are confined to the bottom 64 bits457*/458#ifdef _ZFS_LITTLE_ENDIAN459counter = ntohll(ctx->ccm_cb[1] & ctx->ccm_counter_mask);460counter = htonll(counter + 1);461#else462counter = ctx->ccm_cb[1] & ctx->ccm_counter_mask;463counter++;464#endif /* _ZFS_LITTLE_ENDIAN */465counter &= ctx->ccm_counter_mask;466ctx->ccm_cb[1] =467(ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;468469/* XOR with the ciphertext */470xor_block(blockp, cbp);471472/* Copy the plaintext to the "holding buffer" */473resultp = (uint8_t *)ctx->ccm_pt_buf +474ctx->ccm_processed_data_len;475copy_block(cbp, resultp);476477ctx->ccm_processed_data_len += block_size;478479ctx->ccm_lastp = blockp;480481/* Update pointer to next block of data to be processed. */482if (ctx->ccm_remainder_len != 0) {483datap += need;484ctx->ccm_remainder_len = 0;485} else {486datap += block_size;487}488489remainder = (size_t)&data[length] - (size_t)datap;490491/* Incomplete last block */492if (remainder > 0 && remainder < block_size) {493memcpy(ctx->ccm_remainder, datap, remainder);494ctx->ccm_remainder_len = remainder;495ctx->ccm_copy_to = datap;496if (ctx->ccm_processed_mac_len > 0) {497/*498* not expecting anymore ciphertext, just499* compute plaintext for the remaining input500*/501ccm_decrypt_incomplete_block(ctx,502encrypt_block);503ctx->ccm_processed_data_len += remainder;504ctx->ccm_remainder_len = 0;505}506goto out;507}508ctx->ccm_copy_to = NULL;509510} while (remainder > 0);511512out:513return (CRYPTO_SUCCESS);514}515516int517ccm_decrypt_final(ccm_ctx_t *ctx, crypto_data_t *out, size_t block_size,518int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),519void (*copy_block)(uint8_t *, uint8_t *),520void (*xor_block)(uint8_t *, uint8_t *))521{522size_t mac_remain, pt_len;523uint8_t *pt, *mac_buf, *macp, *ccm_mac_p;524int rv;525526pt_len = ctx->ccm_data_len;527528/* Make sure output buffer can fit all of the plaintext */529if (out->cd_length < pt_len) {530return (CRYPTO_DATA_LEN_RANGE);531}532533pt = ctx->ccm_pt_buf;534mac_remain = ctx->ccm_processed_data_len;535mac_buf = (uint8_t *)ctx->ccm_mac_buf;536537macp = (uint8_t *)ctx->ccm_tmp;538539while (mac_remain > 0) {540if (mac_remain < block_size) {541memset(macp, 0, block_size);542memcpy(macp, pt, mac_remain);543mac_remain = 0;544} else {545copy_block(pt, macp);546mac_remain -= block_size;547pt += block_size;548}549550/* calculate the CBC MAC */551xor_block(macp, mac_buf);552encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);553}554555/* Calculate the CCM MAC */556ccm_mac_p = (uint8_t *)ctx->ccm_tmp;557calculate_ccm_mac((ccm_ctx_t *)ctx, ccm_mac_p, encrypt_block);558559/* compare the input CCM MAC value with what we calculated */560if (memcmp(ctx->ccm_mac_input_buf, ccm_mac_p, ctx->ccm_mac_len)) {561/* They don't match */562return (CRYPTO_INVALID_MAC);563} else {564rv = crypto_put_output_data(ctx->ccm_pt_buf, out, pt_len);565if (rv != CRYPTO_SUCCESS)566return (rv);567out->cd_offset += pt_len;568}569return (CRYPTO_SUCCESS);570}571572static int573ccm_validate_args(CK_AES_CCM_PARAMS *ccm_param, boolean_t is_encrypt_init)574{575size_t macSize, nonceSize;576uint8_t q;577uint64_t maxValue;578579/*580* Check the length of the MAC. The only valid581* lengths for the MAC are: 4, 6, 8, 10, 12, 14, 16582*/583macSize = ccm_param->ulMACSize;584if ((macSize < 4) || (macSize > 16) || ((macSize % 2) != 0)) {585return (CRYPTO_MECHANISM_PARAM_INVALID);586}587588/* Check the nonce length. Valid values are 7, 8, 9, 10, 11, 12, 13 */589nonceSize = ccm_param->ulNonceSize;590if ((nonceSize < 7) || (nonceSize > 13)) {591return (CRYPTO_MECHANISM_PARAM_INVALID);592}593594/* q is the length of the field storing the length, in bytes */595q = (uint8_t)((15 - nonceSize) & 0xFF);596597598/*599* If it is decrypt, need to make sure size of ciphertext is at least600* bigger than MAC len601*/602if ((!is_encrypt_init) && (ccm_param->ulDataSize < macSize)) {603return (CRYPTO_MECHANISM_PARAM_INVALID);604}605606/*607* Check to make sure the length of the payload is within the608* range of values allowed by q609*/610if (q < 8) {611maxValue = (1ULL << (q * 8)) - 1;612} else {613maxValue = ULONG_MAX;614}615616if (ccm_param->ulDataSize > maxValue) {617return (CRYPTO_MECHANISM_PARAM_INVALID);618}619return (CRYPTO_SUCCESS);620}621622/*623* Format the first block used in CBC-MAC (B0) and the initial counter624* block based on formatting functions and counter generation functions625* specified in RFC 3610 and NIST publication 800-38C, appendix A626*627* b0 is the first block used in CBC-MAC628* cb0 is the first counter block629*630* It's assumed that the arguments b0 and cb0 are preallocated AES blocks631*632*/633static void634ccm_format_initial_blocks(uchar_t *nonce, ulong_t nonceSize,635ulong_t authDataSize, uint8_t *b0, ccm_ctx_t *aes_ctx)636{637uint64_t payloadSize;638uint8_t t, q, have_adata = 0;639size_t limit;640int i, j, k;641uint64_t mask = 0;642uint8_t *cb;643644q = (uint8_t)((15 - nonceSize) & 0xFF);645t = (uint8_t)((aes_ctx->ccm_mac_len) & 0xFF);646647/* Construct the first octet of b0 */648if (authDataSize > 0) {649have_adata = 1;650}651b0[0] = (have_adata << 6) | (((t - 2) / 2) << 3) | (q - 1);652653/* copy the nonce value into b0 */654memcpy(&(b0[1]), nonce, nonceSize);655656/* store the length of the payload into b0 */657memset(&(b0[1+nonceSize]), 0, q);658659payloadSize = aes_ctx->ccm_data_len;660limit = MIN(8, q);661662for (i = 0, j = 0, k = 15; i < limit; i++, j += 8, k--) {663b0[k] = (uint8_t)((payloadSize >> j) & 0xFF);664}665666/* format the counter block */667668cb = (uint8_t *)aes_ctx->ccm_cb;669670cb[0] = 0x07 & (q-1); /* first byte */671672/* copy the nonce value into the counter block */673memcpy(&(cb[1]), nonce, nonceSize);674675memset(&(cb[1+nonceSize]), 0, q);676677/* Create the mask for the counter field based on the size of nonce */678q <<= 3;679while (q-- > 0) {680mask |= (1ULL << q);681}682683#ifdef _ZFS_LITTLE_ENDIAN684mask = htonll(mask);685#endif686aes_ctx->ccm_counter_mask = mask;687688/*689* During calculation, we start using counter block 1, we will690* set it up right here.691* We can just set the last byte to have the value 1, because692* even with the biggest nonce of 13, the last byte of the693* counter block will be used for the counter value.694*/695cb[15] = 0x01;696}697698/*699* Encode the length of the associated data as700* specified in RFC 3610 and NIST publication 800-38C, appendix A701*/702static void703encode_adata_len(ulong_t auth_data_len, uint8_t *encoded, size_t *encoded_len)704{705#ifdef UNALIGNED_POINTERS_PERMITTED706uint32_t *lencoded_ptr;707#ifdef _LP64708uint64_t *llencoded_ptr;709#endif710#endif /* UNALIGNED_POINTERS_PERMITTED */711712if (auth_data_len < ((1ULL<<16) - (1ULL<<8))) {713/* 0 < a < (2^16-2^8) */714*encoded_len = 2;715encoded[0] = (auth_data_len & 0xff00) >> 8;716encoded[1] = auth_data_len & 0xff;717718} else if ((auth_data_len >= ((1ULL<<16) - (1ULL<<8))) &&719(auth_data_len < (1ULL << 31))) {720/* (2^16-2^8) <= a < 2^32 */721*encoded_len = 6;722encoded[0] = 0xff;723encoded[1] = 0xfe;724#ifdef UNALIGNED_POINTERS_PERMITTED725lencoded_ptr = (uint32_t *)&encoded[2];726*lencoded_ptr = htonl(auth_data_len);727#else728encoded[2] = (auth_data_len & 0xff000000) >> 24;729encoded[3] = (auth_data_len & 0xff0000) >> 16;730encoded[4] = (auth_data_len & 0xff00) >> 8;731encoded[5] = auth_data_len & 0xff;732#endif /* UNALIGNED_POINTERS_PERMITTED */733734#ifdef _LP64735} else {736/* 2^32 <= a < 2^64 */737*encoded_len = 10;738encoded[0] = 0xff;739encoded[1] = 0xff;740#ifdef UNALIGNED_POINTERS_PERMITTED741llencoded_ptr = (uint64_t *)&encoded[2];742*llencoded_ptr = htonl(auth_data_len);743#else744encoded[2] = (auth_data_len & 0xff00000000000000) >> 56;745encoded[3] = (auth_data_len & 0xff000000000000) >> 48;746encoded[4] = (auth_data_len & 0xff0000000000) >> 40;747encoded[5] = (auth_data_len & 0xff00000000) >> 32;748encoded[6] = (auth_data_len & 0xff000000) >> 24;749encoded[7] = (auth_data_len & 0xff0000) >> 16;750encoded[8] = (auth_data_len & 0xff00) >> 8;751encoded[9] = auth_data_len & 0xff;752#endif /* UNALIGNED_POINTERS_PERMITTED */753#endif /* _LP64 */754}755}756757static int758ccm_init(ccm_ctx_t *ctx, unsigned char *nonce, size_t nonce_len,759unsigned char *auth_data, size_t auth_data_len, size_t block_size,760int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),761void (*xor_block)(uint8_t *, uint8_t *))762{763uint8_t *mac_buf, *datap, *ivp, *authp;764size_t remainder, processed;765uint8_t encoded_a[10]; /* max encoded auth data length is 10 octets */766size_t encoded_a_len = 0;767768mac_buf = (uint8_t *)&(ctx->ccm_mac_buf);769770/*771* Format the 1st block for CBC-MAC and construct the772* 1st counter block.773*774* aes_ctx->ccm_iv is used for storing the counter block775* mac_buf will store b0 at this time.776*/777ccm_format_initial_blocks(nonce, nonce_len,778auth_data_len, mac_buf, ctx);779780/* The IV for CBC MAC for AES CCM mode is always zero */781ivp = (uint8_t *)ctx->ccm_tmp;782memset(ivp, 0, block_size);783784xor_block(ivp, mac_buf);785786/* encrypt the nonce */787encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);788789/* take care of the associated data, if any */790if (auth_data_len == 0) {791return (CRYPTO_SUCCESS);792}793794encode_adata_len(auth_data_len, encoded_a, &encoded_a_len);795796remainder = auth_data_len;797798/* 1st block: it contains encoded associated data, and some data */799authp = (uint8_t *)ctx->ccm_tmp;800memset(authp, 0, block_size);801memcpy(authp, encoded_a, encoded_a_len);802processed = block_size - encoded_a_len;803if (processed > auth_data_len) {804/* in case auth_data is very small */805processed = auth_data_len;806}807memcpy(authp+encoded_a_len, auth_data, processed);808/* xor with previous buffer */809xor_block(authp, mac_buf);810encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);811remainder -= processed;812if (remainder == 0) {813/* a small amount of associated data, it's all done now */814return (CRYPTO_SUCCESS);815}816817do {818if (remainder < block_size) {819/*820* There's not a block full of data, pad rest of821* buffer with zero822*/823memset(authp, 0, block_size);824memcpy(authp, &(auth_data[processed]), remainder);825datap = (uint8_t *)authp;826remainder = 0;827} else {828datap = (uint8_t *)(&(auth_data[processed]));829processed += block_size;830remainder -= block_size;831}832833xor_block(datap, mac_buf);834encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);835836} while (remainder > 0);837838return (CRYPTO_SUCCESS);839}840841/*842* The following function should be call at encrypt or decrypt init time843* for AES CCM mode.844*/845int846ccm_init_ctx(ccm_ctx_t *ccm_ctx, char *param, int kmflag,847boolean_t is_encrypt_init, size_t block_size,848int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),849void (*xor_block)(uint8_t *, uint8_t *))850{851int rv;852CK_AES_CCM_PARAMS *ccm_param;853854if (param != NULL) {855ccm_param = (CK_AES_CCM_PARAMS *)param;856857if ((rv = ccm_validate_args(ccm_param,858is_encrypt_init)) != 0) {859return (rv);860}861862ccm_ctx->ccm_mac_len = ccm_param->ulMACSize;863if (is_encrypt_init) {864ccm_ctx->ccm_data_len = ccm_param->ulDataSize;865} else {866ccm_ctx->ccm_data_len =867ccm_param->ulDataSize - ccm_ctx->ccm_mac_len;868ccm_ctx->ccm_processed_mac_len = 0;869}870ccm_ctx->ccm_processed_data_len = 0;871872ccm_ctx->ccm_flags |= CCM_MODE;873} else {874return (CRYPTO_MECHANISM_PARAM_INVALID);875}876877if (ccm_init(ccm_ctx, ccm_param->nonce, ccm_param->ulNonceSize,878ccm_param->authData, ccm_param->ulAuthDataSize, block_size,879encrypt_block, xor_block) != 0) {880return (CRYPTO_MECHANISM_PARAM_INVALID);881}882if (!is_encrypt_init) {883/* allocate buffer for storing decrypted plaintext */884ccm_ctx->ccm_pt_buf = vmem_alloc(ccm_ctx->ccm_data_len,885kmflag);886if (ccm_ctx->ccm_pt_buf == NULL) {887rv = CRYPTO_HOST_MEMORY;888}889}890return (rv);891}892893void *894ccm_alloc_ctx(int kmflag)895{896ccm_ctx_t *ccm_ctx;897898if ((ccm_ctx = kmem_zalloc(sizeof (ccm_ctx_t), kmflag)) == NULL)899return (NULL);900901ccm_ctx->ccm_flags = CCM_MODE;902return (ccm_ctx);903}904905906