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