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 * 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 ecb_fastpath_enabled = B_TRUE; 43 44 /* 45 * Algorithm independent ECB functions. 46 * `cipher' is a single-block version of the cipher function to be performed 47 * on each input block. `cipher_ecb' is an optional parameter, which if 48 * passed and the input/output conditions allow it, will be invoked for the 49 * entire input buffer once to accelerate the operation. 50 */ 51 int 52 ecb_cipher_contiguous_blocks(ecb_ctx_t *ctx, char *data, size_t length, 53 crypto_data_t *out, size_t block_size, 54 int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct), 55 int (*cipher_ecb)(const void *ks, const uint8_t *pt, uint8_t *ct, 56 uint64_t len)) 57 { 58 size_t remainder = length; 59 size_t need; 60 uint8_t *datap = (uint8_t *)data; 61 uint8_t *blockp; 62 uint8_t *lastp; 63 void *iov_or_mp; 64 offset_t offset; 65 uint8_t *out_data_1; 66 uint8_t *out_data_2; 67 size_t out_data_1_len; 68 69 /* 70 * ECB encryption/decryption fastpath requirements: 71 * - fastpath is enabled 72 * - caller passed an accelerated ECB version of the cipher function 73 * - input is block-aligned 74 * - output is a single contiguous region or the user requested that 75 * we overwrite their input buffer (input/output aliasing allowed) 76 */ 77 if (ecb_fastpath_enabled && cipher_ecb != NULL && 78 ctx->ecb_remainder_len == 0 && length % block_size == 0 && 79 (out == NULL || CRYPTO_DATA_IS_SINGLE_BLOCK(out))) { 80 if (out == NULL) { 81 cipher_ecb(ctx->ecb_keysched, (uint8_t *)data, 82 (uint8_t *)data, length); 83 } else { 84 cipher_ecb(ctx->ecb_keysched, (uint8_t *)data, 85 CRYPTO_DATA_FIRST_BLOCK(out), length); 86 out->cd_offset += length; 87 } 88 return (CRYPTO_SUCCESS); 89 } 90 91 if (length + ctx->ecb_remainder_len < block_size) { 92 /* accumulate bytes here and return */ 93 bcopy(datap, 94 (uint8_t *)ctx->ecb_remainder + ctx->ecb_remainder_len, 95 length); 96 ctx->ecb_remainder_len += length; 97 ctx->ecb_copy_to = datap; 98 return (CRYPTO_SUCCESS); 99 } 100 101 lastp = (uint8_t *)ctx->ecb_iv; 102 if (out != NULL) 103 crypto_init_ptrs(out, &iov_or_mp, &offset); 104 105 do { 106 /* Unprocessed data from last call. */ 107 if (ctx->ecb_remainder_len > 0) { 108 need = block_size - ctx->ecb_remainder_len; 109 110 if (need > remainder) 111 return (CRYPTO_DATA_LEN_RANGE); 112 113 bcopy(datap, &((uint8_t *)ctx->ecb_remainder) 114 [ctx->ecb_remainder_len], need); 115 116 blockp = (uint8_t *)ctx->ecb_remainder; 117 } else { 118 blockp = datap; 119 } 120 121 if (out == NULL) { 122 cipher(ctx->ecb_keysched, blockp, blockp); 123 124 ctx->ecb_lastp = blockp; 125 lastp = blockp; 126 127 if (ctx->ecb_remainder_len > 0) { 128 bcopy(blockp, ctx->ecb_copy_to, 129 ctx->ecb_remainder_len); 130 bcopy(blockp + ctx->ecb_remainder_len, datap, 131 need); 132 } 133 } else { 134 cipher(ctx->ecb_keysched, blockp, lastp); 135 crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 136 &out_data_1_len, &out_data_2, block_size); 137 138 /* copy block to where it belongs */ 139 bcopy(lastp, out_data_1, out_data_1_len); 140 if (out_data_2 != NULL) { 141 bcopy(lastp + out_data_1_len, out_data_2, 142 block_size - out_data_1_len); 143 } 144 /* update offset */ 145 out->cd_offset += block_size; 146 } 147 148 /* Update pointer to next block of data to be processed. */ 149 if (ctx->ecb_remainder_len != 0) { 150 datap += need; 151 ctx->ecb_remainder_len = 0; 152 } else { 153 datap += block_size; 154 } 155 156 remainder = (size_t)&data[length] - (size_t)datap; 157 158 /* Incomplete last block. */ 159 if (remainder > 0 && remainder < block_size) { 160 bcopy(datap, ctx->ecb_remainder, remainder); 161 ctx->ecb_remainder_len = remainder; 162 ctx->ecb_copy_to = datap; 163 goto out; 164 } 165 ctx->ecb_copy_to = NULL; 166 167 } while (remainder > 0); 168 169 out: 170 return (CRYPTO_SUCCESS); 171 } 172 173 /* ARGSUSED */ 174 void * 175 ecb_alloc_ctx(int kmflag) 176 { 177 ecb_ctx_t *ecb_ctx; 178 179 #ifdef _KERNEL 180 if ((ecb_ctx = kmem_zalloc(sizeof (ecb_ctx_t), kmflag)) == NULL) 181 #else 182 if ((ecb_ctx = calloc(1, sizeof (ecb_ctx_t))) == NULL) 183 #endif 184 return (NULL); 185 186 ecb_ctx->ecb_flags = ECB_MODE; 187 return (ecb_ctx); 188 }