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 https://opensource.org/licenses/CDDL-1.0. 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 #include <sys/zfs_context.h> 27 #include <modes/modes.h> 28 #include <sys/crypto/common.h> 29 #include <sys/crypto/impl.h> 30 31 /* 32 * Algorithm independent ECB functions. 33 */ 34 int 35 ecb_cipher_contiguous_blocks(ecb_ctx_t *ctx, char *data, size_t length, 36 crypto_data_t *out, size_t block_size, 37 int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct)) 38 { 39 size_t remainder = length; 40 size_t need = 0; 41 uint8_t *datap = (uint8_t *)data; 42 uint8_t *blockp; 43 uint8_t *lastp; 44 void *iov_or_mp; 45 offset_t offset; 46 uint8_t *out_data_1; 47 uint8_t *out_data_2; 48 size_t out_data_1_len; 49 50 if (length + ctx->ecb_remainder_len < block_size) { 51 /* accumulate bytes here and return */ 52 memcpy((uint8_t *)ctx->ecb_remainder + ctx->ecb_remainder_len, 53 datap, 54 length); 55 ctx->ecb_remainder_len += length; 56 ctx->ecb_copy_to = datap; 57 return (CRYPTO_SUCCESS); 58 } 59 60 lastp = (uint8_t *)ctx->ecb_iv; 61 crypto_init_ptrs(out, &iov_or_mp, &offset); 62 63 do { 64 /* Unprocessed data from last call. */ 65 if (ctx->ecb_remainder_len > 0) { 66 need = block_size - ctx->ecb_remainder_len; 67 68 if (need > remainder) 69 return (CRYPTO_DATA_LEN_RANGE); 70 71 memcpy(&((uint8_t *)ctx->ecb_remainder) 72 [ctx->ecb_remainder_len], datap, need); 73 74 blockp = (uint8_t *)ctx->ecb_remainder; 75 } else { 76 blockp = datap; 77 } 78 79 cipher(ctx->ecb_keysched, blockp, lastp); 80 crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 81 &out_data_1_len, &out_data_2, block_size); 82 83 /* copy block to where it belongs */ 84 memcpy(out_data_1, lastp, out_data_1_len); 85 if (out_data_2 != NULL) { 86 memcpy(out_data_2, lastp + out_data_1_len, 87 block_size - out_data_1_len); 88 } 89 /* update offset */ 90 out->cd_offset += block_size; 91 92 /* Update pointer to next block of data to be processed. */ 93 if (ctx->ecb_remainder_len != 0) { 94 datap += need; 95 ctx->ecb_remainder_len = 0; 96 } else { 97 datap += block_size; 98 } 99 100 remainder = (size_t)&data[length] - (size_t)datap; 101 102 /* Incomplete last block. */ 103 if (remainder > 0 && remainder < block_size) { 104 memcpy(ctx->ecb_remainder, datap, remainder); 105 ctx->ecb_remainder_len = remainder; 106 ctx->ecb_copy_to = datap; 107 goto out; 108 } 109 ctx->ecb_copy_to = NULL; 110 111 } while (remainder > 0); 112 113 out: 114 return (CRYPTO_SUCCESS); 115 } 116 117 void * 118 ecb_alloc_ctx(int kmflag) 119 { 120 ecb_ctx_t *ecb_ctx; 121 122 if ((ecb_ctx = kmem_zalloc(sizeof (ecb_ctx_t), kmflag)) == NULL) 123 return (NULL); 124 125 ecb_ctx->ecb_flags = ECB_MODE; 126 return (ecb_ctx); 127 } 128