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