17188Smcpowers /* 27188Smcpowers * CDDL HEADER START 37188Smcpowers * 47188Smcpowers * The contents of this file are subject to the terms of the 57188Smcpowers * Common Development and Distribution License (the "License"). 67188Smcpowers * You may not use this file except in compliance with the License. 77188Smcpowers * 87188Smcpowers * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97188Smcpowers * or http://www.opensolaris.org/os/licensing. 107188Smcpowers * See the License for the specific language governing permissions 117188Smcpowers * and limitations under the License. 127188Smcpowers * 137188Smcpowers * When distributing Covered Code, include this CDDL HEADER in each 147188Smcpowers * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157188Smcpowers * If applicable, add the following below this CDDL HEADER, with the 167188Smcpowers * fields enclosed by brackets "[]" replaced with your own identifying 177188Smcpowers * information: Portions Copyright [yyyy] [name of copyright owner] 187188Smcpowers * 197188Smcpowers * CDDL HEADER END 207188Smcpowers */ 217188Smcpowers /* 227188Smcpowers * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237188Smcpowers * Use is subject to license terms. 247188Smcpowers */ 257188Smcpowers 267188Smcpowers #ifndef _KERNEL 277188Smcpowers #include <strings.h> 287188Smcpowers #include <limits.h> 297188Smcpowers #include <assert.h> 307188Smcpowers #include <security/cryptoki.h> 317188Smcpowers #endif 327188Smcpowers 337188Smcpowers #include <sys/types.h> 347188Smcpowers #include <sys/kmem.h> 357188Smcpowers #include <modes/modes.h> 367188Smcpowers #include <sys/crypto/common.h> 377188Smcpowers #include <sys/crypto/impl.h> 387188Smcpowers 39*7421SDaniel.Anderson@Sun.COM #if defined(__i386) || defined(__amd64) 40*7421SDaniel.Anderson@Sun.COM #include <sys/byteorder.h> 41*7421SDaniel.Anderson@Sun.COM #define UNALIGNED_POINTERS_PERMITTED 42*7421SDaniel.Anderson@Sun.COM #endif 43*7421SDaniel.Anderson@Sun.COM 447188Smcpowers /* 457188Smcpowers * Encrypt multiple blocks of data in CCM mode. Decrypt for CCM mode 467188Smcpowers * is done in another function. 477188Smcpowers */ 487188Smcpowers int 497188Smcpowers ccm_mode_encrypt_contiguous_blocks(ccm_ctx_t *ctx, char *data, size_t length, 507188Smcpowers crypto_data_t *out, size_t block_size, 517188Smcpowers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 527188Smcpowers void (*copy_block)(uint8_t *, uint8_t *), 537188Smcpowers void (*xor_block)(uint8_t *, uint8_t *)) 547188Smcpowers { 557188Smcpowers size_t remainder = length; 567188Smcpowers size_t need; 577188Smcpowers uint8_t *datap = (uint8_t *)data; 587188Smcpowers uint8_t *blockp; 597188Smcpowers uint8_t *lastp; 607188Smcpowers void *iov_or_mp; 617188Smcpowers offset_t offset; 627188Smcpowers uint8_t *out_data_1; 637188Smcpowers uint8_t *out_data_2; 647188Smcpowers size_t out_data_1_len; 657188Smcpowers uint64_t counter; 667188Smcpowers uint8_t *mac_buf; 677188Smcpowers 687188Smcpowers if (length + ctx->ccm_remainder_len < block_size) { 697188Smcpowers /* accumulate bytes here and return */ 707188Smcpowers bcopy(datap, 717188Smcpowers (uint8_t *)ctx->ccm_remainder + ctx->ccm_remainder_len, 727188Smcpowers length); 737188Smcpowers ctx->ccm_remainder_len += length; 747188Smcpowers ctx->ccm_copy_to = datap; 757188Smcpowers return (CRYPTO_SUCCESS); 767188Smcpowers } 777188Smcpowers 787188Smcpowers lastp = (uint8_t *)ctx->ccm_cb; 797188Smcpowers if (out != NULL) 807188Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset); 817188Smcpowers 827188Smcpowers mac_buf = (uint8_t *)ctx->ccm_mac_buf; 837188Smcpowers 847188Smcpowers do { 857188Smcpowers /* Unprocessed data from last call. */ 867188Smcpowers if (ctx->ccm_remainder_len > 0) { 877188Smcpowers need = block_size - ctx->ccm_remainder_len; 887188Smcpowers 897188Smcpowers if (need > remainder) 907188Smcpowers return (CRYPTO_DATA_LEN_RANGE); 917188Smcpowers 927188Smcpowers bcopy(datap, &((uint8_t *)ctx->ccm_remainder) 937188Smcpowers [ctx->ccm_remainder_len], need); 947188Smcpowers 957188Smcpowers blockp = (uint8_t *)ctx->ccm_remainder; 967188Smcpowers } else { 977188Smcpowers blockp = datap; 987188Smcpowers } 997188Smcpowers 1007188Smcpowers /* 1017188Smcpowers * do CBC MAC 1027188Smcpowers * 1037188Smcpowers * XOR the previous cipher block current clear block. 1047188Smcpowers * mac_buf always contain previous cipher block. 1057188Smcpowers */ 1067188Smcpowers xor_block(blockp, mac_buf); 1077188Smcpowers encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf); 1087188Smcpowers 1097188Smcpowers /* ccm_cb is the counter block */ 1107188Smcpowers encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, 1117188Smcpowers (uint8_t *)ctx->ccm_tmp); 1127188Smcpowers 1137188Smcpowers lastp = (uint8_t *)ctx->ccm_tmp; 1147188Smcpowers 1157188Smcpowers /* 1167188Smcpowers * Increment counter. Counter bits are confined 1177188Smcpowers * to the bottom 64 bits of the counter block. 1187188Smcpowers */ 119*7421SDaniel.Anderson@Sun.COM #ifdef _LITTLE_ENDIAN 120*7421SDaniel.Anderson@Sun.COM counter = ntohll(ctx->ccm_cb[1] & ctx->ccm_counter_mask); 121*7421SDaniel.Anderson@Sun.COM counter = htonll(counter + 1); 122*7421SDaniel.Anderson@Sun.COM #else 1237188Smcpowers counter = ctx->ccm_cb[1] & ctx->ccm_counter_mask; 1247188Smcpowers counter++; 125*7421SDaniel.Anderson@Sun.COM #endif /* _LITTLE_ENDIAN */ 1267188Smcpowers counter &= ctx->ccm_counter_mask; 1277188Smcpowers ctx->ccm_cb[1] = 1287188Smcpowers (ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter; 1297188Smcpowers 1307188Smcpowers /* 1317329SMark.Powers@Sun.COM * XOR encrypted counter block with the current clear block. 1327188Smcpowers */ 1337329SMark.Powers@Sun.COM xor_block(blockp, lastp); 1347188Smcpowers 1357188Smcpowers ctx->ccm_processed_data_len += block_size; 1367188Smcpowers 1377188Smcpowers if (out == NULL) { 1387188Smcpowers if (ctx->ccm_remainder_len > 0) { 1397188Smcpowers bcopy(blockp, ctx->ccm_copy_to, 1407188Smcpowers ctx->ccm_remainder_len); 1417188Smcpowers bcopy(blockp + ctx->ccm_remainder_len, datap, 1427188Smcpowers need); 1437188Smcpowers } 1447188Smcpowers } else { 1457188Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 1467188Smcpowers &out_data_1_len, &out_data_2, block_size); 1477188Smcpowers 1487188Smcpowers /* copy block to where it belongs */ 1497188Smcpowers if (out_data_1_len == block_size) { 1507188Smcpowers copy_block(lastp, out_data_1); 1517188Smcpowers } else { 1527188Smcpowers bcopy(lastp, out_data_1, out_data_1_len); 1537188Smcpowers if (out_data_2 != NULL) { 1547188Smcpowers bcopy(lastp + out_data_1_len, 1557188Smcpowers out_data_2, 1567188Smcpowers block_size - out_data_1_len); 1577188Smcpowers } 1587188Smcpowers } 1597188Smcpowers /* update offset */ 1607188Smcpowers out->cd_offset += block_size; 1617188Smcpowers } 1627188Smcpowers 1637188Smcpowers /* Update pointer to next block of data to be processed. */ 1647188Smcpowers if (ctx->ccm_remainder_len != 0) { 1657188Smcpowers datap += need; 1667188Smcpowers ctx->ccm_remainder_len = 0; 1677188Smcpowers } else { 1687188Smcpowers datap += block_size; 1697188Smcpowers } 1707188Smcpowers 1717188Smcpowers remainder = (size_t)&data[length] - (size_t)datap; 1727188Smcpowers 1737188Smcpowers /* Incomplete last block. */ 1747188Smcpowers if (remainder > 0 && remainder < block_size) { 1757188Smcpowers bcopy(datap, ctx->ccm_remainder, remainder); 1767188Smcpowers ctx->ccm_remainder_len = remainder; 1777188Smcpowers ctx->ccm_copy_to = datap; 1787188Smcpowers goto out; 1797188Smcpowers } 1807188Smcpowers ctx->ccm_copy_to = NULL; 1817188Smcpowers 1827188Smcpowers } while (remainder > 0); 1837188Smcpowers 1847188Smcpowers out: 1857188Smcpowers return (CRYPTO_SUCCESS); 1867188Smcpowers } 1877188Smcpowers 1887188Smcpowers void 1897188Smcpowers calculate_ccm_mac(ccm_ctx_t *ctx, uint8_t *ccm_mac, 1907188Smcpowers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *)) 1917188Smcpowers { 1927188Smcpowers uint64_t counter; 1937188Smcpowers uint8_t *counterp, *mac_buf; 1947188Smcpowers int i; 1957188Smcpowers 1967188Smcpowers mac_buf = (uint8_t *)ctx->ccm_mac_buf; 1977188Smcpowers 1987188Smcpowers /* first counter block start with index 0 */ 1997188Smcpowers counter = 0; 2007188Smcpowers ctx->ccm_cb[1] = (ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter; 2017188Smcpowers 2027188Smcpowers counterp = (uint8_t *)ctx->ccm_tmp; 2037188Smcpowers encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, counterp); 2047188Smcpowers 2057188Smcpowers /* calculate XOR of MAC with first counter block */ 2067188Smcpowers for (i = 0; i < ctx->ccm_mac_len; i++) { 2077188Smcpowers ccm_mac[i] = mac_buf[i] ^ counterp[i]; 2087188Smcpowers } 2097188Smcpowers } 2107188Smcpowers 2117188Smcpowers /* ARGSUSED */ 2127188Smcpowers int 2137188Smcpowers ccm_encrypt_final(ccm_ctx_t *ctx, crypto_data_t *out, size_t block_size, 2147188Smcpowers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 2157188Smcpowers void (*xor_block)(uint8_t *, uint8_t *)) 2167188Smcpowers { 2177188Smcpowers uint8_t *lastp, *mac_buf, *ccm_mac_p, *macp; 2187188Smcpowers void *iov_or_mp; 2197188Smcpowers offset_t offset; 2207188Smcpowers uint8_t *out_data_1; 2217188Smcpowers uint8_t *out_data_2; 2227188Smcpowers size_t out_data_1_len; 2237188Smcpowers int i; 2247188Smcpowers 2257188Smcpowers if (out->cd_length < (ctx->ccm_remainder_len + ctx->ccm_mac_len)) { 2267188Smcpowers return (CRYPTO_DATA_LEN_RANGE); 2277188Smcpowers } 2287188Smcpowers 2297188Smcpowers /* 2307188Smcpowers * When we get here, the number of bytes of payload processed 2317188Smcpowers * plus whatever data remains, if any, 2327188Smcpowers * should be the same as the number of bytes that's being 2337188Smcpowers * passed in the argument during init time. 2347188Smcpowers */ 2357188Smcpowers if ((ctx->ccm_processed_data_len + ctx->ccm_remainder_len) 2367188Smcpowers != (ctx->ccm_data_len)) { 2377188Smcpowers return (CRYPTO_DATA_LEN_RANGE); 2387188Smcpowers } 2397188Smcpowers 2407188Smcpowers mac_buf = (uint8_t *)ctx->ccm_mac_buf; 2417188Smcpowers 2427188Smcpowers if (ctx->ccm_remainder_len > 0) { 2437188Smcpowers 2447188Smcpowers /* ccm_mac_input_buf is not used for encryption */ 2457188Smcpowers macp = (uint8_t *)ctx->ccm_mac_input_buf; 2467188Smcpowers bzero(macp, block_size); 2477188Smcpowers 2487188Smcpowers /* copy remainder to temporary buffer */ 2497188Smcpowers bcopy(ctx->ccm_remainder, macp, ctx->ccm_remainder_len); 2507188Smcpowers 2517188Smcpowers /* calculate the CBC MAC */ 2527188Smcpowers xor_block(macp, mac_buf); 2537188Smcpowers encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf); 2547188Smcpowers 2557188Smcpowers /* calculate the counter mode */ 2567188Smcpowers lastp = (uint8_t *)ctx->ccm_tmp; 2577188Smcpowers encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, lastp); 2587188Smcpowers 2597188Smcpowers /* XOR with counter block */ 2607188Smcpowers for (i = 0; i < ctx->ccm_remainder_len; i++) { 2617188Smcpowers macp[i] ^= lastp[i]; 2627188Smcpowers } 2637188Smcpowers ctx->ccm_processed_data_len += ctx->ccm_remainder_len; 2647188Smcpowers } 2657188Smcpowers 2667188Smcpowers /* Calculate the CCM MAC */ 2677188Smcpowers ccm_mac_p = (uint8_t *)ctx->ccm_tmp; 2687188Smcpowers calculate_ccm_mac(ctx, ccm_mac_p, encrypt_block); 2697188Smcpowers 2707188Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset); 2717188Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 2727188Smcpowers &out_data_1_len, &out_data_2, 2737188Smcpowers ctx->ccm_remainder_len + ctx->ccm_mac_len); 2747188Smcpowers 2757188Smcpowers if (ctx->ccm_remainder_len > 0) { 2767188Smcpowers 2777188Smcpowers /* copy temporary block to where it belongs */ 2787188Smcpowers if (out_data_2 == NULL) { 2797188Smcpowers /* everything will fit in out_data_1 */ 2807188Smcpowers bcopy(macp, out_data_1, ctx->ccm_remainder_len); 2817188Smcpowers bcopy(ccm_mac_p, out_data_1 + ctx->ccm_remainder_len, 2827188Smcpowers ctx->ccm_mac_len); 2837188Smcpowers } else { 2847188Smcpowers 2857188Smcpowers if (out_data_1_len < ctx->ccm_remainder_len) { 2867188Smcpowers 2877188Smcpowers size_t data_2_len_used; 2887188Smcpowers 2897188Smcpowers bcopy(macp, out_data_1, out_data_1_len); 2907188Smcpowers 2917188Smcpowers data_2_len_used = ctx->ccm_remainder_len 2927188Smcpowers - out_data_1_len; 2937188Smcpowers 2947188Smcpowers bcopy((uint8_t *)macp + out_data_1_len, 2957188Smcpowers out_data_2, data_2_len_used); 2967188Smcpowers bcopy(ccm_mac_p, out_data_2 + data_2_len_used, 2977188Smcpowers ctx->ccm_mac_len); 2987188Smcpowers } else { 2997188Smcpowers bcopy(macp, out_data_1, out_data_1_len); 3007188Smcpowers if (out_data_1_len == ctx->ccm_remainder_len) { 3017188Smcpowers /* mac will be in out_data_2 */ 3027188Smcpowers bcopy(ccm_mac_p, out_data_2, 3037188Smcpowers ctx->ccm_mac_len); 3047188Smcpowers } else { 305*7421SDaniel.Anderson@Sun.COM size_t len_not_used = out_data_1_len - 3067188Smcpowers ctx->ccm_remainder_len; 3077188Smcpowers /* 3087188Smcpowers * part of mac in will be in 3097188Smcpowers * out_data_1, part of the mac will be 3107188Smcpowers * in out_data_2 3117188Smcpowers */ 3127188Smcpowers bcopy(ccm_mac_p, 3137188Smcpowers out_data_1 + ctx->ccm_remainder_len, 3147188Smcpowers len_not_used); 3157188Smcpowers bcopy(ccm_mac_p + len_not_used, 3167188Smcpowers out_data_2, 3177188Smcpowers ctx->ccm_mac_len - len_not_used); 3187188Smcpowers 3197188Smcpowers } 3207188Smcpowers } 3217188Smcpowers } 3227188Smcpowers } else { 3237188Smcpowers /* copy block to where it belongs */ 3247188Smcpowers bcopy(ccm_mac_p, out_data_1, out_data_1_len); 3257188Smcpowers if (out_data_2 != NULL) { 3267188Smcpowers bcopy(ccm_mac_p + out_data_1_len, out_data_2, 3277188Smcpowers block_size - out_data_1_len); 3287188Smcpowers } 3297188Smcpowers } 3307188Smcpowers out->cd_offset += ctx->ccm_remainder_len + ctx->ccm_mac_len; 3317188Smcpowers ctx->ccm_remainder_len = 0; 3327188Smcpowers return (CRYPTO_SUCCESS); 3337188Smcpowers } 3347188Smcpowers 3357188Smcpowers /* 3367188Smcpowers * This will only deal with decrypting the last block of the input that 3377188Smcpowers * might not be a multiple of block length. 3387188Smcpowers */ 3397188Smcpowers void 3407188Smcpowers ccm_decrypt_incomplete_block(ccm_ctx_t *ctx, 3417188Smcpowers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *)) 3427188Smcpowers { 3437188Smcpowers uint8_t *datap, *outp, *counterp; 3447188Smcpowers int i; 3457188Smcpowers 3467188Smcpowers datap = (uint8_t *)ctx->ccm_remainder; 3477188Smcpowers outp = &((ctx->ccm_pt_buf)[ctx->ccm_processed_data_len]); 3487188Smcpowers 3497188Smcpowers counterp = (uint8_t *)ctx->ccm_tmp; 3507188Smcpowers encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, counterp); 3517188Smcpowers 3527188Smcpowers /* XOR with counter block */ 3537188Smcpowers for (i = 0; i < ctx->ccm_remainder_len; i++) { 3547188Smcpowers outp[i] = datap[i] ^ counterp[i]; 3557188Smcpowers } 3567188Smcpowers } 3577188Smcpowers 3587188Smcpowers /* 3597188Smcpowers * This will decrypt the cipher text. However, the plaintext won't be 3607188Smcpowers * returned to the caller. It will be returned when decrypt_final() is 3617188Smcpowers * called if the MAC matches 3627188Smcpowers */ 3637188Smcpowers /* ARGSUSED */ 3647188Smcpowers int 3657188Smcpowers ccm_mode_decrypt_contiguous_blocks(ccm_ctx_t *ctx, char *data, size_t length, 3667188Smcpowers crypto_data_t *out, size_t block_size, 3677188Smcpowers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 3687188Smcpowers void (*copy_block)(uint8_t *, uint8_t *), 3697188Smcpowers void (*xor_block)(uint8_t *, uint8_t *)) 3707188Smcpowers { 3717188Smcpowers size_t remainder = length; 3727188Smcpowers size_t need; 3737188Smcpowers uint8_t *datap = (uint8_t *)data; 3747188Smcpowers uint8_t *blockp; 3757188Smcpowers uint8_t *cbp; 3767188Smcpowers uint64_t counter; 3777188Smcpowers size_t pt_len, total_decrypted_len, mac_len, pm_len, pd_len; 3787188Smcpowers uint8_t *resultp; 3797188Smcpowers #ifdef _LITTLE_ENDIAN 3807188Smcpowers uint8_t *p; 3817188Smcpowers #endif /* _LITTLE_ENDIAN */ 3827188Smcpowers 3837188Smcpowers 3847188Smcpowers pm_len = ctx->ccm_processed_mac_len; 3857188Smcpowers 3867188Smcpowers if (pm_len > 0) { 3877188Smcpowers uint8_t *tmp; 3887188Smcpowers /* 3897188Smcpowers * all ciphertext has been processed, just waiting for 3907188Smcpowers * part of the value of the mac 3917188Smcpowers */ 3927188Smcpowers if ((pm_len + length) > ctx->ccm_mac_len) { 3937188Smcpowers return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE); 3947188Smcpowers } 3957188Smcpowers tmp = (uint8_t *)ctx->ccm_mac_input_buf; 3967188Smcpowers 3977188Smcpowers bcopy(datap, tmp + pm_len, length); 3987188Smcpowers 3997188Smcpowers ctx->ccm_processed_mac_len += length; 4007188Smcpowers return (CRYPTO_SUCCESS); 4017188Smcpowers } 4027188Smcpowers 4037188Smcpowers /* 4047188Smcpowers * If we decrypt the given data, what total amount of data would 4057188Smcpowers * have been decrypted? 4067188Smcpowers */ 4077188Smcpowers pd_len = ctx->ccm_processed_data_len; 4087188Smcpowers total_decrypted_len = pd_len + length + ctx->ccm_remainder_len; 4097188Smcpowers 4107188Smcpowers if (total_decrypted_len > 4117188Smcpowers (ctx->ccm_data_len + ctx->ccm_mac_len)) { 4127188Smcpowers return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE); 4137188Smcpowers } 4147188Smcpowers 4157188Smcpowers pt_len = ctx->ccm_data_len; 4167188Smcpowers 4177188Smcpowers if (total_decrypted_len > pt_len) { 4187188Smcpowers /* 4197188Smcpowers * part of the input will be the MAC, need to isolate that 4207188Smcpowers * to be dealt with later. The left-over data in 4217188Smcpowers * ccm_remainder_len from last time will not be part of the 4227188Smcpowers * MAC. Otherwise, it would have already been taken out 4237188Smcpowers * when this call is made last time. 4247188Smcpowers */ 4257188Smcpowers size_t pt_part = pt_len - pd_len - ctx->ccm_remainder_len; 4267188Smcpowers 4277188Smcpowers mac_len = length - pt_part; 4287188Smcpowers 4297188Smcpowers ctx->ccm_processed_mac_len = mac_len; 4307188Smcpowers bcopy(data + pt_part, ctx->ccm_mac_input_buf, mac_len); 4317188Smcpowers 4327188Smcpowers if (pt_part + ctx->ccm_remainder_len < block_size) { 4337188Smcpowers /* 4347188Smcpowers * since this is last of the ciphertext, will 4357188Smcpowers * just decrypt with it here 4367188Smcpowers */ 4377188Smcpowers bcopy(datap, &((uint8_t *)ctx->ccm_remainder) 4387188Smcpowers [ctx->ccm_remainder_len], pt_part); 4397188Smcpowers ctx->ccm_remainder_len += pt_part; 4407188Smcpowers ccm_decrypt_incomplete_block(ctx, encrypt_block); 4417188Smcpowers ctx->ccm_remainder_len = 0; 4427188Smcpowers ctx->ccm_processed_data_len += pt_part; 4437188Smcpowers return (CRYPTO_SUCCESS); 4447188Smcpowers } else { 4457188Smcpowers /* let rest of the code handle this */ 4467188Smcpowers length = pt_part; 4477188Smcpowers } 4487188Smcpowers } else if (length + ctx->ccm_remainder_len < block_size) { 4497188Smcpowers /* accumulate bytes here and return */ 4507188Smcpowers bcopy(datap, 4517188Smcpowers (uint8_t *)ctx->ccm_remainder + ctx->ccm_remainder_len, 4527188Smcpowers length); 4537188Smcpowers ctx->ccm_remainder_len += length; 4547188Smcpowers ctx->ccm_copy_to = datap; 4557188Smcpowers return (CRYPTO_SUCCESS); 4567188Smcpowers } 4577188Smcpowers 4587188Smcpowers do { 4597188Smcpowers /* Unprocessed data from last call. */ 4607188Smcpowers if (ctx->ccm_remainder_len > 0) { 4617188Smcpowers need = block_size - ctx->ccm_remainder_len; 4627188Smcpowers 4637188Smcpowers if (need > remainder) 4647188Smcpowers return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE); 4657188Smcpowers 4667188Smcpowers bcopy(datap, &((uint8_t *)ctx->ccm_remainder) 4677188Smcpowers [ctx->ccm_remainder_len], need); 4687188Smcpowers 4697188Smcpowers blockp = (uint8_t *)ctx->ccm_remainder; 4707188Smcpowers } else { 4717188Smcpowers blockp = datap; 4727188Smcpowers } 4737188Smcpowers 4747188Smcpowers /* Calculate the counter mode, ccm_cb is the counter block */ 4757188Smcpowers cbp = (uint8_t *)ctx->ccm_tmp; 4767188Smcpowers encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, cbp); 4777188Smcpowers 4787188Smcpowers /* 4797188Smcpowers * Increment counter. 4807188Smcpowers * Counter bits are confined to the bottom 64 bits 4817188Smcpowers */ 482*7421SDaniel.Anderson@Sun.COM #ifdef _LITTLE_ENDIAN 483*7421SDaniel.Anderson@Sun.COM counter = ntohll(ctx->ccm_cb[1] & ctx->ccm_counter_mask); 484*7421SDaniel.Anderson@Sun.COM counter = htonll(counter + 1); 485*7421SDaniel.Anderson@Sun.COM #else 4867188Smcpowers counter = ctx->ccm_cb[1] & ctx->ccm_counter_mask; 4877188Smcpowers counter++; 488*7421SDaniel.Anderson@Sun.COM #endif /* _LITTLE_ENDIAN */ 4897188Smcpowers counter &= ctx->ccm_counter_mask; 4907188Smcpowers ctx->ccm_cb[1] = 4917188Smcpowers (ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter; 4927188Smcpowers 4937188Smcpowers /* XOR with the ciphertext */ 4947188Smcpowers xor_block(blockp, cbp); 4957188Smcpowers 4967188Smcpowers /* Copy the plaintext to the "holding buffer" */ 4977188Smcpowers resultp = (uint8_t *)ctx->ccm_pt_buf + 4987188Smcpowers ctx->ccm_processed_data_len; 4997188Smcpowers copy_block(cbp, resultp); 5007188Smcpowers 5017188Smcpowers ctx->ccm_processed_data_len += block_size; 5027188Smcpowers 5037188Smcpowers ctx->ccm_lastp = blockp; 5047188Smcpowers 5057188Smcpowers /* Update pointer to next block of data to be processed. */ 5067188Smcpowers if (ctx->ccm_remainder_len != 0) { 5077188Smcpowers datap += need; 5087188Smcpowers ctx->ccm_remainder_len = 0; 5097188Smcpowers } else { 5107188Smcpowers datap += block_size; 5117188Smcpowers } 5127188Smcpowers 5137188Smcpowers remainder = (size_t)&data[length] - (size_t)datap; 5147188Smcpowers 5157188Smcpowers /* Incomplete last block */ 5167188Smcpowers if (remainder > 0 && remainder < block_size) { 5177188Smcpowers bcopy(datap, ctx->ccm_remainder, remainder); 5187188Smcpowers ctx->ccm_remainder_len = remainder; 5197188Smcpowers ctx->ccm_copy_to = datap; 5207188Smcpowers if (ctx->ccm_processed_mac_len > 0) { 5217188Smcpowers /* 5227188Smcpowers * not expecting anymore ciphertext, just 5237188Smcpowers * compute plaintext for the remaining input 5247188Smcpowers */ 5257188Smcpowers ccm_decrypt_incomplete_block(ctx, 5267188Smcpowers encrypt_block); 5277188Smcpowers ctx->ccm_processed_data_len += remainder; 5287188Smcpowers ctx->ccm_remainder_len = 0; 5297188Smcpowers } 5307188Smcpowers goto out; 5317188Smcpowers } 5327188Smcpowers ctx->ccm_copy_to = NULL; 5337188Smcpowers 5347188Smcpowers } while (remainder > 0); 5357188Smcpowers 5367188Smcpowers out: 5377188Smcpowers return (CRYPTO_SUCCESS); 5387188Smcpowers } 5397188Smcpowers 5407188Smcpowers int 5417188Smcpowers ccm_decrypt_final(ccm_ctx_t *ctx, crypto_data_t *out, size_t block_size, 5427188Smcpowers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 5437188Smcpowers void (*copy_block)(uint8_t *, uint8_t *), 5447188Smcpowers void (*xor_block)(uint8_t *, uint8_t *)) 5457188Smcpowers { 5467188Smcpowers size_t mac_remain, pt_len; 5477188Smcpowers uint8_t *pt, *mac_buf, *macp, *ccm_mac_p; 5487188Smcpowers void *iov_or_mp; 5497188Smcpowers offset_t offset; 5507188Smcpowers uint8_t *out_data_1, *out_data_2; 5517188Smcpowers size_t out_data_1_len; 5527188Smcpowers 5537188Smcpowers pt_len = ctx->ccm_data_len; 5547188Smcpowers 5557188Smcpowers /* Make sure output buffer can fit all of the plaintext */ 5567188Smcpowers if (out->cd_length < pt_len) { 5577188Smcpowers return (CRYPTO_DATA_LEN_RANGE); 5587188Smcpowers } 5597188Smcpowers 5607188Smcpowers pt = ctx->ccm_pt_buf; 5617188Smcpowers mac_remain = ctx->ccm_processed_data_len; 5627188Smcpowers mac_buf = (uint8_t *)ctx->ccm_mac_buf; 5637188Smcpowers 5647188Smcpowers macp = (uint8_t *)ctx->ccm_tmp; 5657188Smcpowers 5667188Smcpowers while (mac_remain > 0) { 5677188Smcpowers 5687188Smcpowers if (mac_remain < block_size) { 5697188Smcpowers bzero(macp, block_size); 5707188Smcpowers bcopy(pt, macp, mac_remain); 5717188Smcpowers mac_remain = 0; 5727188Smcpowers } else { 5737188Smcpowers copy_block(pt, macp); 5747188Smcpowers mac_remain -= block_size; 5757188Smcpowers pt += block_size; 5767188Smcpowers } 5777188Smcpowers 5787188Smcpowers /* calculate the CBC MAC */ 5797188Smcpowers xor_block(macp, mac_buf); 5807188Smcpowers encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf); 5817188Smcpowers } 5827188Smcpowers 5837188Smcpowers /* Calculate the CCM MAC */ 5847188Smcpowers ccm_mac_p = (uint8_t *)ctx->ccm_tmp; 5857188Smcpowers calculate_ccm_mac((ccm_ctx_t *)ctx, ccm_mac_p, encrypt_block); 5867188Smcpowers 5877188Smcpowers /* compare the input CCM MAC value with what we calculated */ 5887188Smcpowers if (bcmp(ctx->ccm_mac_input_buf, ccm_mac_p, ctx->ccm_mac_len)) { 5897188Smcpowers /* They don't match */ 5907188Smcpowers return (CRYPTO_INVALID_MAC); 5917188Smcpowers } else { 5927188Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset); 5937188Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 5947188Smcpowers &out_data_1_len, &out_data_2, pt_len); 5957188Smcpowers bcopy(ctx->ccm_pt_buf, out_data_1, out_data_1_len); 5967188Smcpowers if (out_data_2 != NULL) { 5977188Smcpowers bcopy((ctx->ccm_pt_buf) + out_data_1_len, 5987188Smcpowers out_data_2, pt_len - out_data_1_len); 5997188Smcpowers } 6007188Smcpowers out->cd_offset += pt_len; 6017188Smcpowers } 6027188Smcpowers return (CRYPTO_SUCCESS); 6037188Smcpowers } 6047188Smcpowers 6057188Smcpowers int 6067188Smcpowers ccm_validate_args(CK_AES_CCM_PARAMS *ccm_param, boolean_t is_encrypt_init) 6077188Smcpowers { 6087188Smcpowers size_t macSize, nonceSize; 6097188Smcpowers uint8_t q; 6107188Smcpowers uint64_t maxValue; 6117188Smcpowers 6127188Smcpowers /* 6137188Smcpowers * Check the length of the MAC. The only valid 6147188Smcpowers * lengths for the MAC are: 4, 6, 8, 10, 12, 14, 16 6157188Smcpowers */ 6167188Smcpowers macSize = ccm_param->ulMACSize; 6177188Smcpowers if ((macSize < 4) || (macSize > 16) || ((macSize % 2) != 0)) { 6187188Smcpowers return (CRYPTO_MECHANISM_PARAM_INVALID); 6197188Smcpowers } 6207188Smcpowers 6217188Smcpowers /* Check the nonce length. Valid values are 7, 8, 9, 10, 11, 12, 13 */ 6227188Smcpowers nonceSize = ccm_param->ulNonceSize; 6237188Smcpowers if ((nonceSize < 7) || (nonceSize > 13)) { 6247188Smcpowers return (CRYPTO_MECHANISM_PARAM_INVALID); 6257188Smcpowers } 6267188Smcpowers 6277188Smcpowers /* q is the length of the field storing the length, in bytes */ 6287188Smcpowers q = (uint8_t)((15 - nonceSize) & 0xFF); 6297188Smcpowers 6307188Smcpowers 6317188Smcpowers /* 6327188Smcpowers * If it is decrypt, need to make sure size of ciphertext is at least 6337188Smcpowers * bigger than MAC len 6347188Smcpowers */ 6357188Smcpowers if ((!is_encrypt_init) && (ccm_param->ulDataSize < macSize)) { 6367188Smcpowers return (CRYPTO_MECHANISM_PARAM_INVALID); 6377188Smcpowers } 6387188Smcpowers 6397188Smcpowers /* 6407188Smcpowers * Check to make sure the length of the payload is within the 6417188Smcpowers * range of values allowed by q 6427188Smcpowers */ 6437188Smcpowers if (q < 8) { 6447188Smcpowers maxValue = (1ULL << (q * 8)) - 1; 6457188Smcpowers } else { 6467188Smcpowers maxValue = ULONG_MAX; 6477188Smcpowers } 6487188Smcpowers 6497188Smcpowers if (ccm_param->ulDataSize > maxValue) { 6507188Smcpowers return (CRYPTO_MECHANISM_PARAM_INVALID); 6517188Smcpowers } 6527188Smcpowers return (CRYPTO_SUCCESS); 6537188Smcpowers } 6547188Smcpowers 6557188Smcpowers /* 6567188Smcpowers * Format the first block used in CBC-MAC (B0) and the initial counter 6577188Smcpowers * block based on formatting functions and counter generation functions 6587188Smcpowers * specified in RFC 3610 and NIST publication 800-38C, appendix A 6597188Smcpowers * 6607188Smcpowers * b0 is the first block used in CBC-MAC 6617188Smcpowers * cb0 is the first counter block 6627188Smcpowers * 6637188Smcpowers * It's assumed that the arguments b0 and cb0 are preallocated AES blocks 6647188Smcpowers * 6657188Smcpowers */ 6667188Smcpowers static void 6677188Smcpowers ccm_format_initial_blocks(uchar_t *nonce, ulong_t nonceSize, 6687188Smcpowers ulong_t authDataSize, uint8_t *b0, ccm_ctx_t *aes_ctx) 6697188Smcpowers { 6707188Smcpowers uint64_t payloadSize; 6717188Smcpowers uint8_t t, q, have_adata = 0; 6727188Smcpowers size_t limit; 6737188Smcpowers int i, j, k; 6747188Smcpowers uint64_t mask = 0; 6757188Smcpowers uint8_t *cb; 6767188Smcpowers 6777188Smcpowers q = (uint8_t)((15 - nonceSize) & 0xFF); 6787188Smcpowers t = (uint8_t)((aes_ctx->ccm_mac_len) & 0xFF); 6797188Smcpowers 6807188Smcpowers /* Construct the first octet of b0 */ 6817188Smcpowers if (authDataSize > 0) { 6827188Smcpowers have_adata = 1; 6837188Smcpowers } 6847188Smcpowers b0[0] = (have_adata << 6) | (((t - 2) / 2) << 3) | (q - 1); 6857188Smcpowers 6867188Smcpowers /* copy the nonce value into b0 */ 6877188Smcpowers bcopy(nonce, &(b0[1]), nonceSize); 6887188Smcpowers 6897188Smcpowers /* store the length of the payload into b0 */ 6907188Smcpowers bzero(&(b0[1+nonceSize]), q); 6917188Smcpowers 6927188Smcpowers payloadSize = aes_ctx->ccm_data_len; 6937188Smcpowers limit = 8 < q ? 8 : q; 6947188Smcpowers 6957188Smcpowers for (i = 0, j = 0, k = 15; i < limit; i++, j += 8, k--) { 6967188Smcpowers b0[k] = (uint8_t)((payloadSize >> j) & 0xFF); 6977188Smcpowers } 6987188Smcpowers 6997188Smcpowers /* format the counter block */ 7007188Smcpowers 7017188Smcpowers cb = (uint8_t *)aes_ctx->ccm_cb; 7027188Smcpowers 7037188Smcpowers cb[0] = 0x07 & (q-1); /* first byte */ 7047188Smcpowers 7057188Smcpowers /* copy the nonce value into the counter block */ 7067188Smcpowers bcopy(nonce, &(cb[1]), nonceSize); 7077188Smcpowers 7087188Smcpowers bzero(&(cb[1+nonceSize]), q); 7097188Smcpowers 7107188Smcpowers /* Create the mask for the counter field based on the size of nonce */ 7117188Smcpowers q <<= 3; 7127188Smcpowers while (q-- > 0) { 7137188Smcpowers mask |= (1ULL << q); 7147188Smcpowers } 7157188Smcpowers 7167188Smcpowers #ifdef _LITTLE_ENDIAN 717*7421SDaniel.Anderson@Sun.COM mask = htonll(mask); 7187188Smcpowers #endif 7197188Smcpowers aes_ctx->ccm_counter_mask = mask; 7207188Smcpowers 7217188Smcpowers /* 7227188Smcpowers * During calculation, we start using counter block 1, we will 7237188Smcpowers * set it up right here. 7247188Smcpowers * We can just set the last byte to have the value 1, because 7257188Smcpowers * even with the biggest nonce of 13, the last byte of the 7267188Smcpowers * counter block will be used for the counter value. 7277188Smcpowers */ 7287188Smcpowers cb[15] = 0x01; 7297188Smcpowers } 7307188Smcpowers 7317188Smcpowers /* 7327188Smcpowers * Encode the length of the associated data as 7337188Smcpowers * specified in RFC 3610 and NIST publication 800-38C, appendix A 7347188Smcpowers */ 7357188Smcpowers static void 7367188Smcpowers encode_adata_len(ulong_t auth_data_len, uint8_t *encoded, size_t *encoded_len) 7377188Smcpowers { 738*7421SDaniel.Anderson@Sun.COM #ifdef UNALIGNED_POINTERS_PERMITTED 739*7421SDaniel.Anderson@Sun.COM uint32_t *lencoded_ptr; 740*7421SDaniel.Anderson@Sun.COM #ifdef _LP64 741*7421SDaniel.Anderson@Sun.COM uint64_t *llencoded_ptr; 742*7421SDaniel.Anderson@Sun.COM #endif 743*7421SDaniel.Anderson@Sun.COM #endif /* UNALIGNED_POINTERS_PERMITTED */ 744*7421SDaniel.Anderson@Sun.COM 7457188Smcpowers if (auth_data_len < ((1ULL<<16) - (1ULL<<8))) { 7467188Smcpowers /* 0 < a < (2^16-2^8) */ 7477188Smcpowers *encoded_len = 2; 7487188Smcpowers encoded[0] = (auth_data_len & 0xff00) >> 8; 7497188Smcpowers encoded[1] = auth_data_len & 0xff; 7507188Smcpowers 7517188Smcpowers } else if ((auth_data_len >= ((1ULL<<16) - (1ULL<<8))) && 7527188Smcpowers (auth_data_len < (1ULL << 31))) { 7537188Smcpowers /* (2^16-2^8) <= a < 2^32 */ 7547188Smcpowers *encoded_len = 6; 7557188Smcpowers encoded[0] = 0xff; 7567188Smcpowers encoded[1] = 0xfe; 757*7421SDaniel.Anderson@Sun.COM #ifdef UNALIGNED_POINTERS_PERMITTED 758*7421SDaniel.Anderson@Sun.COM lencoded_ptr = (uint32_t *)&encoded[2]; 759*7421SDaniel.Anderson@Sun.COM *lencoded_ptr = htonl(auth_data_len); 760*7421SDaniel.Anderson@Sun.COM #else 7617188Smcpowers encoded[2] = (auth_data_len & 0xff000000) >> 24; 7627188Smcpowers encoded[3] = (auth_data_len & 0xff0000) >> 16; 7637188Smcpowers encoded[4] = (auth_data_len & 0xff00) >> 8; 7647188Smcpowers encoded[5] = auth_data_len & 0xff; 765*7421SDaniel.Anderson@Sun.COM #endif /* UNALIGNED_POINTERS_PERMITTED */ 766*7421SDaniel.Anderson@Sun.COM 7677188Smcpowers #ifdef _LP64 7687188Smcpowers } else { 7697188Smcpowers /* 2^32 <= a < 2^64 */ 7707188Smcpowers *encoded_len = 10; 7717188Smcpowers encoded[0] = 0xff; 7727188Smcpowers encoded[1] = 0xff; 773*7421SDaniel.Anderson@Sun.COM #ifdef UNALIGNED_POINTERS_PERMITTED 774*7421SDaniel.Anderson@Sun.COM llencoded_ptr = (uint64_t *)&encoded[2]; 775*7421SDaniel.Anderson@Sun.COM *llencoded_ptr = htonl(auth_data_len); 776*7421SDaniel.Anderson@Sun.COM #else 7777188Smcpowers encoded[2] = (auth_data_len & 0xff00000000000000) >> 56; 7787188Smcpowers encoded[3] = (auth_data_len & 0xff000000000000) >> 48; 7797188Smcpowers encoded[4] = (auth_data_len & 0xff0000000000) >> 40; 7807188Smcpowers encoded[5] = (auth_data_len & 0xff00000000) >> 32; 7817188Smcpowers encoded[6] = (auth_data_len & 0xff000000) >> 24; 7827188Smcpowers encoded[7] = (auth_data_len & 0xff0000) >> 16; 7837188Smcpowers encoded[8] = (auth_data_len & 0xff00) >> 8; 7847188Smcpowers encoded[9] = auth_data_len & 0xff; 785*7421SDaniel.Anderson@Sun.COM #endif /* UNALIGNED_POINTERS_PERMITTED */ 7867188Smcpowers #endif /* _LP64 */ 7877188Smcpowers } 7887188Smcpowers } 7897188Smcpowers 7907188Smcpowers /* 7917188Smcpowers * The following function should be call at encrypt or decrypt init time 7927188Smcpowers * for AES CCM mode. 7937188Smcpowers */ 7947188Smcpowers int 7957188Smcpowers ccm_init(ccm_ctx_t *ctx, unsigned char *nonce, size_t nonce_len, 7967188Smcpowers unsigned char *auth_data, size_t auth_data_len, size_t block_size, 7977188Smcpowers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 7987188Smcpowers void (*xor_block)(uint8_t *, uint8_t *)) 7997188Smcpowers { 8007188Smcpowers uint8_t *mac_buf, *datap, *ivp, *authp; 8017188Smcpowers size_t remainder, processed; 8027188Smcpowers uint8_t encoded_a[10]; /* max encoded auth data length is 10 octets */ 8037188Smcpowers size_t encoded_a_len = 0; 8047188Smcpowers 8057188Smcpowers mac_buf = (uint8_t *)&(ctx->ccm_mac_buf); 8067188Smcpowers 8077188Smcpowers /* 8087188Smcpowers * Format the 1st block for CBC-MAC and construct the 8097188Smcpowers * 1st counter block. 8107188Smcpowers * 8117188Smcpowers * aes_ctx->ccm_iv is used for storing the counter block 8127188Smcpowers * mac_buf will store b0 at this time. 8137188Smcpowers */ 8147188Smcpowers ccm_format_initial_blocks(nonce, nonce_len, 8157188Smcpowers auth_data_len, mac_buf, ctx); 8167188Smcpowers 8177188Smcpowers /* The IV for CBC MAC for AES CCM mode is always zero */ 8187188Smcpowers ivp = (uint8_t *)ctx->ccm_tmp; 8197188Smcpowers bzero(ivp, block_size); 8207188Smcpowers 8217188Smcpowers xor_block(ivp, mac_buf); 8227188Smcpowers 8237188Smcpowers /* encrypt the nonce */ 8247188Smcpowers encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf); 8257188Smcpowers 8267188Smcpowers /* take care of the associated data, if any */ 8277188Smcpowers if (auth_data_len == 0) { 8287188Smcpowers return (CRYPTO_SUCCESS); 8297188Smcpowers } 8307188Smcpowers 8317188Smcpowers encode_adata_len(auth_data_len, encoded_a, &encoded_a_len); 8327188Smcpowers 8337188Smcpowers remainder = auth_data_len; 8347188Smcpowers 8357188Smcpowers /* 1st block: it contains encoded associated data, and some data */ 8367188Smcpowers authp = (uint8_t *)ctx->ccm_tmp; 8377188Smcpowers bzero(authp, block_size); 8387188Smcpowers bcopy(encoded_a, authp, encoded_a_len); 8397188Smcpowers processed = block_size - encoded_a_len; 8407188Smcpowers if (processed > auth_data_len) { 8417188Smcpowers /* in case auth_data is very small */ 8427188Smcpowers processed = auth_data_len; 8437188Smcpowers } 8447188Smcpowers bcopy(auth_data, authp+encoded_a_len, processed); 8457188Smcpowers /* xor with previous buffer */ 8467188Smcpowers xor_block(authp, mac_buf); 8477188Smcpowers encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf); 8487188Smcpowers remainder -= processed; 8497188Smcpowers if (remainder == 0) { 8507188Smcpowers /* a small amount of associated data, it's all done now */ 8517188Smcpowers return (CRYPTO_SUCCESS); 8527188Smcpowers } 8537188Smcpowers 8547188Smcpowers do { 8557188Smcpowers if (remainder < block_size) { 8567188Smcpowers /* 8577188Smcpowers * There's not a block full of data, pad rest of 8587188Smcpowers * buffer with zero 8597188Smcpowers */ 8607188Smcpowers bzero(authp, block_size); 8617188Smcpowers bcopy(&(auth_data[processed]), authp, remainder); 8627188Smcpowers datap = (uint8_t *)authp; 8637188Smcpowers remainder = 0; 8647188Smcpowers } else { 8657188Smcpowers datap = (uint8_t *)(&(auth_data[processed])); 8667188Smcpowers processed += block_size; 8677188Smcpowers remainder -= block_size; 8687188Smcpowers } 8697188Smcpowers 8707188Smcpowers xor_block(datap, mac_buf); 8717188Smcpowers encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf); 8727188Smcpowers 8737188Smcpowers } while (remainder > 0); 8747188Smcpowers 8757188Smcpowers return (CRYPTO_SUCCESS); 8767188Smcpowers } 8777188Smcpowers 8787188Smcpowers int 8797188Smcpowers ccm_init_ctx(ccm_ctx_t *ccm_ctx, char *param, int kmflag, 8807188Smcpowers boolean_t is_encrypt_init, size_t block_size, 8817188Smcpowers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 8827188Smcpowers void (*xor_block)(uint8_t *, uint8_t *)) 8837188Smcpowers { 8847188Smcpowers int rv; 8857188Smcpowers CK_AES_CCM_PARAMS *ccm_param; 8867188Smcpowers 8877188Smcpowers if (param != NULL) { 8887188Smcpowers ccm_param = (CK_AES_CCM_PARAMS *)param; 8897188Smcpowers 8907188Smcpowers if ((rv = ccm_validate_args(ccm_param, 8917188Smcpowers is_encrypt_init)) != 0) { 8927188Smcpowers return (rv); 8937188Smcpowers } 8947188Smcpowers 8957188Smcpowers ccm_ctx->ccm_mac_len = ccm_param->ulMACSize; 8967188Smcpowers if (is_encrypt_init) { 8977188Smcpowers ccm_ctx->ccm_data_len = ccm_param->ulDataSize; 8987188Smcpowers } else { 8997188Smcpowers ccm_ctx->ccm_data_len = 9007188Smcpowers ccm_param->ulDataSize - ccm_ctx->ccm_mac_len; 9017188Smcpowers ccm_ctx->ccm_processed_mac_len = 0; 9027188Smcpowers } 9037188Smcpowers ccm_ctx->ccm_processed_data_len = 0; 9047188Smcpowers 9057188Smcpowers ccm_ctx->ccm_flags |= CCM_MODE; 9067188Smcpowers } else { 9077188Smcpowers rv = CRYPTO_MECHANISM_PARAM_INVALID; 9087188Smcpowers goto out; 9097188Smcpowers } 9107188Smcpowers 9117188Smcpowers if (ccm_init(ccm_ctx, ccm_param->nonce, ccm_param->ulNonceSize, 9127188Smcpowers ccm_param->authData, ccm_param->ulAuthDataSize, block_size, 9137188Smcpowers encrypt_block, xor_block) != 0) { 9147188Smcpowers rv = CRYPTO_MECHANISM_PARAM_INVALID; 9157188Smcpowers goto out; 9167188Smcpowers } 9177188Smcpowers if (!is_encrypt_init) { 9187188Smcpowers /* allocate buffer for storing decrypted plaintext */ 9197188Smcpowers #ifdef _KERNEL 9207188Smcpowers ccm_ctx->ccm_pt_buf = kmem_alloc(ccm_ctx->ccm_data_len, 9217188Smcpowers kmflag); 9227188Smcpowers #else 9237188Smcpowers ccm_ctx->ccm_pt_buf = malloc(ccm_ctx->ccm_data_len); 9247188Smcpowers #endif 9257188Smcpowers if (ccm_ctx->ccm_pt_buf == NULL) { 9267188Smcpowers rv = CRYPTO_HOST_MEMORY; 9277188Smcpowers } 9287188Smcpowers } 9297188Smcpowers out: 9307188Smcpowers return (rv); 9317188Smcpowers } 9327188Smcpowers 9337188Smcpowers void * 9347188Smcpowers ccm_alloc_ctx(int kmflag) 9357188Smcpowers { 9367188Smcpowers ccm_ctx_t *ccm_ctx; 9377188Smcpowers 9387188Smcpowers #ifdef _KERNEL 9397188Smcpowers if ((ccm_ctx = kmem_zalloc(sizeof (ccm_ctx_t), kmflag)) == NULL) 9407188Smcpowers #else 9417188Smcpowers if ((ccm_ctx = calloc(1, sizeof (ccm_ctx_t))) == NULL) 9427188Smcpowers #endif 9437188Smcpowers return (NULL); 9447188Smcpowers 9457188Smcpowers ccm_ctx->ccm_flags = CCM_MODE; 9467188Smcpowers return (ccm_ctx); 9477188Smcpowers } 948