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 <modes/modes.h> 3523c57df7Smcpowers #include <sys/crypto/common.h> 3623c57df7Smcpowers #include <sys/crypto/impl.h> 3723c57df7Smcpowers 38*4b56a003SDaniel Anderson #ifdef _LITTLE_ENDIAN 39*4b56a003SDaniel Anderson #include <sys/byteorder.h> 40*4b56a003SDaniel Anderson #endif 41*4b56a003SDaniel Anderson 4223c57df7Smcpowers /* 4323c57df7Smcpowers * Encrypt and decrypt multiple blocks of data in counter mode. 4423c57df7Smcpowers */ 4523c57df7Smcpowers int 4623c57df7Smcpowers ctr_mode_contiguous_blocks(ctr_ctx_t *ctx, char *data, size_t length, 4723c57df7Smcpowers crypto_data_t *out, size_t block_size, 4823c57df7Smcpowers int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct), 4923c57df7Smcpowers void (*xor_block)(uint8_t *, uint8_t *)) 5023c57df7Smcpowers { 5123c57df7Smcpowers size_t remainder = length; 5223c57df7Smcpowers size_t need; 5323c57df7Smcpowers uint8_t *datap = (uint8_t *)data; 5423c57df7Smcpowers uint8_t *blockp; 5523c57df7Smcpowers uint8_t *lastp; 5623c57df7Smcpowers void *iov_or_mp; 5723c57df7Smcpowers offset_t offset; 5823c57df7Smcpowers uint8_t *out_data_1; 5923c57df7Smcpowers uint8_t *out_data_2; 6023c57df7Smcpowers size_t out_data_1_len; 6123c57df7Smcpowers uint64_t counter; 6223c57df7Smcpowers #ifdef _LITTLE_ENDIAN 6323c57df7Smcpowers uint8_t *p; 6423c57df7Smcpowers #endif 6523c57df7Smcpowers 6623c57df7Smcpowers if (length + ctx->ctr_remainder_len < block_size) { 6723c57df7Smcpowers /* accumulate bytes here and return */ 6823c57df7Smcpowers bcopy(datap, 6923c57df7Smcpowers (uint8_t *)ctx->ctr_remainder + ctx->ctr_remainder_len, 7023c57df7Smcpowers length); 7123c57df7Smcpowers ctx->ctr_remainder_len += length; 7223c57df7Smcpowers ctx->ctr_copy_to = datap; 7323c57df7Smcpowers return (CRYPTO_SUCCESS); 7423c57df7Smcpowers } 7523c57df7Smcpowers 7623c57df7Smcpowers lastp = (uint8_t *)ctx->ctr_cb; 7723c57df7Smcpowers if (out != NULL) 7823c57df7Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset); 7923c57df7Smcpowers 8023c57df7Smcpowers do { 8123c57df7Smcpowers /* Unprocessed data from last call. */ 8223c57df7Smcpowers if (ctx->ctr_remainder_len > 0) { 8323c57df7Smcpowers need = block_size - ctx->ctr_remainder_len; 8423c57df7Smcpowers 8523c57df7Smcpowers if (need > remainder) 8623c57df7Smcpowers return (CRYPTO_DATA_LEN_RANGE); 8723c57df7Smcpowers 8823c57df7Smcpowers bcopy(datap, &((uint8_t *)ctx->ctr_remainder) 8923c57df7Smcpowers [ctx->ctr_remainder_len], need); 9023c57df7Smcpowers 9123c57df7Smcpowers blockp = (uint8_t *)ctx->ctr_remainder; 9223c57df7Smcpowers } else { 9323c57df7Smcpowers blockp = datap; 9423c57df7Smcpowers } 9523c57df7Smcpowers 9623c57df7Smcpowers /* ctr_cb is the counter block */ 9723c57df7Smcpowers cipher(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb, 9823c57df7Smcpowers (uint8_t *)ctx->ctr_tmp); 9923c57df7Smcpowers 10023c57df7Smcpowers lastp = (uint8_t *)ctx->ctr_tmp; 10123c57df7Smcpowers 10223c57df7Smcpowers /* 10323c57df7Smcpowers * Increment counter. Counter bits are confined 10423c57df7Smcpowers * to the bottom 64 bits of the counter block. 10523c57df7Smcpowers */ 106*4b56a003SDaniel Anderson #ifdef _LITTLE_ENDIAN 107*4b56a003SDaniel Anderson counter = ntohll(ctx->ctr_cb[1] & ctx->ctr_counter_mask); 108*4b56a003SDaniel Anderson counter = htonll(counter + 1); 109*4b56a003SDaniel Anderson #else 11023c57df7Smcpowers counter = ctx->ctr_cb[1] & ctx->ctr_counter_mask; 11123c57df7Smcpowers counter++; 112*4b56a003SDaniel Anderson #endif /* _LITTLE_ENDIAN */ 11323c57df7Smcpowers counter &= ctx->ctr_counter_mask; 11423c57df7Smcpowers ctx->ctr_cb[1] = 11523c57df7Smcpowers (ctx->ctr_cb[1] & ~(ctx->ctr_counter_mask)) | counter; 11623c57df7Smcpowers 11723c57df7Smcpowers /* 11823c57df7Smcpowers * XOR the previous cipher block or IV with the 11923c57df7Smcpowers * current clear block. 12023c57df7Smcpowers */ 12123c57df7Smcpowers xor_block(blockp, lastp); 12223c57df7Smcpowers 12323c57df7Smcpowers if (out == NULL) { 12423c57df7Smcpowers if (ctx->ctr_remainder_len > 0) { 12523c57df7Smcpowers bcopy(lastp, ctx->ctr_copy_to, 12623c57df7Smcpowers ctx->ctr_remainder_len); 12723c57df7Smcpowers bcopy(lastp + ctx->ctr_remainder_len, datap, 12823c57df7Smcpowers need); 12923c57df7Smcpowers } 13023c57df7Smcpowers } else { 13123c57df7Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 13223c57df7Smcpowers &out_data_1_len, &out_data_2, block_size); 13323c57df7Smcpowers 13423c57df7Smcpowers /* copy block to where it belongs */ 13523c57df7Smcpowers bcopy(lastp, out_data_1, out_data_1_len); 13623c57df7Smcpowers if (out_data_2 != NULL) { 13723c57df7Smcpowers bcopy(lastp + out_data_1_len, out_data_2, 13823c57df7Smcpowers block_size - out_data_1_len); 13923c57df7Smcpowers } 14023c57df7Smcpowers /* update offset */ 14123c57df7Smcpowers out->cd_offset += block_size; 14223c57df7Smcpowers } 14323c57df7Smcpowers 14423c57df7Smcpowers /* Update pointer to next block of data to be processed. */ 14523c57df7Smcpowers if (ctx->ctr_remainder_len != 0) { 14623c57df7Smcpowers datap += need; 14723c57df7Smcpowers ctx->ctr_remainder_len = 0; 14823c57df7Smcpowers } else { 14923c57df7Smcpowers datap += block_size; 15023c57df7Smcpowers } 15123c57df7Smcpowers 15223c57df7Smcpowers remainder = (size_t)&data[length] - (size_t)datap; 15323c57df7Smcpowers 15423c57df7Smcpowers /* Incomplete last block. */ 15523c57df7Smcpowers if (remainder > 0 && remainder < block_size) { 15623c57df7Smcpowers bcopy(datap, ctx->ctr_remainder, remainder); 15723c57df7Smcpowers ctx->ctr_remainder_len = remainder; 15823c57df7Smcpowers ctx->ctr_copy_to = datap; 15923c57df7Smcpowers goto out; 16023c57df7Smcpowers } 16123c57df7Smcpowers ctx->ctr_copy_to = NULL; 16223c57df7Smcpowers 16323c57df7Smcpowers } while (remainder > 0); 16423c57df7Smcpowers 16523c57df7Smcpowers out: 16623c57df7Smcpowers return (CRYPTO_SUCCESS); 16723c57df7Smcpowers } 16823c57df7Smcpowers 16923c57df7Smcpowers int 17023c57df7Smcpowers ctr_mode_final(ctr_ctx_t *ctx, crypto_data_t *out, 17123c57df7Smcpowers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *)) 17223c57df7Smcpowers { 17323c57df7Smcpowers uint8_t *lastp; 17423c57df7Smcpowers void *iov_or_mp; 17523c57df7Smcpowers offset_t offset; 17623c57df7Smcpowers uint8_t *out_data_1; 17723c57df7Smcpowers uint8_t *out_data_2; 17823c57df7Smcpowers size_t out_data_1_len; 17923c57df7Smcpowers uint8_t *p; 18023c57df7Smcpowers int i; 18123c57df7Smcpowers 18223c57df7Smcpowers if (out->cd_length < ctx->ctr_remainder_len) 18323c57df7Smcpowers return (CRYPTO_DATA_LEN_RANGE); 18423c57df7Smcpowers 18523c57df7Smcpowers encrypt_block(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb, 18623c57df7Smcpowers (uint8_t *)ctx->ctr_tmp); 18723c57df7Smcpowers 18823c57df7Smcpowers lastp = (uint8_t *)ctx->ctr_tmp; 18923c57df7Smcpowers p = (uint8_t *)ctx->ctr_remainder; 19023c57df7Smcpowers for (i = 0; i < ctx->ctr_remainder_len; i++) { 19123c57df7Smcpowers p[i] ^= lastp[i]; 19223c57df7Smcpowers } 19323c57df7Smcpowers 19423c57df7Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset); 19523c57df7Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 19623c57df7Smcpowers &out_data_1_len, &out_data_2, ctx->ctr_remainder_len); 19723c57df7Smcpowers 19823c57df7Smcpowers bcopy(p, out_data_1, out_data_1_len); 19923c57df7Smcpowers if (out_data_2 != NULL) { 20023c57df7Smcpowers bcopy((uint8_t *)p + out_data_1_len, 20123c57df7Smcpowers out_data_2, ctx->ctr_remainder_len - out_data_1_len); 20223c57df7Smcpowers } 20323c57df7Smcpowers out->cd_offset += ctx->ctr_remainder_len; 20423c57df7Smcpowers ctx->ctr_remainder_len = 0; 20523c57df7Smcpowers return (CRYPTO_SUCCESS); 20623c57df7Smcpowers } 20723c57df7Smcpowers 20823c57df7Smcpowers int 20923c57df7Smcpowers ctr_init_ctx(ctr_ctx_t *ctr_ctx, ulong_t count, uint8_t *cb, 21023c57df7Smcpowers void (*copy_block)(uint8_t *, uint8_t *)) 21123c57df7Smcpowers { 21223c57df7Smcpowers uint64_t mask = 0; 21323c57df7Smcpowers 21423c57df7Smcpowers if (count == 0 || count > 64) { 21523c57df7Smcpowers return (CRYPTO_MECHANISM_PARAM_INVALID); 21623c57df7Smcpowers } 21723c57df7Smcpowers while (count-- > 0) 21823c57df7Smcpowers mask |= (1ULL << count); 219*4b56a003SDaniel Anderson 22023c57df7Smcpowers #ifdef _LITTLE_ENDIAN 221*4b56a003SDaniel Anderson mask = htonll(mask); 22223c57df7Smcpowers #endif 22323c57df7Smcpowers ctr_ctx->ctr_counter_mask = mask; 22423c57df7Smcpowers copy_block(cb, (uchar_t *)ctr_ctx->ctr_cb); 22523c57df7Smcpowers ctr_ctx->ctr_lastp = (uint8_t *)&ctr_ctx->ctr_cb[0]; 22623c57df7Smcpowers ctr_ctx->ctr_flags |= CTR_MODE; 22723c57df7Smcpowers return (CRYPTO_SUCCESS); 22823c57df7Smcpowers } 22923c57df7Smcpowers 23023c57df7Smcpowers /* ARGSUSED */ 23123c57df7Smcpowers void * 23223c57df7Smcpowers ctr_alloc_ctx(int kmflag) 23323c57df7Smcpowers { 23423c57df7Smcpowers ctr_ctx_t *ctr_ctx; 23523c57df7Smcpowers 23623c57df7Smcpowers #ifdef _KERNEL 23723c57df7Smcpowers if ((ctr_ctx = kmem_zalloc(sizeof (ctr_ctx_t), kmflag)) == NULL) 23823c57df7Smcpowers #else 23923c57df7Smcpowers if ((ctr_ctx = calloc(1, sizeof (ctr_ctx_t))) == NULL) 24023c57df7Smcpowers #endif 24123c57df7Smcpowers return (NULL); 24223c57df7Smcpowers 24323c57df7Smcpowers ctr_ctx->ctr_flags = CTR_MODE; 24423c57df7Smcpowers return (ctr_ctx); 24523c57df7Smcpowers } 246