1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   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 ECB functions.
  40  */
  41 int
  42 ecb_cipher_contiguous_blocks(ecb_ctx_t *ctx, char *data, size_t length,
  43     crypto_data_t *out, size_t block_size,
  44     int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct))
  45 {
  46         size_t remainder = length;
  47         size_t need;
  48         uint8_t *datap = (uint8_t *)data;
  49         uint8_t *blockp;
  50         uint8_t *lastp;
  51         void *iov_or_mp;
  52         offset_t offset;
  53         uint8_t *out_data_1;
  54         uint8_t *out_data_2;
  55         size_t out_data_1_len;
  56 
  57         if (length + ctx->ecb_remainder_len < block_size) {
  58                 /* accumulate bytes here and return */
  59                 bcopy(datap,
  60                     (uint8_t *)ctx->ecb_remainder + ctx->ecb_remainder_len,
  61                     length);
  62                 ctx->ecb_remainder_len += length;
  63                 ctx->ecb_copy_to = datap;
  64                 return (CRYPTO_SUCCESS);
  65         }
  66 
  67         lastp = (uint8_t *)ctx->ecb_iv;
  68         if (out != NULL)
  69                 crypto_init_ptrs(out, &iov_or_mp, &offset);
  70 
  71         do {
  72                 /* Unprocessed data from last call. */
  73                 if (ctx->ecb_remainder_len > 0) {
  74                         need = block_size - ctx->ecb_remainder_len;
  75 
  76                         if (need > remainder)
  77                                 return (CRYPTO_DATA_LEN_RANGE);
  78 
  79                         bcopy(datap, &((uint8_t *)ctx->ecb_remainder)
  80                             [ctx->ecb_remainder_len], need);
  81 
  82                         blockp = (uint8_t *)ctx->ecb_remainder;
  83                 } else {
  84                         blockp = datap;
  85                 }
  86 
  87                 if (out == NULL) {
  88                         cipher(ctx->ecb_keysched, blockp, blockp);
  89 
  90                         ctx->ecb_lastp = blockp;
  91                         lastp = blockp;
  92 
  93                         if (ctx->ecb_remainder_len > 0) {
  94                                 bcopy(blockp, ctx->ecb_copy_to,
  95                                     ctx->ecb_remainder_len);
  96                                 bcopy(blockp + ctx->ecb_remainder_len, datap,
  97                                     need);
  98                         }
  99                 } else {
 100                         cipher(ctx->ecb_keysched, blockp, lastp);
 101                         crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
 102                             &out_data_1_len, &out_data_2, block_size);
 103 
 104                         /* copy block to where it belongs */
 105                         bcopy(lastp, out_data_1, out_data_1_len);
 106                         if (out_data_2 != NULL) {
 107                                 bcopy(lastp + out_data_1_len, out_data_2,
 108                                     block_size - out_data_1_len);
 109                         }
 110                         /* update offset */
 111                         out->cd_offset += block_size;
 112                 }
 113 
 114                 /* Update pointer to next block of data to be processed. */
 115                 if (ctx->ecb_remainder_len != 0) {
 116                         datap += need;
 117                         ctx->ecb_remainder_len = 0;
 118                 } else {
 119                         datap += block_size;
 120                 }
 121 
 122                 remainder = (size_t)&data[length] - (size_t)datap;
 123 
 124                 /* Incomplete last block. */
 125                 if (remainder > 0 && remainder < block_size) {
 126                         bcopy(datap, ctx->ecb_remainder, remainder);
 127                         ctx->ecb_remainder_len = remainder;
 128                         ctx->ecb_copy_to = datap;
 129                         goto out;
 130                 }
 131                 ctx->ecb_copy_to = NULL;
 132 
 133         } while (remainder > 0);
 134 
 135 out:
 136         return (CRYPTO_SUCCESS);
 137 }
 138 
 139 /* ARGSUSED */
 140 void *
 141 ecb_alloc_ctx(int kmflag)
 142 {
 143         ecb_ctx_t *ecb_ctx;
 144 
 145 #ifdef _KERNEL
 146         if ((ecb_ctx = kmem_zalloc(sizeof (ecb_ctx_t), kmflag)) == NULL)
 147 #else
 148         if ((ecb_ctx = calloc(1, sizeof (ecb_ctx_t))) == NULL)
 149 #endif
 150                 return (NULL);
 151 
 152         ecb_ctx->ecb_flags = ECB_MODE;
 153         return (ecb_ctx);
 154 }