Print this page
4896 Performance improvements for KCF AES modes


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */



  25 
  26 #ifndef _KERNEL
  27 #include <strings.h>
  28 #include <limits.h>
  29 #include <assert.h>
  30 #include <security/cryptoki.h>
  31 #endif
  32 
  33 #include <sys/types.h>

  34 #include <modes/modes.h>
  35 #include <sys/crypto/common.h>
  36 #include <sys/crypto/impl.h>
  37 
































  38 /*
  39  * Algorithm independent CBC functions.
  40  */
  41 int
  42 cbc_encrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
  43     crypto_data_t *out, size_t block_size,
  44     int (*encrypt)(const void *, const uint8_t *, uint8_t *),
  45     void (*copy_block)(uint8_t *, uint8_t *),
  46     void (*xor_block)(uint8_t *, uint8_t *))


  47 {
  48         size_t remainder = length;
  49         size_t need;
  50         uint8_t *datap = (uint8_t *)data;
  51         uint8_t *blockp;
  52         uint8_t *lastp;
  53         void *iov_or_mp;
  54         offset_t offset;
  55         uint8_t *out_data_1;
  56         uint8_t *out_data_2;
  57         size_t out_data_1_len;
  58 

























  59         if (length + ctx->cbc_remainder_len < block_size) {
  60                 /* accumulate bytes here and return */
  61                 bcopy(datap,
  62                     (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len,
  63                     length);
  64                 ctx->cbc_remainder_len += length;
  65                 ctx->cbc_copy_to = datap;
  66                 return (CRYPTO_SUCCESS);
  67         }
  68 
  69         lastp = (uint8_t *)ctx->cbc_iv;
  70         if (out != NULL)
  71                 crypto_init_ptrs(out, &iov_or_mp, &offset);
  72 
  73         do {
  74                 /* Unprocessed data from last call. */
  75                 if (ctx->cbc_remainder_len > 0) {
  76                         need = block_size - ctx->cbc_remainder_len;
  77 
  78                         if (need > remainder)


 152 out:
 153         /*
 154          * Save the last encrypted block in the context.
 155          */
 156         if (ctx->cbc_lastp != NULL) {
 157                 copy_block((uint8_t *)ctx->cbc_lastp, (uint8_t *)ctx->cbc_iv);
 158                 ctx->cbc_lastp = (uint8_t *)ctx->cbc_iv;
 159         }
 160 
 161         return (CRYPTO_SUCCESS);
 162 }
 163 
 164 #define OTHER(a, ctx) \
 165         (((a) == (ctx)->cbc_lastblock) ? (ctx)->cbc_iv : (ctx)->cbc_lastblock)
 166 
 167 /* ARGSUSED */
 168 int
 169 cbc_decrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
 170     crypto_data_t *out, size_t block_size,
 171     int (*decrypt)(const void *, const uint8_t *, uint8_t *),
 172     void (*copy_block)(uint8_t *, uint8_t *),
 173     void (*xor_block)(uint8_t *, uint8_t *))


 174 {
 175         size_t remainder = length;
 176         size_t need;
 177         uint8_t *datap = (uint8_t *)data;
 178         uint8_t *blockp;
 179         uint8_t *lastp;
 180         void *iov_or_mp;
 181         offset_t offset;
 182         uint8_t *out_data_1;
 183         uint8_t *out_data_2;
 184         size_t out_data_1_len;
 185 




















 186         if (length + ctx->cbc_remainder_len < block_size) {
 187                 /* accumulate bytes here and return */
 188                 bcopy(datap,
 189                     (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len,
 190                     length);
 191                 ctx->cbc_remainder_len += length;
 192                 ctx->cbc_copy_to = datap;
 193                 return (CRYPTO_SUCCESS);
 194         }
 195 
 196         lastp = ctx->cbc_lastp;
 197         if (out != NULL)
 198                 crypto_init_ptrs(out, &iov_or_mp, &offset);
 199 
 200         do {
 201                 /* Unprocessed data from last call. */
 202                 if (ctx->cbc_remainder_len > 0) {
 203                         need = block_size - ctx->cbc_remainder_len;
 204 
 205                         if (need > remainder)


 263                 remainder = (size_t)&data[length] - (size_t)datap;
 264 
 265                 /* Incomplete last block. */
 266                 if (remainder > 0 && remainder < block_size) {
 267                         bcopy(datap, ctx->cbc_remainder, remainder);
 268                         ctx->cbc_remainder_len = remainder;
 269                         ctx->cbc_lastp = lastp;
 270                         ctx->cbc_copy_to = datap;
 271                         return (CRYPTO_SUCCESS);
 272                 }
 273                 ctx->cbc_copy_to = NULL;
 274 
 275         } while (remainder > 0);
 276 
 277         ctx->cbc_lastp = lastp;
 278         return (CRYPTO_SUCCESS);
 279 }
 280 
 281 int
 282 cbc_init_ctx(cbc_ctx_t *cbc_ctx, char *param, size_t param_len,
 283     size_t block_size, void (*copy_block)(uint8_t *, uint64_t *))
 284 {
 285         /*
 286          * Copy IV into context.
 287          *
 288          * If cm_param == NULL then the IV comes from the
 289          * cd_miscdata field in the crypto_data structure.
 290          */
 291         if (param != NULL) {
 292 #ifdef _KERNEL
 293                 ASSERT(param_len == block_size);
 294 #else
 295                 assert(param_len == block_size);
 296 #endif
 297                 copy_block((uchar_t *)param, cbc_ctx->cbc_iv);
 298         }
 299 
 300         cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0];
 301         cbc_ctx->cbc_flags |= CBC_MODE;
 302         return (CRYPTO_SUCCESS);
 303 }


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright 2015 by Saso Kiselkov. All rights reserved.
  27  */
  28 
  29 #ifndef _KERNEL
  30 #include <strings.h>
  31 #include <limits.h>
  32 #include <assert.h>
  33 #include <security/cryptoki.h>
  34 #endif
  35 
  36 #include <sys/types.h>
  37 #define INLINE_CRYPTO_GET_PTRS
  38 #include <modes/modes.h>
  39 #include <sys/crypto/common.h>
  40 #include <sys/crypto/impl.h>
  41 
  42 boolean_t cbc_fastpath_enabled = B_TRUE;
  43 
  44 static void
  45 cbc_decrypt_fastpath(cbc_ctx_t *ctx, const uint8_t *data, size_t length,
  46     uint8_t *out, size_t block_size,
  47     int (*decrypt)(const void *, const uint8_t *, uint8_t *),
  48     int (*decrypt_ecb)(const void *, const uint8_t *, uint8_t *, uint64_t),
  49     void (*xor_block)(const uint8_t *, uint8_t *),
  50     void (*xor_block_range)(const uint8_t *, uint8_t *, uint64_t))
  51 {
  52         const uint8_t *iv = (uint8_t *)ctx->cbc_iv;
  53 
  54         /* Use bulk decryption when available. */
  55         if (decrypt_ecb != NULL) {
  56                 decrypt_ecb(ctx->cbc_keysched, data, out, length);
  57         } else {
  58                 for (size_t i = 0; i < length; i += block_size)
  59                         decrypt(ctx->cbc_keysched, &data[i], &out[i]);
  60         }
  61 
  62         /* Use bulk XOR when available. */
  63         if (xor_block_range != NULL && length >= 2 * block_size) {
  64                 xor_block(iv, out);
  65                 xor_block_range(data, &out[block_size], length - block_size);
  66         } else {
  67                 for (size_t i = 0; i < length; i += block_size) {
  68                         xor_block(iv, &out[i]);
  69                         iv = &data[i];
  70                 }
  71         }
  72 }
  73 
  74 /*
  75  * Algorithm independent CBC functions.
  76  */
  77 int
  78 cbc_encrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
  79     crypto_data_t *out, size_t block_size,
  80     int (*encrypt)(const void *, const uint8_t *, uint8_t *),
  81     void (*copy_block)(const uint8_t *, uint8_t *),
  82     void (*xor_block)(const uint8_t *, uint8_t *),
  83     int (*encrypt_cbc)(const void *, const uint8_t *, uint8_t *,
  84     const uint8_t *, uint64_t))
  85 {
  86         size_t remainder = length;
  87         size_t need;
  88         uint8_t *datap = (uint8_t *)data;
  89         uint8_t *blockp;
  90         uint8_t *lastp;
  91         void *iov_or_mp;
  92         offset_t offset;
  93         uint8_t *out_data_1;
  94         uint8_t *out_data_2;
  95         size_t out_data_1_len;
  96 
  97         /*
  98          * CBC encryption fastpath requirements:
  99          * - fastpath is enabled
 100          * - algorithm-specific acceleration function is available
 101          * - input is block-aligned
 102          * - output is a single contiguous region or the user requested that
 103          *   we overwrite their input buffer (input/output aliasing allowed)
 104          */
 105         if (cbc_fastpath_enabled && encrypt_cbc != NULL && length != 0 &&
 106             ctx->cbc_remainder_len == 0 && (length & (block_size - 1)) == 0 &&
 107             (out == NULL || CRYPTO_DATA_IS_SINGLE_BLOCK(out))) {
 108                 if (out == NULL) {
 109                         encrypt_cbc(ctx->cbc_keysched, (uint8_t *)data,
 110                             (uint8_t *)data, (uint8_t *)ctx->cbc_iv, length);
 111                         ctx->cbc_lastp = (uint8_t *)&data[length - block_size];
 112                 } else {
 113                         uint8_t *outp = CRYPTO_DATA_FIRST_BLOCK(out);
 114                         encrypt_cbc(ctx->cbc_keysched, (uint8_t *)data, outp,
 115                             (uint8_t *)ctx->cbc_iv, length);
 116                         out->cd_offset += length;
 117                         ctx->cbc_lastp = &outp[length - block_size];
 118                 }
 119                 goto out;
 120         }
 121 
 122         if (length + ctx->cbc_remainder_len < block_size) {
 123                 /* accumulate bytes here and return */
 124                 bcopy(datap,
 125                     (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len,
 126                     length);
 127                 ctx->cbc_remainder_len += length;
 128                 ctx->cbc_copy_to = datap;
 129                 return (CRYPTO_SUCCESS);
 130         }
 131 
 132         lastp = (uint8_t *)ctx->cbc_iv;
 133         if (out != NULL)
 134                 crypto_init_ptrs(out, &iov_or_mp, &offset);
 135 
 136         do {
 137                 /* Unprocessed data from last call. */
 138                 if (ctx->cbc_remainder_len > 0) {
 139                         need = block_size - ctx->cbc_remainder_len;
 140 
 141                         if (need > remainder)


 215 out:
 216         /*
 217          * Save the last encrypted block in the context.
 218          */
 219         if (ctx->cbc_lastp != NULL) {
 220                 copy_block((uint8_t *)ctx->cbc_lastp, (uint8_t *)ctx->cbc_iv);
 221                 ctx->cbc_lastp = (uint8_t *)ctx->cbc_iv;
 222         }
 223 
 224         return (CRYPTO_SUCCESS);
 225 }
 226 
 227 #define OTHER(a, ctx) \
 228         (((a) == (ctx)->cbc_lastblock) ? (ctx)->cbc_iv : (ctx)->cbc_lastblock)
 229 
 230 /* ARGSUSED */
 231 int
 232 cbc_decrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
 233     crypto_data_t *out, size_t block_size,
 234     int (*decrypt)(const void *, const uint8_t *, uint8_t *),
 235     void (*copy_block)(const uint8_t *, uint8_t *),
 236     void (*xor_block)(const uint8_t *, uint8_t *),
 237     int (*decrypt_ecb)(const void *, const uint8_t *, uint8_t *, uint64_t),
 238     void (*xor_block_range)(const uint8_t *, uint8_t *, uint64_t))
 239 {
 240         size_t remainder = length;
 241         size_t need;
 242         uint8_t *datap = (uint8_t *)data;
 243         uint8_t *blockp;
 244         uint8_t *lastp;
 245         void *iov_or_mp;
 246         offset_t offset;
 247         uint8_t *out_data_1;
 248         uint8_t *out_data_2;
 249         size_t out_data_1_len;
 250 
 251         /*
 252          * CBC decryption fastpath requirements:
 253          * - fastpath is enabled
 254          * - input is block-aligned
 255          * - output is a single contiguous region and doesn't alias input
 256          */
 257         if (cbc_fastpath_enabled && ctx->cbc_remainder_len == 0 &&
 258             length != 0 && (length & (block_size - 1)) == 0 &&
 259             CRYPTO_DATA_IS_SINGLE_BLOCK(out)) {
 260                 uint8_t *outp = CRYPTO_DATA_FIRST_BLOCK(out);
 261 
 262                 cbc_decrypt_fastpath(ctx, (uint8_t *)data, length, outp,
 263                     block_size, decrypt, decrypt_ecb, xor_block,
 264                     xor_block_range);
 265                 out->cd_offset += length;
 266                 bcopy(&data[length - block_size], ctx->cbc_iv, block_size);
 267                 ctx->cbc_lastp = (uint8_t *)ctx->cbc_iv;
 268                 return (CRYPTO_SUCCESS);
 269         }
 270 
 271         if (length + ctx->cbc_remainder_len < block_size) {
 272                 /* accumulate bytes here and return */
 273                 bcopy(datap,
 274                     (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len,
 275                     length);
 276                 ctx->cbc_remainder_len += length;
 277                 ctx->cbc_copy_to = datap;
 278                 return (CRYPTO_SUCCESS);
 279         }
 280 
 281         lastp = ctx->cbc_lastp;
 282         if (out != NULL)
 283                 crypto_init_ptrs(out, &iov_or_mp, &offset);
 284 
 285         do {
 286                 /* Unprocessed data from last call. */
 287                 if (ctx->cbc_remainder_len > 0) {
 288                         need = block_size - ctx->cbc_remainder_len;
 289 
 290                         if (need > remainder)


 348                 remainder = (size_t)&data[length] - (size_t)datap;
 349 
 350                 /* Incomplete last block. */
 351                 if (remainder > 0 && remainder < block_size) {
 352                         bcopy(datap, ctx->cbc_remainder, remainder);
 353                         ctx->cbc_remainder_len = remainder;
 354                         ctx->cbc_lastp = lastp;
 355                         ctx->cbc_copy_to = datap;
 356                         return (CRYPTO_SUCCESS);
 357                 }
 358                 ctx->cbc_copy_to = NULL;
 359 
 360         } while (remainder > 0);
 361 
 362         ctx->cbc_lastp = lastp;
 363         return (CRYPTO_SUCCESS);
 364 }
 365 
 366 int
 367 cbc_init_ctx(cbc_ctx_t *cbc_ctx, char *param, size_t param_len,
 368     size_t block_size, void (*copy_block)(const uint8_t *, uint64_t *))
 369 {
 370         /*
 371          * Copy IV into context.
 372          *
 373          * If cm_param == NULL then the IV comes from the
 374          * cd_miscdata field in the crypto_data structure.
 375          */
 376         if (param != NULL) {
 377 #ifdef _KERNEL
 378                 ASSERT(param_len == block_size);
 379 #else
 380                 assert(param_len == block_size);
 381 #endif
 382                 copy_block((uchar_t *)param, cbc_ctx->cbc_iv);
 383         }
 384 
 385         cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0];
 386         cbc_ctx->cbc_flags |= CBC_MODE;
 387         return (CRYPTO_SUCCESS);
 388 }