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 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #ifndef _KERNEL 29 #include <strings.h> 30 #include <limits.h> 31 #include <assert.h> 32 #include <security/cryptoki.h> 33 #endif 34 35 #include <sys/types.h> 36 #include <modes/modes.h> 37 #include <sys/crypto/common.h> 38 #include <sys/crypto/impl.h> 39 40 /* 41 * Algorithm independent CBC functions. 42 */ 43 int 44 cbc_encrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length, 45 crypto_data_t *out, size_t block_size, 46 int (*encrypt)(const void *, const uint8_t *, uint8_t *), 47 void (*copy_block)(uint8_t *, uint8_t *), 48 void (*xor_block)(uint8_t *, uint8_t *)) 49 { 50 size_t remainder = length; 51 size_t need; 52 uint8_t *datap = (uint8_t *)data; 53 uint8_t *blockp; 54 uint8_t *lastp; 55 void *iov_or_mp; 56 offset_t offset; 57 uint8_t *out_data_1; 58 uint8_t *out_data_2; 59 size_t out_data_1_len; 60 61 if (length + ctx->cc_remainder_len < block_size) { 62 /* accumulate bytes here and return */ 63 bcopy(datap, 64 (uint8_t *)ctx->cc_remainder + ctx->cc_remainder_len, 65 length); 66 ctx->cc_remainder_len += length; 67 ctx->cc_copy_to = datap; 68 return (CRYPTO_SUCCESS); 69 } 70 71 lastp = (uint8_t *)ctx->cc_iv; 72 if (out != NULL) 73 crypto_init_ptrs(out, &iov_or_mp, &offset); 74 75 do { 76 /* Unprocessed data from last call. */ 77 if (ctx->cc_remainder_len > 0) { 78 need = block_size - ctx->cc_remainder_len; 79 80 if (need > remainder) 81 return (CRYPTO_DATA_LEN_RANGE); 82 83 bcopy(datap, &((uint8_t *)ctx->cc_remainder) 84 [ctx->cc_remainder_len], need); 85 86 blockp = (uint8_t *)ctx->cc_remainder; 87 } else { 88 blockp = datap; 89 } 90 91 if (out == NULL) { 92 /* 93 * XOR the previous cipher block or IV with the 94 * current clear block. 95 */ 96 xor_block(lastp, blockp); 97 encrypt(ctx->cc_keysched, blockp, blockp); 98 99 ctx->cc_lastp = blockp; 100 lastp = blockp; 101 102 if (ctx->cc_remainder_len > 0) { 103 bcopy(blockp, ctx->cc_copy_to, 104 ctx->cc_remainder_len); 105 bcopy(blockp + ctx->cc_remainder_len, datap, 106 need); 107 } 108 } else { 109 /* 110 * XOR the previous cipher block or IV with the 111 * current clear block. 112 */ 113 xor_block(blockp, lastp); 114 encrypt(ctx->cc_keysched, lastp, lastp); 115 crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 116 &out_data_1_len, &out_data_2, block_size); 117 118 /* copy block to where it belongs */ 119 if (out_data_1_len == block_size) { 120 copy_block(lastp, out_data_1); 121 } else { 122 bcopy(lastp, out_data_1, out_data_1_len); 123 if (out_data_2 != NULL) { 124 bcopy(lastp + out_data_1_len, 125 out_data_2, 126 block_size - out_data_1_len); 127 } 128 } 129 /* update offset */ 130 out->cd_offset += block_size; 131 } 132 133 /* Update pointer to next block of data to be processed. */ 134 if (ctx->cc_remainder_len != 0) { 135 datap += need; 136 ctx->cc_remainder_len = 0; 137 } else { 138 datap += block_size; 139 } 140 141 remainder = (size_t)&data[length] - (size_t)datap; 142 143 /* Incomplete last block. */ 144 if (remainder > 0 && remainder < block_size) { 145 bcopy(datap, ctx->cc_remainder, remainder); 146 ctx->cc_remainder_len = remainder; 147 ctx->cc_copy_to = datap; 148 goto out; 149 } 150 ctx->cc_copy_to = NULL; 151 152 } while (remainder > 0); 153 154 out: 155 /* 156 * Save the last encrypted block in the context. 157 */ 158 if (ctx->cc_lastp != NULL) { 159 copy_block((uint8_t *)ctx->cc_lastp, (uint8_t *)ctx->cc_iv); 160 ctx->cc_lastp = (uint8_t *)ctx->cc_iv; 161 } 162 163 return (CRYPTO_SUCCESS); 164 } 165 166 #define OTHER(a, ctx) \ 167 (((a) == (ctx)->cc_lastblock) ? (ctx)->cc_iv : (ctx)->cc_lastblock) 168 169 /* ARGSUSED */ 170 int 171 cbc_decrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length, 172 crypto_data_t *out, size_t block_size, 173 int (*decrypt)(const void *, const uint8_t *, uint8_t *), 174 void (*copy_block)(uint8_t *, uint8_t *), 175 void (*xor_block)(uint8_t *, uint8_t *)) 176 { 177 size_t remainder = length; 178 size_t need; 179 uint8_t *datap = (uint8_t *)data; 180 uint8_t *blockp; 181 uint8_t *lastp; 182 void *iov_or_mp; 183 offset_t offset; 184 uint8_t *out_data_1; 185 uint8_t *out_data_2; 186 size_t out_data_1_len; 187 188 if (length + ctx->cc_remainder_len < block_size) { 189 /* accumulate bytes here and return */ 190 bcopy(datap, 191 (uint8_t *)ctx->cc_remainder + ctx->cc_remainder_len, 192 length); 193 ctx->cc_remainder_len += length; 194 ctx->cc_copy_to = datap; 195 return (CRYPTO_SUCCESS); 196 } 197 198 lastp = ctx->cc_lastp; 199 if (out != NULL) 200 crypto_init_ptrs(out, &iov_or_mp, &offset); 201 202 do { 203 /* Unprocessed data from last call. */ 204 if (ctx->cc_remainder_len > 0) { 205 need = block_size - ctx->cc_remainder_len; 206 207 if (need > remainder) 208 return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE); 209 210 bcopy(datap, &((uint8_t *)ctx->cc_remainder) 211 [ctx->cc_remainder_len], need); 212 213 blockp = (uint8_t *)ctx->cc_remainder; 214 } else { 215 blockp = datap; 216 } 217 218 /* LINTED: pointer alignment */ 219 copy_block(blockp, (uint8_t *)OTHER((uint64_t *)lastp, ctx)); 220 221 if (out != NULL) { 222 decrypt(ctx->cc_keysched, blockp, 223 (uint8_t *)ctx->cc_remainder); 224 blockp = (uint8_t *)ctx->cc_remainder; 225 } else { 226 decrypt(ctx->cc_keysched, blockp, blockp); 227 } 228 229 /* 230 * XOR the previous cipher block or IV with the 231 * currently decrypted block. 232 */ 233 xor_block(lastp, blockp); 234 235 /* LINTED: pointer alignment */ 236 lastp = (uint8_t *)OTHER((uint64_t *)lastp, ctx); 237 238 if (out != NULL) { 239 crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 240 &out_data_1_len, &out_data_2, block_size); 241 242 bcopy(blockp, out_data_1, out_data_1_len); 243 if (out_data_2 != NULL) { 244 bcopy(blockp + out_data_1_len, out_data_2, 245 block_size - out_data_1_len); 246 } 247 248 /* update offset */ 249 out->cd_offset += block_size; 250 251 } else if (ctx->cc_remainder_len > 0) { 252 /* copy temporary block to where it belongs */ 253 bcopy(blockp, ctx->cc_copy_to, ctx->cc_remainder_len); 254 bcopy(blockp + ctx->cc_remainder_len, datap, need); 255 } 256 257 /* Update pointer to next block of data to be processed. */ 258 if (ctx->cc_remainder_len != 0) { 259 datap += need; 260 ctx->cc_remainder_len = 0; 261 } else { 262 datap += block_size; 263 } 264 265 remainder = (size_t)&data[length] - (size_t)datap; 266 267 /* Incomplete last block. */ 268 if (remainder > 0 && remainder < block_size) { 269 bcopy(datap, ctx->cc_remainder, remainder); 270 ctx->cc_remainder_len = remainder; 271 ctx->cc_lastp = lastp; 272 ctx->cc_copy_to = datap; 273 return (CRYPTO_SUCCESS); 274 } 275 ctx->cc_copy_to = NULL; 276 277 } while (remainder > 0); 278 279 ctx->cc_lastp = lastp; 280 return (CRYPTO_SUCCESS); 281 } 282 283 int 284 cbc_init_ctx(cbc_ctx_t *cbc_ctx, char *param, size_t param_len, 285 size_t block_size, void (*copy_block)(uint8_t *, uint64_t *)) 286 { 287 /* 288 * Copy IV into context. 289 * 290 * If cm_param == NULL then the IV comes from the 291 * cd_miscdata field in the crypto_data structure. 292 */ 293 if (param != NULL) { 294 #ifdef _KERNEL 295 ASSERT(param_len == block_size); 296 #else 297 assert(param_len == block_size); 298 #endif 299 copy_block((uchar_t *)param, cbc_ctx->cc_iv); 300 } 301 302 cbc_ctx->cc_lastp = (uint8_t *)&cbc_ctx->cc_iv[0]; 303 cbc_ctx->cc_flags |= CBC_MODE; 304 return (CRYPTO_SUCCESS); 305 } 306 307 /* ARGSUSED */ 308 void * 309 cbc_alloc_ctx(int kmflag) 310 { 311 cbc_ctx_t *cbc_ctx; 312 313 #ifdef _KERNEL 314 if ((cbc_ctx = kmem_zalloc(sizeof (cbc_ctx_t), kmflag)) == NULL) 315 #else 316 if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL) 317 #endif 318 return (NULL); 319 320 cbc_ctx->cc_flags = CBC_MODE; 321 return (cbc_ctx); 322 } 323