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 3823c57df7Smcpowers /* 3923c57df7Smcpowers * Algorithm independent CBC functions. 4023c57df7Smcpowers */ 4123c57df7Smcpowers int 4223c57df7Smcpowers cbc_encrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length, 4323c57df7Smcpowers crypto_data_t *out, size_t block_size, 4423c57df7Smcpowers int (*encrypt)(const void *, const uint8_t *, uint8_t *), 4523c57df7Smcpowers void (*copy_block)(uint8_t *, uint8_t *), 4623c57df7Smcpowers void (*xor_block)(uint8_t *, uint8_t *)) 4723c57df7Smcpowers { 4823c57df7Smcpowers size_t remainder = length; 4923c57df7Smcpowers size_t need; 5023c57df7Smcpowers uint8_t *datap = (uint8_t *)data; 5123c57df7Smcpowers uint8_t *blockp; 5223c57df7Smcpowers uint8_t *lastp; 5323c57df7Smcpowers void *iov_or_mp; 5423c57df7Smcpowers offset_t offset; 5523c57df7Smcpowers uint8_t *out_data_1; 5623c57df7Smcpowers uint8_t *out_data_2; 5723c57df7Smcpowers size_t out_data_1_len; 5823c57df7Smcpowers 59*16239bc8SMark Powers if (length + ctx->cbc_remainder_len < block_size) { 6023c57df7Smcpowers /* accumulate bytes here and return */ 6123c57df7Smcpowers bcopy(datap, 62*16239bc8SMark Powers (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len, 6323c57df7Smcpowers length); 64*16239bc8SMark Powers ctx->cbc_remainder_len += length; 65*16239bc8SMark Powers ctx->cbc_copy_to = datap; 6623c57df7Smcpowers return (CRYPTO_SUCCESS); 6723c57df7Smcpowers } 6823c57df7Smcpowers 69*16239bc8SMark Powers lastp = (uint8_t *)ctx->cbc_iv; 7023c57df7Smcpowers if (out != NULL) 7123c57df7Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset); 7223c57df7Smcpowers 7323c57df7Smcpowers do { 7423c57df7Smcpowers /* Unprocessed data from last call. */ 75*16239bc8SMark Powers if (ctx->cbc_remainder_len > 0) { 76*16239bc8SMark Powers need = block_size - ctx->cbc_remainder_len; 7723c57df7Smcpowers 7823c57df7Smcpowers if (need > remainder) 7923c57df7Smcpowers return (CRYPTO_DATA_LEN_RANGE); 8023c57df7Smcpowers 81*16239bc8SMark Powers bcopy(datap, &((uint8_t *)ctx->cbc_remainder) 82*16239bc8SMark Powers [ctx->cbc_remainder_len], need); 8323c57df7Smcpowers 84*16239bc8SMark Powers blockp = (uint8_t *)ctx->cbc_remainder; 8523c57df7Smcpowers } else { 8623c57df7Smcpowers blockp = datap; 8723c57df7Smcpowers } 8823c57df7Smcpowers 8923c57df7Smcpowers if (out == NULL) { 9023c57df7Smcpowers /* 9123c57df7Smcpowers * XOR the previous cipher block or IV with the 9223c57df7Smcpowers * current clear block. 9323c57df7Smcpowers */ 9423c57df7Smcpowers xor_block(lastp, blockp); 95*16239bc8SMark Powers encrypt(ctx->cbc_keysched, blockp, blockp); 9623c57df7Smcpowers 97*16239bc8SMark Powers ctx->cbc_lastp = blockp; 9823c57df7Smcpowers lastp = blockp; 9923c57df7Smcpowers 100*16239bc8SMark Powers if (ctx->cbc_remainder_len > 0) { 101*16239bc8SMark Powers bcopy(blockp, ctx->cbc_copy_to, 102*16239bc8SMark Powers ctx->cbc_remainder_len); 103*16239bc8SMark Powers bcopy(blockp + ctx->cbc_remainder_len, datap, 10423c57df7Smcpowers need); 10523c57df7Smcpowers } 10623c57df7Smcpowers } else { 10723c57df7Smcpowers /* 10823c57df7Smcpowers * XOR the previous cipher block or IV with the 10923c57df7Smcpowers * current clear block. 11023c57df7Smcpowers */ 11123c57df7Smcpowers xor_block(blockp, lastp); 112*16239bc8SMark Powers encrypt(ctx->cbc_keysched, lastp, lastp); 11323c57df7Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 11423c57df7Smcpowers &out_data_1_len, &out_data_2, block_size); 11523c57df7Smcpowers 11623c57df7Smcpowers /* copy block to where it belongs */ 11723c57df7Smcpowers if (out_data_1_len == block_size) { 11823c57df7Smcpowers copy_block(lastp, out_data_1); 11923c57df7Smcpowers } else { 12023c57df7Smcpowers bcopy(lastp, out_data_1, out_data_1_len); 12123c57df7Smcpowers if (out_data_2 != NULL) { 12223c57df7Smcpowers bcopy(lastp + out_data_1_len, 12323c57df7Smcpowers out_data_2, 12423c57df7Smcpowers block_size - out_data_1_len); 12523c57df7Smcpowers } 12623c57df7Smcpowers } 12723c57df7Smcpowers /* update offset */ 12823c57df7Smcpowers out->cd_offset += block_size; 12923c57df7Smcpowers } 13023c57df7Smcpowers 13123c57df7Smcpowers /* Update pointer to next block of data to be processed. */ 132*16239bc8SMark Powers if (ctx->cbc_remainder_len != 0) { 13323c57df7Smcpowers datap += need; 134*16239bc8SMark Powers ctx->cbc_remainder_len = 0; 13523c57df7Smcpowers } else { 13623c57df7Smcpowers datap += block_size; 13723c57df7Smcpowers } 13823c57df7Smcpowers 13923c57df7Smcpowers remainder = (size_t)&data[length] - (size_t)datap; 14023c57df7Smcpowers 14123c57df7Smcpowers /* Incomplete last block. */ 14223c57df7Smcpowers if (remainder > 0 && remainder < block_size) { 143*16239bc8SMark Powers bcopy(datap, ctx->cbc_remainder, remainder); 144*16239bc8SMark Powers ctx->cbc_remainder_len = remainder; 145*16239bc8SMark Powers ctx->cbc_copy_to = datap; 14623c57df7Smcpowers goto out; 14723c57df7Smcpowers } 148*16239bc8SMark Powers ctx->cbc_copy_to = NULL; 14923c57df7Smcpowers 15023c57df7Smcpowers } while (remainder > 0); 15123c57df7Smcpowers 15223c57df7Smcpowers out: 15323c57df7Smcpowers /* 15423c57df7Smcpowers * Save the last encrypted block in the context. 15523c57df7Smcpowers */ 156*16239bc8SMark Powers if (ctx->cbc_lastp != NULL) { 157*16239bc8SMark Powers copy_block((uint8_t *)ctx->cbc_lastp, (uint8_t *)ctx->cbc_iv); 158*16239bc8SMark Powers ctx->cbc_lastp = (uint8_t *)ctx->cbc_iv; 15923c57df7Smcpowers } 16023c57df7Smcpowers 16123c57df7Smcpowers return (CRYPTO_SUCCESS); 16223c57df7Smcpowers } 16323c57df7Smcpowers 16423c57df7Smcpowers #define OTHER(a, ctx) \ 165*16239bc8SMark Powers (((a) == (ctx)->cbc_lastblock) ? (ctx)->cbc_iv : (ctx)->cbc_lastblock) 16623c57df7Smcpowers 16723c57df7Smcpowers /* ARGSUSED */ 16823c57df7Smcpowers int 16923c57df7Smcpowers cbc_decrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length, 17023c57df7Smcpowers crypto_data_t *out, size_t block_size, 17123c57df7Smcpowers int (*decrypt)(const void *, const uint8_t *, uint8_t *), 17223c57df7Smcpowers void (*copy_block)(uint8_t *, uint8_t *), 17323c57df7Smcpowers void (*xor_block)(uint8_t *, uint8_t *)) 17423c57df7Smcpowers { 17523c57df7Smcpowers size_t remainder = length; 17623c57df7Smcpowers size_t need; 17723c57df7Smcpowers uint8_t *datap = (uint8_t *)data; 17823c57df7Smcpowers uint8_t *blockp; 17923c57df7Smcpowers uint8_t *lastp; 18023c57df7Smcpowers void *iov_or_mp; 18123c57df7Smcpowers offset_t offset; 18223c57df7Smcpowers uint8_t *out_data_1; 18323c57df7Smcpowers uint8_t *out_data_2; 18423c57df7Smcpowers size_t out_data_1_len; 18523c57df7Smcpowers 186*16239bc8SMark Powers if (length + ctx->cbc_remainder_len < block_size) { 18723c57df7Smcpowers /* accumulate bytes here and return */ 18823c57df7Smcpowers bcopy(datap, 189*16239bc8SMark Powers (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len, 19023c57df7Smcpowers length); 191*16239bc8SMark Powers ctx->cbc_remainder_len += length; 192*16239bc8SMark Powers ctx->cbc_copy_to = datap; 19323c57df7Smcpowers return (CRYPTO_SUCCESS); 19423c57df7Smcpowers } 19523c57df7Smcpowers 196*16239bc8SMark Powers lastp = ctx->cbc_lastp; 19723c57df7Smcpowers if (out != NULL) 19823c57df7Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset); 19923c57df7Smcpowers 20023c57df7Smcpowers do { 20123c57df7Smcpowers /* Unprocessed data from last call. */ 202*16239bc8SMark Powers if (ctx->cbc_remainder_len > 0) { 203*16239bc8SMark Powers need = block_size - ctx->cbc_remainder_len; 20423c57df7Smcpowers 20523c57df7Smcpowers if (need > remainder) 20623c57df7Smcpowers return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE); 20723c57df7Smcpowers 208*16239bc8SMark Powers bcopy(datap, &((uint8_t *)ctx->cbc_remainder) 209*16239bc8SMark Powers [ctx->cbc_remainder_len], need); 21023c57df7Smcpowers 211*16239bc8SMark Powers blockp = (uint8_t *)ctx->cbc_remainder; 21223c57df7Smcpowers } else { 21323c57df7Smcpowers blockp = datap; 21423c57df7Smcpowers } 21523c57df7Smcpowers 21623c57df7Smcpowers /* LINTED: pointer alignment */ 21723c57df7Smcpowers copy_block(blockp, (uint8_t *)OTHER((uint64_t *)lastp, ctx)); 21823c57df7Smcpowers 21923c57df7Smcpowers if (out != NULL) { 220*16239bc8SMark Powers decrypt(ctx->cbc_keysched, blockp, 221*16239bc8SMark Powers (uint8_t *)ctx->cbc_remainder); 222*16239bc8SMark Powers blockp = (uint8_t *)ctx->cbc_remainder; 22323c57df7Smcpowers } else { 224*16239bc8SMark Powers decrypt(ctx->cbc_keysched, blockp, blockp); 22523c57df7Smcpowers } 22623c57df7Smcpowers 22723c57df7Smcpowers /* 22823c57df7Smcpowers * XOR the previous cipher block or IV with the 22923c57df7Smcpowers * currently decrypted block. 23023c57df7Smcpowers */ 23123c57df7Smcpowers xor_block(lastp, blockp); 23223c57df7Smcpowers 23323c57df7Smcpowers /* LINTED: pointer alignment */ 23423c57df7Smcpowers lastp = (uint8_t *)OTHER((uint64_t *)lastp, ctx); 23523c57df7Smcpowers 23623c57df7Smcpowers if (out != NULL) { 23723c57df7Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 23823c57df7Smcpowers &out_data_1_len, &out_data_2, block_size); 23923c57df7Smcpowers 24023c57df7Smcpowers bcopy(blockp, out_data_1, out_data_1_len); 24123c57df7Smcpowers if (out_data_2 != NULL) { 24223c57df7Smcpowers bcopy(blockp + out_data_1_len, out_data_2, 24323c57df7Smcpowers block_size - out_data_1_len); 24423c57df7Smcpowers } 24523c57df7Smcpowers 24623c57df7Smcpowers /* update offset */ 24723c57df7Smcpowers out->cd_offset += block_size; 24823c57df7Smcpowers 249*16239bc8SMark Powers } else if (ctx->cbc_remainder_len > 0) { 25023c57df7Smcpowers /* copy temporary block to where it belongs */ 251*16239bc8SMark Powers bcopy(blockp, ctx->cbc_copy_to, ctx->cbc_remainder_len); 252*16239bc8SMark Powers bcopy(blockp + ctx->cbc_remainder_len, datap, need); 25323c57df7Smcpowers } 25423c57df7Smcpowers 25523c57df7Smcpowers /* Update pointer to next block of data to be processed. */ 256*16239bc8SMark Powers if (ctx->cbc_remainder_len != 0) { 25723c57df7Smcpowers datap += need; 258*16239bc8SMark Powers ctx->cbc_remainder_len = 0; 25923c57df7Smcpowers } else { 26023c57df7Smcpowers datap += block_size; 26123c57df7Smcpowers } 26223c57df7Smcpowers 26323c57df7Smcpowers remainder = (size_t)&data[length] - (size_t)datap; 26423c57df7Smcpowers 26523c57df7Smcpowers /* Incomplete last block. */ 26623c57df7Smcpowers if (remainder > 0 && remainder < block_size) { 267*16239bc8SMark Powers bcopy(datap, ctx->cbc_remainder, remainder); 268*16239bc8SMark Powers ctx->cbc_remainder_len = remainder; 269*16239bc8SMark Powers ctx->cbc_lastp = lastp; 270*16239bc8SMark Powers ctx->cbc_copy_to = datap; 27123c57df7Smcpowers return (CRYPTO_SUCCESS); 27223c57df7Smcpowers } 273*16239bc8SMark Powers ctx->cbc_copy_to = NULL; 27423c57df7Smcpowers 27523c57df7Smcpowers } while (remainder > 0); 27623c57df7Smcpowers 277*16239bc8SMark Powers ctx->cbc_lastp = lastp; 27823c57df7Smcpowers return (CRYPTO_SUCCESS); 27923c57df7Smcpowers } 28023c57df7Smcpowers 28123c57df7Smcpowers int 28223c57df7Smcpowers cbc_init_ctx(cbc_ctx_t *cbc_ctx, char *param, size_t param_len, 28323c57df7Smcpowers size_t block_size, void (*copy_block)(uint8_t *, uint64_t *)) 28423c57df7Smcpowers { 28523c57df7Smcpowers /* 28623c57df7Smcpowers * Copy IV into context. 28723c57df7Smcpowers * 28823c57df7Smcpowers * If cm_param == NULL then the IV comes from the 28923c57df7Smcpowers * cd_miscdata field in the crypto_data structure. 29023c57df7Smcpowers */ 29123c57df7Smcpowers if (param != NULL) { 29223c57df7Smcpowers #ifdef _KERNEL 29323c57df7Smcpowers ASSERT(param_len == block_size); 29423c57df7Smcpowers #else 29523c57df7Smcpowers assert(param_len == block_size); 29623c57df7Smcpowers #endif 297*16239bc8SMark Powers copy_block((uchar_t *)param, cbc_ctx->cbc_iv); 29823c57df7Smcpowers } 29923c57df7Smcpowers 300*16239bc8SMark Powers cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0]; 301*16239bc8SMark Powers cbc_ctx->cbc_flags |= CBC_MODE; 30223c57df7Smcpowers return (CRYPTO_SUCCESS); 30323c57df7Smcpowers } 30423c57df7Smcpowers 30523c57df7Smcpowers /* ARGSUSED */ 30623c57df7Smcpowers void * 30723c57df7Smcpowers cbc_alloc_ctx(int kmflag) 30823c57df7Smcpowers { 30923c57df7Smcpowers cbc_ctx_t *cbc_ctx; 31023c57df7Smcpowers 31123c57df7Smcpowers #ifdef _KERNEL 31223c57df7Smcpowers if ((cbc_ctx = kmem_zalloc(sizeof (cbc_ctx_t), kmflag)) == NULL) 31323c57df7Smcpowers #else 31423c57df7Smcpowers if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL) 31523c57df7Smcpowers #endif 31623c57df7Smcpowers return (NULL); 31723c57df7Smcpowers 318*16239bc8SMark Powers cbc_ctx->cbc_flags = CBC_MODE; 31923c57df7Smcpowers return (cbc_ctx); 32023c57df7Smcpowers } 321