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 #include <sys/zfs_context.h> 27 #include <modes/modes.h> 28 #include <sys/crypto/common.h> 29 #include <sys/crypto/impl.h> 30 #include <sys/byteorder.h> 31 32 /* 33 * Encrypt and decrypt multiple blocks of data in counter mode. 34 */ 35 int 36 ctr_mode_contiguous_blocks(ctr_ctx_t *ctx, char *data, size_t length, 37 crypto_data_t *out, size_t block_size, 38 int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct), 39 void (*xor_block)(uint8_t *, uint8_t *)) 40 { 41 size_t remainder = length; 42 size_t need = 0; 43 uint8_t *datap = (uint8_t *)data; 44 uint8_t *blockp; 45 uint8_t *lastp; 46 void *iov_or_mp; 47 offset_t offset; 48 uint8_t *out_data_1; 49 uint8_t *out_data_2; 50 size_t out_data_1_len; 51 uint64_t lower_counter, upper_counter; 52 53 if (length + ctx->ctr_remainder_len < block_size) { 54 /* accumulate bytes here and return */ 55 memcpy((uint8_t *)ctx->ctr_remainder + ctx->ctr_remainder_len, 56 datap, 57 length); 58 ctx->ctr_remainder_len += length; 59 ctx->ctr_copy_to = datap; 60 return (CRYPTO_SUCCESS); 61 } 62 63 lastp = (uint8_t *)ctx->ctr_cb; 64 crypto_init_ptrs(out, &iov_or_mp, &offset); 65 66 do { 67 /* Unprocessed data from last call. */ 68 if (ctx->ctr_remainder_len > 0) { 69 need = block_size - ctx->ctr_remainder_len; 70 71 if (need > remainder) 72 return (CRYPTO_DATA_LEN_RANGE); 73 74 memcpy(&((uint8_t *)ctx->ctr_remainder) 75 [ctx->ctr_remainder_len], datap, need); 76 77 blockp = (uint8_t *)ctx->ctr_remainder; 78 } else { 79 blockp = datap; 80 } 81 82 /* ctr_cb is the counter block */ 83 cipher(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb, 84 (uint8_t *)ctx->ctr_tmp); 85 86 lastp = (uint8_t *)ctx->ctr_tmp; 87 88 /* 89 * Increment Counter. 90 */ 91 lower_counter = ntohll(ctx->ctr_cb[1] & ctx->ctr_lower_mask); 92 lower_counter = htonll(lower_counter + 1); 93 lower_counter &= ctx->ctr_lower_mask; 94 ctx->ctr_cb[1] = (ctx->ctr_cb[1] & ~(ctx->ctr_lower_mask)) | 95 lower_counter; 96 97 /* wrap around */ 98 if (lower_counter == 0) { 99 upper_counter = 100 ntohll(ctx->ctr_cb[0] & ctx->ctr_upper_mask); 101 upper_counter = htonll(upper_counter + 1); 102 upper_counter &= ctx->ctr_upper_mask; 103 ctx->ctr_cb[0] = 104 (ctx->ctr_cb[0] & ~(ctx->ctr_upper_mask)) | 105 upper_counter; 106 } 107 108 /* 109 * XOR encrypted counter block with the current clear block. 110 */ 111 xor_block(blockp, lastp); 112 113 crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 114 &out_data_1_len, &out_data_2, block_size); 115 116 /* copy block to where it belongs */ 117 memcpy(out_data_1, lastp, out_data_1_len); 118 if (out_data_2 != NULL) { 119 memcpy(out_data_2, lastp + out_data_1_len, 120 block_size - out_data_1_len); 121 } 122 /* update offset */ 123 out->cd_offset += block_size; 124 125 /* Update pointer to next block of data to be processed. */ 126 if (ctx->ctr_remainder_len != 0) { 127 datap += need; 128 ctx->ctr_remainder_len = 0; 129 } else { 130 datap += block_size; 131 } 132 133 remainder = (size_t)&data[length] - (size_t)datap; 134 135 /* Incomplete last block. */ 136 if (remainder > 0 && remainder < block_size) { 137 memcpy(ctx->ctr_remainder, datap, remainder); 138 ctx->ctr_remainder_len = remainder; 139 ctx->ctr_copy_to = datap; 140 goto out; 141 } 142 ctx->ctr_copy_to = NULL; 143 144 } while (remainder > 0); 145 146 out: 147 return (CRYPTO_SUCCESS); 148 } 149 150 int 151 ctr_mode_final(ctr_ctx_t *ctx, crypto_data_t *out, 152 int (*encrypt_block)(const void *, const uint8_t *, uint8_t *)) 153 { 154 uint8_t *lastp; 155 void *iov_or_mp; 156 offset_t offset; 157 uint8_t *out_data_1; 158 uint8_t *out_data_2; 159 size_t out_data_1_len; 160 uint8_t *p; 161 int i; 162 163 if (out->cd_length < ctx->ctr_remainder_len) 164 return (CRYPTO_DATA_LEN_RANGE); 165 166 encrypt_block(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb, 167 (uint8_t *)ctx->ctr_tmp); 168 169 lastp = (uint8_t *)ctx->ctr_tmp; 170 p = (uint8_t *)ctx->ctr_remainder; 171 for (i = 0; i < ctx->ctr_remainder_len; i++) { 172 p[i] ^= lastp[i]; 173 } 174 175 crypto_init_ptrs(out, &iov_or_mp, &offset); 176 crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 177 &out_data_1_len, &out_data_2, ctx->ctr_remainder_len); 178 179 memcpy(out_data_1, p, out_data_1_len); 180 if (out_data_2 != NULL) { 181 memcpy(out_data_2, 182 (uint8_t *)p + out_data_1_len, 183 ctx->ctr_remainder_len - out_data_1_len); 184 } 185 out->cd_offset += ctx->ctr_remainder_len; 186 ctx->ctr_remainder_len = 0; 187 return (CRYPTO_SUCCESS); 188 } 189 190 int 191 ctr_init_ctx(ctr_ctx_t *ctr_ctx, ulong_t count, uint8_t *cb, 192 void (*copy_block)(uint8_t *, uint8_t *)) 193 { 194 uint64_t upper_mask = 0; 195 uint64_t lower_mask = 0; 196 197 if (count == 0 || count > 128) { 198 return (CRYPTO_MECHANISM_PARAM_INVALID); 199 } 200 /* upper 64 bits of the mask */ 201 if (count >= 64) { 202 count -= 64; 203 upper_mask = (count == 64) ? UINT64_MAX : (1ULL << count) - 1; 204 lower_mask = UINT64_MAX; 205 } else { 206 /* now the lower 63 bits */ 207 lower_mask = (1ULL << count) - 1; 208 } 209 ctr_ctx->ctr_lower_mask = htonll(lower_mask); 210 ctr_ctx->ctr_upper_mask = htonll(upper_mask); 211 212 copy_block(cb, (uchar_t *)ctr_ctx->ctr_cb); 213 ctr_ctx->ctr_lastp = (uint8_t *)&ctr_ctx->ctr_cb[0]; 214 ctr_ctx->ctr_flags |= CTR_MODE; 215 return (CRYPTO_SUCCESS); 216 } 217 218 void * 219 ctr_alloc_ctx(int kmflag) 220 { 221 ctr_ctx_t *ctr_ctx; 222 223 if ((ctr_ctx = kmem_zalloc(sizeof (ctr_ctx_t), kmflag)) == NULL) 224 return (NULL); 225 226 ctr_ctx->ctr_flags = CTR_MODE; 227 return (ctr_ctx); 228 } 229