17188Smcpowers /* 27188Smcpowers * CDDL HEADER START 37188Smcpowers * 47188Smcpowers * The contents of this file are subject to the terms of the 57188Smcpowers * Common Development and Distribution License (the "License"). 67188Smcpowers * You may not use this file except in compliance with the License. 77188Smcpowers * 87188Smcpowers * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97188Smcpowers * or http://www.opensolaris.org/os/licensing. 107188Smcpowers * See the License for the specific language governing permissions 117188Smcpowers * and limitations under the License. 127188Smcpowers * 137188Smcpowers * When distributing Covered Code, include this CDDL HEADER in each 147188Smcpowers * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157188Smcpowers * If applicable, add the following below this CDDL HEADER, with the 167188Smcpowers * fields enclosed by brackets "[]" replaced with your own identifying 177188Smcpowers * information: Portions Copyright [yyyy] [name of copyright owner] 187188Smcpowers * 197188Smcpowers * CDDL HEADER END 207188Smcpowers */ 217188Smcpowers /* 227188Smcpowers * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237188Smcpowers * Use is subject to license terms. 247188Smcpowers */ 257188Smcpowers 267188Smcpowers #ifndef _KERNEL 277188Smcpowers #include <strings.h> 287188Smcpowers #include <limits.h> 297188Smcpowers #include <assert.h> 307188Smcpowers #include <security/cryptoki.h> 317188Smcpowers #endif 327188Smcpowers 337188Smcpowers #include <sys/types.h> 347188Smcpowers #include <modes/modes.h> 357188Smcpowers #include <sys/crypto/common.h> 367188Smcpowers #include <sys/crypto/impl.h> 377421SDaniel.Anderson@Sun.COM #include <sys/byteorder.h> 387421SDaniel.Anderson@Sun.COM 397188Smcpowers /* 407188Smcpowers * Encrypt and decrypt multiple blocks of data in counter mode. 417188Smcpowers */ 427188Smcpowers int 437188Smcpowers ctr_mode_contiguous_blocks(ctr_ctx_t *ctx, char *data, size_t length, 447188Smcpowers crypto_data_t *out, size_t block_size, 457188Smcpowers int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct), 467188Smcpowers void (*xor_block)(uint8_t *, uint8_t *)) 477188Smcpowers { 487188Smcpowers size_t remainder = length; 497188Smcpowers size_t need; 507188Smcpowers uint8_t *datap = (uint8_t *)data; 517188Smcpowers uint8_t *blockp; 527188Smcpowers uint8_t *lastp; 537188Smcpowers void *iov_or_mp; 547188Smcpowers offset_t offset; 557188Smcpowers uint8_t *out_data_1; 567188Smcpowers uint8_t *out_data_2; 577188Smcpowers size_t out_data_1_len; 58*7581SMark.Powers@Sun.COM uint64_t lower_counter, upper_counter; 597188Smcpowers 607188Smcpowers if (length + ctx->ctr_remainder_len < block_size) { 617188Smcpowers /* accumulate bytes here and return */ 627188Smcpowers bcopy(datap, 637188Smcpowers (uint8_t *)ctx->ctr_remainder + ctx->ctr_remainder_len, 647188Smcpowers length); 657188Smcpowers ctx->ctr_remainder_len += length; 667188Smcpowers ctx->ctr_copy_to = datap; 677188Smcpowers return (CRYPTO_SUCCESS); 687188Smcpowers } 697188Smcpowers 707188Smcpowers lastp = (uint8_t *)ctx->ctr_cb; 717188Smcpowers if (out != NULL) 727188Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset); 737188Smcpowers 747188Smcpowers do { 757188Smcpowers /* Unprocessed data from last call. */ 767188Smcpowers if (ctx->ctr_remainder_len > 0) { 777188Smcpowers need = block_size - ctx->ctr_remainder_len; 787188Smcpowers 797188Smcpowers if (need > remainder) 807188Smcpowers return (CRYPTO_DATA_LEN_RANGE); 817188Smcpowers 827188Smcpowers bcopy(datap, &((uint8_t *)ctx->ctr_remainder) 837188Smcpowers [ctx->ctr_remainder_len], need); 847188Smcpowers 857188Smcpowers blockp = (uint8_t *)ctx->ctr_remainder; 867188Smcpowers } else { 877188Smcpowers blockp = datap; 887188Smcpowers } 897188Smcpowers 907188Smcpowers /* ctr_cb is the counter block */ 917188Smcpowers cipher(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb, 927188Smcpowers (uint8_t *)ctx->ctr_tmp); 937188Smcpowers 947188Smcpowers lastp = (uint8_t *)ctx->ctr_tmp; 957188Smcpowers 967188Smcpowers /* 97*7581SMark.Powers@Sun.COM * Increment Counter. 987188Smcpowers */ 99*7581SMark.Powers@Sun.COM lower_counter = ntohll(ctx->ctr_cb[1] & ctx->ctr_lower_mask); 100*7581SMark.Powers@Sun.COM lower_counter = htonll(lower_counter + 1); 101*7581SMark.Powers@Sun.COM lower_counter &= ctx->ctr_lower_mask; 102*7581SMark.Powers@Sun.COM ctx->ctr_cb[1] = (ctx->ctr_cb[1] & ~(ctx->ctr_lower_mask)) | 103*7581SMark.Powers@Sun.COM lower_counter; 104*7581SMark.Powers@Sun.COM 105*7581SMark.Powers@Sun.COM /* wrap around */ 106*7581SMark.Powers@Sun.COM if (lower_counter == 0) { 107*7581SMark.Powers@Sun.COM upper_counter = 108*7581SMark.Powers@Sun.COM ntohll(ctx->ctr_cb[0] & ctx->ctr_upper_mask); 109*7581SMark.Powers@Sun.COM upper_counter = htonll(upper_counter + 1); 110*7581SMark.Powers@Sun.COM upper_counter &= ctx->ctr_upper_mask; 111*7581SMark.Powers@Sun.COM ctx->ctr_cb[0] = 112*7581SMark.Powers@Sun.COM (ctx->ctr_cb[0] & ~(ctx->ctr_upper_mask)) | 113*7581SMark.Powers@Sun.COM upper_counter; 114*7581SMark.Powers@Sun.COM } 1157188Smcpowers 1167188Smcpowers /* 117*7581SMark.Powers@Sun.COM * XOR encrypted counter block with the current clear block. 1187188Smcpowers */ 1197188Smcpowers xor_block(blockp, lastp); 1207188Smcpowers 1217188Smcpowers if (out == NULL) { 1227188Smcpowers if (ctx->ctr_remainder_len > 0) { 1237188Smcpowers bcopy(lastp, ctx->ctr_copy_to, 1247188Smcpowers ctx->ctr_remainder_len); 1257188Smcpowers bcopy(lastp + ctx->ctr_remainder_len, datap, 1267188Smcpowers need); 1277188Smcpowers } 1287188Smcpowers } else { 1297188Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 1307188Smcpowers &out_data_1_len, &out_data_2, block_size); 1317188Smcpowers 1327188Smcpowers /* copy block to where it belongs */ 1337188Smcpowers bcopy(lastp, out_data_1, out_data_1_len); 1347188Smcpowers if (out_data_2 != NULL) { 1357188Smcpowers bcopy(lastp + out_data_1_len, out_data_2, 1367188Smcpowers block_size - out_data_1_len); 1377188Smcpowers } 1387188Smcpowers /* update offset */ 1397188Smcpowers out->cd_offset += block_size; 1407188Smcpowers } 1417188Smcpowers 1427188Smcpowers /* Update pointer to next block of data to be processed. */ 1437188Smcpowers if (ctx->ctr_remainder_len != 0) { 1447188Smcpowers datap += need; 1457188Smcpowers ctx->ctr_remainder_len = 0; 1467188Smcpowers } else { 1477188Smcpowers datap += block_size; 1487188Smcpowers } 1497188Smcpowers 1507188Smcpowers remainder = (size_t)&data[length] - (size_t)datap; 1517188Smcpowers 1527188Smcpowers /* Incomplete last block. */ 1537188Smcpowers if (remainder > 0 && remainder < block_size) { 1547188Smcpowers bcopy(datap, ctx->ctr_remainder, remainder); 1557188Smcpowers ctx->ctr_remainder_len = remainder; 1567188Smcpowers ctx->ctr_copy_to = datap; 1577188Smcpowers goto out; 1587188Smcpowers } 1597188Smcpowers ctx->ctr_copy_to = NULL; 1607188Smcpowers 1617188Smcpowers } while (remainder > 0); 1627188Smcpowers 1637188Smcpowers out: 1647188Smcpowers return (CRYPTO_SUCCESS); 1657188Smcpowers } 1667188Smcpowers 1677188Smcpowers int 1687188Smcpowers ctr_mode_final(ctr_ctx_t *ctx, crypto_data_t *out, 1697188Smcpowers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *)) 1707188Smcpowers { 1717188Smcpowers uint8_t *lastp; 1727188Smcpowers void *iov_or_mp; 1737188Smcpowers offset_t offset; 1747188Smcpowers uint8_t *out_data_1; 1757188Smcpowers uint8_t *out_data_2; 1767188Smcpowers size_t out_data_1_len; 1777188Smcpowers uint8_t *p; 1787188Smcpowers int i; 1797188Smcpowers 1807188Smcpowers if (out->cd_length < ctx->ctr_remainder_len) 1817188Smcpowers return (CRYPTO_DATA_LEN_RANGE); 1827188Smcpowers 1837188Smcpowers encrypt_block(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb, 1847188Smcpowers (uint8_t *)ctx->ctr_tmp); 1857188Smcpowers 1867188Smcpowers lastp = (uint8_t *)ctx->ctr_tmp; 1877188Smcpowers p = (uint8_t *)ctx->ctr_remainder; 1887188Smcpowers for (i = 0; i < ctx->ctr_remainder_len; i++) { 1897188Smcpowers p[i] ^= lastp[i]; 1907188Smcpowers } 1917188Smcpowers 1927188Smcpowers crypto_init_ptrs(out, &iov_or_mp, &offset); 1937188Smcpowers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 1947188Smcpowers &out_data_1_len, &out_data_2, ctx->ctr_remainder_len); 1957188Smcpowers 1967188Smcpowers bcopy(p, out_data_1, out_data_1_len); 1977188Smcpowers if (out_data_2 != NULL) { 1987188Smcpowers bcopy((uint8_t *)p + out_data_1_len, 1997188Smcpowers out_data_2, ctx->ctr_remainder_len - out_data_1_len); 2007188Smcpowers } 2017188Smcpowers out->cd_offset += ctx->ctr_remainder_len; 2027188Smcpowers ctx->ctr_remainder_len = 0; 2037188Smcpowers return (CRYPTO_SUCCESS); 2047188Smcpowers } 2057188Smcpowers 2067188Smcpowers int 2077188Smcpowers ctr_init_ctx(ctr_ctx_t *ctr_ctx, ulong_t count, uint8_t *cb, 2087188Smcpowers void (*copy_block)(uint8_t *, uint8_t *)) 2097188Smcpowers { 210*7581SMark.Powers@Sun.COM uint64_t upper_mask = 0; 211*7581SMark.Powers@Sun.COM uint64_t lower_mask = 0; 2127188Smcpowers 213*7581SMark.Powers@Sun.COM if (count == 0 || count > 128) { 2147188Smcpowers return (CRYPTO_MECHANISM_PARAM_INVALID); 2157188Smcpowers } 216*7581SMark.Powers@Sun.COM /* upper 64 bits of the mask */ 217*7581SMark.Powers@Sun.COM if (count >= 64) { 218*7581SMark.Powers@Sun.COM count -= 64; 219*7581SMark.Powers@Sun.COM upper_mask = (count == 64) ? UINT64_MAX : (1ULL << count) - 1; 220*7581SMark.Powers@Sun.COM lower_mask = UINT64_MAX; 221*7581SMark.Powers@Sun.COM } else { 222*7581SMark.Powers@Sun.COM /* now the lower 63 bits */ 223*7581SMark.Powers@Sun.COM lower_mask = (1ULL << count) - 1; 224*7581SMark.Powers@Sun.COM } 225*7581SMark.Powers@Sun.COM ctr_ctx->ctr_lower_mask = htonll(lower_mask); 226*7581SMark.Powers@Sun.COM ctr_ctx->ctr_upper_mask = htonll(upper_mask); 2277421SDaniel.Anderson@Sun.COM 2287188Smcpowers copy_block(cb, (uchar_t *)ctr_ctx->ctr_cb); 2297188Smcpowers ctr_ctx->ctr_lastp = (uint8_t *)&ctr_ctx->ctr_cb[0]; 2307188Smcpowers ctr_ctx->ctr_flags |= CTR_MODE; 2317188Smcpowers return (CRYPTO_SUCCESS); 2327188Smcpowers } 2337188Smcpowers 2347188Smcpowers /* ARGSUSED */ 2357188Smcpowers void * 2367188Smcpowers ctr_alloc_ctx(int kmflag) 2377188Smcpowers { 2387188Smcpowers ctr_ctx_t *ctr_ctx; 2397188Smcpowers 2407188Smcpowers #ifdef _KERNEL 2417188Smcpowers if ((ctr_ctx = kmem_zalloc(sizeof (ctr_ctx_t), kmflag)) == NULL) 2427188Smcpowers #else 2437188Smcpowers if ((ctr_ctx = calloc(1, sizeof (ctr_ctx_t))) == NULL) 2447188Smcpowers #endif 2457188Smcpowers return (NULL); 2467188Smcpowers 2477188Smcpowers ctr_ctx->ctr_flags = CTR_MODE; 2487188Smcpowers return (ctr_ctx); 2497188Smcpowers } 250