14d703b5cSMark Powers /* 24d703b5cSMark Powers * CDDL HEADER START 34d703b5cSMark Powers * 44d703b5cSMark Powers * The contents of this file are subject to the terms of the 54d703b5cSMark Powers * Common Development and Distribution License (the "License"). 64d703b5cSMark Powers * You may not use this file except in compliance with the License. 74d703b5cSMark Powers * 84d703b5cSMark Powers * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94d703b5cSMark Powers * or http://www.opensolaris.org/os/licensing. 104d703b5cSMark Powers * See the License for the specific language governing permissions 114d703b5cSMark Powers * and limitations under the License. 124d703b5cSMark Powers * 134d703b5cSMark Powers * When distributing Covered Code, include this CDDL HEADER in each 144d703b5cSMark Powers * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154d703b5cSMark Powers * If applicable, add the following below this CDDL HEADER, with the 164d703b5cSMark Powers * fields enclosed by brackets "[]" replaced with your own identifying 174d703b5cSMark Powers * information: Portions Copyright [yyyy] [name of copyright owner] 184d703b5cSMark Powers * 194d703b5cSMark Powers * CDDL HEADER END 204d703b5cSMark Powers */ 214d703b5cSMark Powers /* 22e8c016efSMark Powers * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 234d703b5cSMark Powers * Use is subject to license terms. 244d703b5cSMark Powers */ 254d703b5cSMark Powers 264d703b5cSMark Powers #ifndef _KERNEL 274d703b5cSMark Powers #include <strings.h> 284d703b5cSMark Powers #include <limits.h> 294d703b5cSMark Powers #include <assert.h> 304d703b5cSMark Powers #include <security/cryptoki.h> 314d703b5cSMark Powers #endif 324d703b5cSMark Powers 334d703b5cSMark Powers #include <sys/types.h> 344d703b5cSMark Powers #include <sys/kmem.h> 354d703b5cSMark Powers #include <modes/modes.h> 364d703b5cSMark Powers #include <sys/crypto/common.h> 374d703b5cSMark Powers #include <sys/crypto/impl.h> 384d703b5cSMark Powers #include <sys/byteorder.h> 394d703b5cSMark Powers 404d703b5cSMark Powers struct aes_block { 414d703b5cSMark Powers uint64_t a; 424d703b5cSMark Powers uint64_t b; 434d703b5cSMark Powers }; 444d703b5cSMark Powers 45e8c016efSMark Powers void 464d703b5cSMark Powers gcm_mul(uint64_t *x_in, uint64_t *y, uint64_t *res) 474d703b5cSMark Powers { 484d703b5cSMark Powers uint64_t R = { 0xe100000000000000ULL }; 494d703b5cSMark Powers struct aes_block z = { 0, 0 }; 504d703b5cSMark Powers struct aes_block v; 514d703b5cSMark Powers uint64_t x; 524d703b5cSMark Powers int i, j; 534d703b5cSMark Powers 544d703b5cSMark Powers v.a = ntohll(y[0]); 554d703b5cSMark Powers v.b = ntohll(y[1]); 564d703b5cSMark Powers 574d703b5cSMark Powers for (j = 0; j < 2; j++) { 584d703b5cSMark Powers x = ntohll(x_in[j]); 594d703b5cSMark Powers for (i = 0; i < 64; i++, x <<= 1) { 604d703b5cSMark Powers if (x & 0x8000000000000000ULL) { 614d703b5cSMark Powers z.a ^= v.a; 624d703b5cSMark Powers z.b ^= v.b; 634d703b5cSMark Powers } 644d703b5cSMark Powers if (v.b & 1ULL) { 654d703b5cSMark Powers v.b = (v.a << 63)|(v.b >> 1); 664d703b5cSMark Powers v.a = (v.a >> 1) ^ R; 674d703b5cSMark Powers } else { 684d703b5cSMark Powers v.b = (v.a << 63)|(v.b >> 1); 694d703b5cSMark Powers v.a = v.a >> 1; 704d703b5cSMark Powers } 714d703b5cSMark Powers } 724d703b5cSMark Powers } 734d703b5cSMark Powers res[0] = htonll(z.a); 744d703b5cSMark Powers res[1] = htonll(z.b); 754d703b5cSMark Powers } 764d703b5cSMark Powers 774d703b5cSMark Powers #define GHASH(c, d, t) \ 784d703b5cSMark Powers xor_block((uint8_t *)(d), (uint8_t *)(c)->gcm_ghash); \ 794d703b5cSMark Powers gcm_mul((uint64_t *)(c)->gcm_ghash, (c)->gcm_H, (uint64_t *)(t)); 804d703b5cSMark Powers 814d703b5cSMark Powers /* 824d703b5cSMark Powers * Encrypt multiple blocks of data in GCM mode. Decrypt for GCM mode 834d703b5cSMark Powers * is done in another function. 844d703b5cSMark Powers */ 854d703b5cSMark Powers int 864d703b5cSMark Powers gcm_mode_encrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length, 874d703b5cSMark Powers crypto_data_t *out, size_t block_size, 884d703b5cSMark Powers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 894d703b5cSMark Powers void (*copy_block)(uint8_t *, uint8_t *), 904d703b5cSMark Powers void (*xor_block)(uint8_t *, uint8_t *)) 914d703b5cSMark Powers { 924d703b5cSMark Powers size_t remainder = length; 934d703b5cSMark Powers size_t need; 944d703b5cSMark Powers uint8_t *datap = (uint8_t *)data; 954d703b5cSMark Powers uint8_t *blockp; 964d703b5cSMark Powers uint8_t *lastp; 974d703b5cSMark Powers void *iov_or_mp; 984d703b5cSMark Powers offset_t offset; 994d703b5cSMark Powers uint8_t *out_data_1; 1004d703b5cSMark Powers uint8_t *out_data_2; 1014d703b5cSMark Powers size_t out_data_1_len; 1024d703b5cSMark Powers uint64_t counter; 1034d703b5cSMark Powers uint64_t counter_mask = ntohll(0x00000000ffffffffULL); 1044d703b5cSMark Powers 1054d703b5cSMark Powers if (length + ctx->gcm_remainder_len < block_size) { 1064d703b5cSMark Powers /* accumulate bytes here and return */ 1074d703b5cSMark Powers bcopy(datap, 1084d703b5cSMark Powers (uint8_t *)ctx->gcm_remainder + ctx->gcm_remainder_len, 1094d703b5cSMark Powers length); 1104d703b5cSMark Powers ctx->gcm_remainder_len += length; 1114d703b5cSMark Powers ctx->gcm_copy_to = datap; 1124d703b5cSMark Powers return (CRYPTO_SUCCESS); 1134d703b5cSMark Powers } 1144d703b5cSMark Powers 1154d703b5cSMark Powers lastp = (uint8_t *)ctx->gcm_cb; 1164d703b5cSMark Powers if (out != NULL) 1174d703b5cSMark Powers crypto_init_ptrs(out, &iov_or_mp, &offset); 1184d703b5cSMark Powers 1194d703b5cSMark Powers do { 1204d703b5cSMark Powers /* Unprocessed data from last call. */ 1214d703b5cSMark Powers if (ctx->gcm_remainder_len > 0) { 1224d703b5cSMark Powers need = block_size - ctx->gcm_remainder_len; 1234d703b5cSMark Powers 1244d703b5cSMark Powers if (need > remainder) 1254d703b5cSMark Powers return (CRYPTO_DATA_LEN_RANGE); 1264d703b5cSMark Powers 1274d703b5cSMark Powers bcopy(datap, &((uint8_t *)ctx->gcm_remainder) 1284d703b5cSMark Powers [ctx->gcm_remainder_len], need); 1294d703b5cSMark Powers 1304d703b5cSMark Powers blockp = (uint8_t *)ctx->gcm_remainder; 1314d703b5cSMark Powers } else { 1324d703b5cSMark Powers blockp = datap; 1334d703b5cSMark Powers } 1344d703b5cSMark Powers 1354d703b5cSMark Powers /* 1364d703b5cSMark Powers * Increment counter. Counter bits are confined 1374d703b5cSMark Powers * to the bottom 32 bits of the counter block. 1384d703b5cSMark Powers */ 1394d703b5cSMark Powers counter = ntohll(ctx->gcm_cb[1] & counter_mask); 1404d703b5cSMark Powers counter = htonll(counter + 1); 1414d703b5cSMark Powers counter &= counter_mask; 1424d703b5cSMark Powers ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter; 1434d703b5cSMark Powers 1444d703b5cSMark Powers encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, 1454d703b5cSMark Powers (uint8_t *)ctx->gcm_tmp); 1464d703b5cSMark Powers xor_block(blockp, (uint8_t *)ctx->gcm_tmp); 1474d703b5cSMark Powers 1484d703b5cSMark Powers lastp = (uint8_t *)ctx->gcm_tmp; 1494d703b5cSMark Powers 1504d703b5cSMark Powers ctx->gcm_processed_data_len += block_size; 1514d703b5cSMark Powers 1524d703b5cSMark Powers if (out == NULL) { 1534d703b5cSMark Powers if (ctx->gcm_remainder_len > 0) { 1544d703b5cSMark Powers bcopy(blockp, ctx->gcm_copy_to, 1554d703b5cSMark Powers ctx->gcm_remainder_len); 1564d703b5cSMark Powers bcopy(blockp + ctx->gcm_remainder_len, datap, 1574d703b5cSMark Powers need); 1584d703b5cSMark Powers } 1594d703b5cSMark Powers } else { 1604d703b5cSMark Powers crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, 1614d703b5cSMark Powers &out_data_1_len, &out_data_2, block_size); 1624d703b5cSMark Powers 1634d703b5cSMark Powers /* copy block to where it belongs */ 1644d703b5cSMark Powers if (out_data_1_len == block_size) { 1654d703b5cSMark Powers copy_block(lastp, out_data_1); 1664d703b5cSMark Powers } else { 1674d703b5cSMark Powers bcopy(lastp, out_data_1, out_data_1_len); 1684d703b5cSMark Powers if (out_data_2 != NULL) { 1694d703b5cSMark Powers bcopy(lastp + out_data_1_len, 1704d703b5cSMark Powers out_data_2, 1714d703b5cSMark Powers block_size - out_data_1_len); 1724d703b5cSMark Powers } 1734d703b5cSMark Powers } 1744d703b5cSMark Powers /* update offset */ 1754d703b5cSMark Powers out->cd_offset += block_size; 1764d703b5cSMark Powers } 1774d703b5cSMark Powers 1784d703b5cSMark Powers /* add ciphertext to the hash */ 1794d703b5cSMark Powers GHASH(ctx, ctx->gcm_tmp, ctx->gcm_ghash); 1804d703b5cSMark Powers 1814d703b5cSMark Powers /* Update pointer to next block of data to be processed. */ 1824d703b5cSMark Powers if (ctx->gcm_remainder_len != 0) { 1834d703b5cSMark Powers datap += need; 1844d703b5cSMark Powers ctx->gcm_remainder_len = 0; 1854d703b5cSMark Powers } else { 1864d703b5cSMark Powers datap += block_size; 1874d703b5cSMark Powers } 1884d703b5cSMark Powers 1894d703b5cSMark Powers remainder = (size_t)&data[length] - (size_t)datap; 1904d703b5cSMark Powers 1914d703b5cSMark Powers /* Incomplete last block. */ 1924d703b5cSMark Powers if (remainder > 0 && remainder < block_size) { 1934d703b5cSMark Powers bcopy(datap, ctx->gcm_remainder, remainder); 1944d703b5cSMark Powers ctx->gcm_remainder_len = remainder; 1954d703b5cSMark Powers ctx->gcm_copy_to = datap; 1964d703b5cSMark Powers goto out; 1974d703b5cSMark Powers } 1984d703b5cSMark Powers ctx->gcm_copy_to = NULL; 1994d703b5cSMark Powers 2004d703b5cSMark Powers } while (remainder > 0); 2014d703b5cSMark Powers out: 2024d703b5cSMark Powers return (CRYPTO_SUCCESS); 2034d703b5cSMark Powers } 2044d703b5cSMark Powers 2054d703b5cSMark Powers /* ARGSUSED */ 2064d703b5cSMark Powers int 2074d703b5cSMark Powers gcm_encrypt_final(gcm_ctx_t *ctx, crypto_data_t *out, size_t block_size, 2084d703b5cSMark Powers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 2094d703b5cSMark Powers void (*copy_block)(uint8_t *, uint8_t *), 2104d703b5cSMark Powers void (*xor_block)(uint8_t *, uint8_t *)) 2114d703b5cSMark Powers { 2124d703b5cSMark Powers uint64_t counter_mask = ntohll(0x00000000ffffffffULL); 2134d703b5cSMark Powers uint8_t *ghash, *macp; 2144d703b5cSMark Powers int i, rv; 2154d703b5cSMark Powers 2164d703b5cSMark Powers if (out->cd_length < 2174d703b5cSMark Powers (ctx->gcm_remainder_len + ctx->gcm_tag_len)) { 2184d703b5cSMark Powers return (CRYPTO_DATA_LEN_RANGE); 2194d703b5cSMark Powers } 2204d703b5cSMark Powers 2214d703b5cSMark Powers ghash = (uint8_t *)ctx->gcm_ghash; 2224d703b5cSMark Powers 2234d703b5cSMark Powers if (ctx->gcm_remainder_len > 0) { 2244d703b5cSMark Powers uint64_t counter; 2254d703b5cSMark Powers uint8_t *tmpp = (uint8_t *)ctx->gcm_tmp; 2264d703b5cSMark Powers 2274d703b5cSMark Powers /* 2284d703b5cSMark Powers * Here is where we deal with data that is not a 2294d703b5cSMark Powers * multiple of the block size. 2304d703b5cSMark Powers */ 2314d703b5cSMark Powers 2324d703b5cSMark Powers /* 2334d703b5cSMark Powers * Increment counter. 2344d703b5cSMark Powers */ 2354d703b5cSMark Powers counter = ntohll(ctx->gcm_cb[1] & counter_mask); 2364d703b5cSMark Powers counter = htonll(counter + 1); 2374d703b5cSMark Powers counter &= counter_mask; 2384d703b5cSMark Powers ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter; 2394d703b5cSMark Powers 2404d703b5cSMark Powers encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, 2414d703b5cSMark Powers (uint8_t *)ctx->gcm_tmp); 2424d703b5cSMark Powers 2434d703b5cSMark Powers macp = (uint8_t *)ctx->gcm_remainder; 2444d703b5cSMark Powers bzero(macp + ctx->gcm_remainder_len, 2454d703b5cSMark Powers block_size - ctx->gcm_remainder_len); 2464d703b5cSMark Powers 2474d703b5cSMark Powers /* XOR with counter block */ 2484d703b5cSMark Powers for (i = 0; i < ctx->gcm_remainder_len; i++) { 2494d703b5cSMark Powers macp[i] ^= tmpp[i]; 2504d703b5cSMark Powers } 2514d703b5cSMark Powers 2524d703b5cSMark Powers /* add ciphertext to the hash */ 2534d703b5cSMark Powers GHASH(ctx, macp, ghash); 2544d703b5cSMark Powers 2554d703b5cSMark Powers ctx->gcm_processed_data_len += ctx->gcm_remainder_len; 2564d703b5cSMark Powers } 2574d703b5cSMark Powers 2584d703b5cSMark Powers ctx->gcm_len_a_len_c[1] = htonll(ctx->gcm_processed_data_len << 3); 2594d703b5cSMark Powers GHASH(ctx, ctx->gcm_len_a_len_c, ghash); 2604d703b5cSMark Powers encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_J0, 2614d703b5cSMark Powers (uint8_t *)ctx->gcm_J0); 2624d703b5cSMark Powers xor_block((uint8_t *)ctx->gcm_J0, ghash); 2634d703b5cSMark Powers 2644d703b5cSMark Powers if (ctx->gcm_remainder_len > 0) { 2654d703b5cSMark Powers rv = crypto_put_output_data(macp, out, ctx->gcm_remainder_len); 2664d703b5cSMark Powers if (rv != CRYPTO_SUCCESS) 2674d703b5cSMark Powers return (rv); 2684d703b5cSMark Powers } 2694d703b5cSMark Powers out->cd_offset += ctx->gcm_remainder_len; 2704d703b5cSMark Powers ctx->gcm_remainder_len = 0; 2714d703b5cSMark Powers rv = crypto_put_output_data(ghash, out, ctx->gcm_tag_len); 2724d703b5cSMark Powers if (rv != CRYPTO_SUCCESS) 2734d703b5cSMark Powers return (rv); 2744d703b5cSMark Powers out->cd_offset += ctx->gcm_tag_len; 2754d703b5cSMark Powers 2764d703b5cSMark Powers return (CRYPTO_SUCCESS); 2774d703b5cSMark Powers } 2784d703b5cSMark Powers 2794d703b5cSMark Powers /* 2804d703b5cSMark Powers * This will only deal with decrypting the last block of the input that 2814d703b5cSMark Powers * might not be a multiple of block length. 2824d703b5cSMark Powers */ 2834d703b5cSMark Powers static void 2844d703b5cSMark Powers gcm_decrypt_incomplete_block(gcm_ctx_t *ctx, size_t block_size, size_t index, 2854d703b5cSMark Powers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 2864d703b5cSMark Powers void (*xor_block)(uint8_t *, uint8_t *)) 2874d703b5cSMark Powers { 2884d703b5cSMark Powers uint8_t *datap, *outp, *counterp; 2894d703b5cSMark Powers uint64_t counter; 2904d703b5cSMark Powers uint64_t counter_mask = ntohll(0x00000000ffffffffULL); 2914d703b5cSMark Powers int i; 2924d703b5cSMark Powers 2934d703b5cSMark Powers /* 2944d703b5cSMark Powers * Increment counter. 2954d703b5cSMark Powers * Counter bits are confined to the bottom 32 bits 2964d703b5cSMark Powers */ 2974d703b5cSMark Powers counter = ntohll(ctx->gcm_cb[1] & counter_mask); 2984d703b5cSMark Powers counter = htonll(counter + 1); 2994d703b5cSMark Powers counter &= counter_mask; 3004d703b5cSMark Powers ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter; 3014d703b5cSMark Powers 3024d703b5cSMark Powers datap = (uint8_t *)ctx->gcm_remainder; 3034d703b5cSMark Powers outp = &((ctx->gcm_pt_buf)[index]); 3044d703b5cSMark Powers counterp = (uint8_t *)ctx->gcm_tmp; 3054d703b5cSMark Powers 3064d703b5cSMark Powers /* authentication tag */ 3074d703b5cSMark Powers bzero((uint8_t *)ctx->gcm_tmp, block_size); 3084d703b5cSMark Powers bcopy(datap, (uint8_t *)ctx->gcm_tmp, ctx->gcm_remainder_len); 3094d703b5cSMark Powers 3104d703b5cSMark Powers /* add ciphertext to the hash */ 3114d703b5cSMark Powers GHASH(ctx, ctx->gcm_tmp, ctx->gcm_ghash); 3124d703b5cSMark Powers 3134d703b5cSMark Powers /* decrypt remaining ciphertext */ 3144d703b5cSMark Powers encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, counterp); 3154d703b5cSMark Powers 3164d703b5cSMark Powers /* XOR with counter block */ 3174d703b5cSMark Powers for (i = 0; i < ctx->gcm_remainder_len; i++) { 3184d703b5cSMark Powers outp[i] = datap[i] ^ counterp[i]; 3194d703b5cSMark Powers } 3204d703b5cSMark Powers } 3214d703b5cSMark Powers 3224d703b5cSMark Powers /* ARGSUSED */ 3234d703b5cSMark Powers int 3244d703b5cSMark Powers gcm_mode_decrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length, 3254d703b5cSMark Powers crypto_data_t *out, size_t block_size, 3264d703b5cSMark Powers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 3274d703b5cSMark Powers void (*copy_block)(uint8_t *, uint8_t *), 3284d703b5cSMark Powers void (*xor_block)(uint8_t *, uint8_t *)) 3294d703b5cSMark Powers { 3304d703b5cSMark Powers size_t new_len; 3314d703b5cSMark Powers uint8_t *new; 3324d703b5cSMark Powers 3334d703b5cSMark Powers /* 3344d703b5cSMark Powers * Copy contiguous ciphertext input blocks to plaintext buffer. 3354d703b5cSMark Powers * Ciphertext will be decrypted in the final. 3364d703b5cSMark Powers */ 3374d703b5cSMark Powers if (length > 0) { 3384d703b5cSMark Powers new_len = ctx->gcm_pt_buf_len + length; 3394d703b5cSMark Powers #ifdef _KERNEL 3404d703b5cSMark Powers new = kmem_alloc(new_len, ctx->gcm_kmflag); 3414d703b5cSMark Powers bcopy(ctx->gcm_pt_buf, new, ctx->gcm_pt_buf_len); 3424d703b5cSMark Powers kmem_free(ctx->gcm_pt_buf, ctx->gcm_pt_buf_len); 3434d703b5cSMark Powers #else 3444d703b5cSMark Powers new = malloc(new_len); 3454d703b5cSMark Powers bcopy(ctx->gcm_pt_buf, new, ctx->gcm_pt_buf_len); 3464d703b5cSMark Powers free(ctx->gcm_pt_buf); 3474d703b5cSMark Powers #endif 3484d703b5cSMark Powers if (new == NULL) 3494d703b5cSMark Powers return (CRYPTO_HOST_MEMORY); 3504d703b5cSMark Powers 3514d703b5cSMark Powers ctx->gcm_pt_buf = new; 3524d703b5cSMark Powers ctx->gcm_pt_buf_len = new_len; 3534d703b5cSMark Powers bcopy(data, &ctx->gcm_pt_buf[ctx->gcm_processed_data_len], 3544d703b5cSMark Powers length); 3554d703b5cSMark Powers ctx->gcm_processed_data_len += length; 3564d703b5cSMark Powers } 3574d703b5cSMark Powers 3584d703b5cSMark Powers ctx->gcm_remainder_len = 0; 3594d703b5cSMark Powers return (CRYPTO_SUCCESS); 3604d703b5cSMark Powers } 3614d703b5cSMark Powers 3624d703b5cSMark Powers int 3634d703b5cSMark Powers gcm_decrypt_final(gcm_ctx_t *ctx, crypto_data_t *out, size_t block_size, 3644d703b5cSMark Powers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 3654d703b5cSMark Powers void (*xor_block)(uint8_t *, uint8_t *)) 3664d703b5cSMark Powers { 3674d703b5cSMark Powers size_t pt_len; 3684d703b5cSMark Powers size_t remainder; 3694d703b5cSMark Powers uint8_t *ghash; 3704d703b5cSMark Powers uint8_t *blockp; 3714d703b5cSMark Powers uint8_t *cbp; 3724d703b5cSMark Powers uint64_t counter; 3734d703b5cSMark Powers uint64_t counter_mask = ntohll(0x00000000ffffffffULL); 3744d703b5cSMark Powers int processed = 0, rv; 3754d703b5cSMark Powers 3764d703b5cSMark Powers ASSERT(ctx->gcm_processed_data_len == ctx->gcm_pt_buf_len); 3774d703b5cSMark Powers 3784d703b5cSMark Powers pt_len = ctx->gcm_processed_data_len - ctx->gcm_tag_len; 3794d703b5cSMark Powers ghash = (uint8_t *)ctx->gcm_ghash; 3804d703b5cSMark Powers blockp = ctx->gcm_pt_buf; 3814d703b5cSMark Powers remainder = pt_len; 3824d703b5cSMark Powers while (remainder > 0) { 3834d703b5cSMark Powers /* add ciphertext to the hash */ 3844d703b5cSMark Powers GHASH(ctx, blockp, ghash); 3854d703b5cSMark Powers 3864d703b5cSMark Powers /* 3874d703b5cSMark Powers * Increment counter. 3884d703b5cSMark Powers * Counter bits are confined to the bottom 32 bits 3894d703b5cSMark Powers */ 3904d703b5cSMark Powers counter = ntohll(ctx->gcm_cb[1] & counter_mask); 3914d703b5cSMark Powers counter = htonll(counter + 1); 3924d703b5cSMark Powers counter &= counter_mask; 3934d703b5cSMark Powers ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter; 3944d703b5cSMark Powers 3954d703b5cSMark Powers cbp = (uint8_t *)ctx->gcm_tmp; 3964d703b5cSMark Powers encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, cbp); 3974d703b5cSMark Powers 3984d703b5cSMark Powers /* XOR with ciphertext */ 3994d703b5cSMark Powers xor_block(cbp, blockp); 4004d703b5cSMark Powers 4014d703b5cSMark Powers processed += block_size; 4024d703b5cSMark Powers blockp += block_size; 4034d703b5cSMark Powers remainder -= block_size; 4044d703b5cSMark Powers 4054d703b5cSMark Powers /* Incomplete last block */ 4064d703b5cSMark Powers if (remainder > 0 && remainder < block_size) { 4074d703b5cSMark Powers bcopy(blockp, ctx->gcm_remainder, remainder); 4084d703b5cSMark Powers ctx->gcm_remainder_len = remainder; 4094d703b5cSMark Powers /* 4104d703b5cSMark Powers * not expecting anymore ciphertext, just 4114d703b5cSMark Powers * compute plaintext for the remaining input 4124d703b5cSMark Powers */ 4134d703b5cSMark Powers gcm_decrypt_incomplete_block(ctx, block_size, 4144d703b5cSMark Powers processed, encrypt_block, xor_block); 4154d703b5cSMark Powers ctx->gcm_remainder_len = 0; 4164d703b5cSMark Powers goto out; 4174d703b5cSMark Powers } 4184d703b5cSMark Powers } 4194d703b5cSMark Powers out: 4204d703b5cSMark Powers ctx->gcm_len_a_len_c[1] = htonll(pt_len << 3); 4214d703b5cSMark Powers GHASH(ctx, ctx->gcm_len_a_len_c, ghash); 4224d703b5cSMark Powers encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_J0, 4234d703b5cSMark Powers (uint8_t *)ctx->gcm_J0); 4244d703b5cSMark Powers xor_block((uint8_t *)ctx->gcm_J0, ghash); 4254d703b5cSMark Powers 4264d703b5cSMark Powers /* compare the input authentication tag with what we calculated */ 4274d703b5cSMark Powers if (bcmp(&ctx->gcm_pt_buf[pt_len], ghash, ctx->gcm_tag_len)) { 4284d703b5cSMark Powers /* They don't match */ 4294d703b5cSMark Powers return (CRYPTO_INVALID_MAC); 4304d703b5cSMark Powers } else { 4314d703b5cSMark Powers rv = crypto_put_output_data(ctx->gcm_pt_buf, out, pt_len); 4324d703b5cSMark Powers if (rv != CRYPTO_SUCCESS) 4334d703b5cSMark Powers return (rv); 4344d703b5cSMark Powers out->cd_offset += pt_len; 4354d703b5cSMark Powers } 4364d703b5cSMark Powers return (CRYPTO_SUCCESS); 4374d703b5cSMark Powers } 4384d703b5cSMark Powers 4394d703b5cSMark Powers static int 4404d703b5cSMark Powers gcm_validate_args(CK_AES_GCM_PARAMS *gcm_param) 4414d703b5cSMark Powers { 4424d703b5cSMark Powers size_t tag_len; 4434d703b5cSMark Powers 4444d703b5cSMark Powers /* 4454d703b5cSMark Powers * Check the length of the authentication tag (in bits). 4464d703b5cSMark Powers */ 4474d703b5cSMark Powers tag_len = gcm_param->ulTagBits; 4484d703b5cSMark Powers switch (tag_len) { 4494d703b5cSMark Powers case 32: 4504d703b5cSMark Powers case 64: 4514d703b5cSMark Powers case 96: 4524d703b5cSMark Powers case 104: 4534d703b5cSMark Powers case 112: 4544d703b5cSMark Powers case 120: 4554d703b5cSMark Powers case 128: 4564d703b5cSMark Powers break; 4574d703b5cSMark Powers default: 4584d703b5cSMark Powers return (CRYPTO_MECHANISM_PARAM_INVALID); 4594d703b5cSMark Powers } 4604d703b5cSMark Powers 4614d703b5cSMark Powers if (gcm_param->ulIvLen == 0) 4624d703b5cSMark Powers return (CRYPTO_MECHANISM_PARAM_INVALID); 4634d703b5cSMark Powers 4644d703b5cSMark Powers return (CRYPTO_SUCCESS); 4654d703b5cSMark Powers } 4664d703b5cSMark Powers 4674d703b5cSMark Powers static void 4684d703b5cSMark Powers gcm_format_initial_blocks(uchar_t *iv, ulong_t iv_len, 4694d703b5cSMark Powers gcm_ctx_t *ctx, size_t block_size, 4704d703b5cSMark Powers void (*copy_block)(uint8_t *, uint8_t *), 4714d703b5cSMark Powers void (*xor_block)(uint8_t *, uint8_t *)) 4724d703b5cSMark Powers { 4734d703b5cSMark Powers uint8_t *cb; 4744d703b5cSMark Powers ulong_t remainder = iv_len; 4754d703b5cSMark Powers ulong_t processed = 0; 4764d703b5cSMark Powers uint8_t *datap, *ghash; 4774d703b5cSMark Powers uint64_t len_a_len_c[2]; 4784d703b5cSMark Powers 4794d703b5cSMark Powers ghash = (uint8_t *)ctx->gcm_ghash; 4804d703b5cSMark Powers cb = (uint8_t *)ctx->gcm_cb; 4814d703b5cSMark Powers if (iv_len == 12) { 4824d703b5cSMark Powers bcopy(iv, cb, 12); 4834d703b5cSMark Powers cb[12] = 0; 4844d703b5cSMark Powers cb[13] = 0; 4854d703b5cSMark Powers cb[14] = 0; 4864d703b5cSMark Powers cb[15] = 1; 4874d703b5cSMark Powers /* J0 will be used again in the final */ 4884d703b5cSMark Powers copy_block(cb, (uint8_t *)ctx->gcm_J0); 4894d703b5cSMark Powers } else { 4904d703b5cSMark Powers /* GHASH the IV */ 4914d703b5cSMark Powers do { 4924d703b5cSMark Powers if (remainder < block_size) { 4934d703b5cSMark Powers bzero(cb, block_size); 4944d703b5cSMark Powers bcopy(&(iv[processed]), cb, remainder); 4954d703b5cSMark Powers datap = (uint8_t *)cb; 4964d703b5cSMark Powers remainder = 0; 4974d703b5cSMark Powers } else { 4984d703b5cSMark Powers datap = (uint8_t *)(&(iv[processed])); 4994d703b5cSMark Powers processed += block_size; 5004d703b5cSMark Powers remainder -= block_size; 5014d703b5cSMark Powers } 5024d703b5cSMark Powers GHASH(ctx, datap, ghash); 5034d703b5cSMark Powers } while (remainder > 0); 5044d703b5cSMark Powers 5054d703b5cSMark Powers len_a_len_c[0] = 0; 5064d703b5cSMark Powers len_a_len_c[1] = htonll(iv_len << 3); 5074d703b5cSMark Powers GHASH(ctx, len_a_len_c, ctx->gcm_J0); 5084d703b5cSMark Powers 5094d703b5cSMark Powers /* J0 will be used again in the final */ 5104d703b5cSMark Powers copy_block((uint8_t *)ctx->gcm_J0, (uint8_t *)cb); 5114d703b5cSMark Powers } 5124d703b5cSMark Powers } 5134d703b5cSMark Powers 5144d703b5cSMark Powers /* 5154d703b5cSMark Powers * The following function is called at encrypt or decrypt init time 5164d703b5cSMark Powers * for AES GCM mode. 5174d703b5cSMark Powers */ 5184d703b5cSMark Powers int 5194d703b5cSMark Powers gcm_init(gcm_ctx_t *ctx, unsigned char *iv, size_t iv_len, 5204d703b5cSMark Powers unsigned char *auth_data, size_t auth_data_len, size_t block_size, 5214d703b5cSMark Powers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 5224d703b5cSMark Powers void (*copy_block)(uint8_t *, uint8_t *), 5234d703b5cSMark Powers void (*xor_block)(uint8_t *, uint8_t *)) 5244d703b5cSMark Powers { 5254d703b5cSMark Powers uint8_t *ghash, *datap, *authp; 5264d703b5cSMark Powers size_t remainder, processed; 5274d703b5cSMark Powers 5284d703b5cSMark Powers /* encrypt zero block to get subkey H */ 5294d703b5cSMark Powers bzero(ctx->gcm_H, sizeof (ctx->gcm_H)); 5304d703b5cSMark Powers encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_H, 5314d703b5cSMark Powers (uint8_t *)ctx->gcm_H); 5324d703b5cSMark Powers 5334d703b5cSMark Powers gcm_format_initial_blocks(iv, iv_len, ctx, block_size, 5344d703b5cSMark Powers copy_block, xor_block); 5354d703b5cSMark Powers 5364d703b5cSMark Powers authp = (uint8_t *)ctx->gcm_tmp; 5374d703b5cSMark Powers ghash = (uint8_t *)ctx->gcm_ghash; 5384d703b5cSMark Powers bzero(authp, block_size); 5394d703b5cSMark Powers bzero(ghash, block_size); 5404d703b5cSMark Powers 5414d703b5cSMark Powers processed = 0; 5424d703b5cSMark Powers remainder = auth_data_len; 5434d703b5cSMark Powers do { 5444d703b5cSMark Powers if (remainder < block_size) { 5454d703b5cSMark Powers /* 5464d703b5cSMark Powers * There's not a block full of data, pad rest of 5474d703b5cSMark Powers * buffer with zero 5484d703b5cSMark Powers */ 5494d703b5cSMark Powers bzero(authp, block_size); 5504d703b5cSMark Powers bcopy(&(auth_data[processed]), authp, remainder); 5514d703b5cSMark Powers datap = (uint8_t *)authp; 5524d703b5cSMark Powers remainder = 0; 5534d703b5cSMark Powers } else { 5544d703b5cSMark Powers datap = (uint8_t *)(&(auth_data[processed])); 5554d703b5cSMark Powers processed += block_size; 5564d703b5cSMark Powers remainder -= block_size; 5574d703b5cSMark Powers } 5584d703b5cSMark Powers 5594d703b5cSMark Powers /* add auth data to the hash */ 5604d703b5cSMark Powers GHASH(ctx, datap, ghash); 5614d703b5cSMark Powers 5624d703b5cSMark Powers } while (remainder > 0); 5634d703b5cSMark Powers 5644d703b5cSMark Powers return (CRYPTO_SUCCESS); 5654d703b5cSMark Powers } 5664d703b5cSMark Powers 5674d703b5cSMark Powers int 5684d703b5cSMark Powers gcm_init_ctx(gcm_ctx_t *gcm_ctx, char *param, size_t block_size, 5694d703b5cSMark Powers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 5704d703b5cSMark Powers void (*copy_block)(uint8_t *, uint8_t *), 5714d703b5cSMark Powers void (*xor_block)(uint8_t *, uint8_t *)) 5724d703b5cSMark Powers { 5734d703b5cSMark Powers int rv; 5744d703b5cSMark Powers CK_AES_GCM_PARAMS *gcm_param; 5754d703b5cSMark Powers 5764d703b5cSMark Powers if (param != NULL) { 5774d703b5cSMark Powers gcm_param = (CK_AES_GCM_PARAMS *)param; 5784d703b5cSMark Powers 5794d703b5cSMark Powers if ((rv = gcm_validate_args(gcm_param)) != 0) { 5804d703b5cSMark Powers return (rv); 5814d703b5cSMark Powers } 5824d703b5cSMark Powers 5834d703b5cSMark Powers gcm_ctx->gcm_tag_len = gcm_param->ulTagBits; 5844d703b5cSMark Powers gcm_ctx->gcm_tag_len >>= 3; 5854d703b5cSMark Powers gcm_ctx->gcm_processed_data_len = 0; 5864d703b5cSMark Powers 5874d703b5cSMark Powers /* these values are in bits */ 5884d703b5cSMark Powers gcm_ctx->gcm_len_a_len_c[0] = htonll(gcm_param->ulAADLen << 3); 5894d703b5cSMark Powers 5904d703b5cSMark Powers rv = CRYPTO_SUCCESS; 5914d703b5cSMark Powers gcm_ctx->gcm_flags |= GCM_MODE; 5924d703b5cSMark Powers } else { 5934d703b5cSMark Powers rv = CRYPTO_MECHANISM_PARAM_INVALID; 5944d703b5cSMark Powers goto out; 5954d703b5cSMark Powers } 5964d703b5cSMark Powers 5974d703b5cSMark Powers if (gcm_init(gcm_ctx, gcm_param->pIv, gcm_param->ulIvLen, 5984d703b5cSMark Powers gcm_param->pAAD, gcm_param->ulAADLen, block_size, 5994d703b5cSMark Powers encrypt_block, copy_block, xor_block) != 0) { 6004d703b5cSMark Powers rv = CRYPTO_MECHANISM_PARAM_INVALID; 6014d703b5cSMark Powers } 6024d703b5cSMark Powers out: 6034d703b5cSMark Powers return (rv); 6044d703b5cSMark Powers } 6054d703b5cSMark Powers 606*983a1033SMark Powers int 607*983a1033SMark Powers gmac_init_ctx(gcm_ctx_t *gcm_ctx, char *param, size_t block_size, 608*983a1033SMark Powers int (*encrypt_block)(const void *, const uint8_t *, uint8_t *), 609*983a1033SMark Powers void (*copy_block)(uint8_t *, uint8_t *), 610*983a1033SMark Powers void (*xor_block)(uint8_t *, uint8_t *)) 611*983a1033SMark Powers { 612*983a1033SMark Powers int rv; 613*983a1033SMark Powers CK_AES_GMAC_PARAMS *gmac_param; 614*983a1033SMark Powers 615*983a1033SMark Powers if (param != NULL) { 616*983a1033SMark Powers gmac_param = (CK_AES_GMAC_PARAMS *)param; 617*983a1033SMark Powers 618*983a1033SMark Powers gcm_ctx->gcm_tag_len = CRYPTO_BITS2BYTES(AES_GMAC_TAG_BITS); 619*983a1033SMark Powers gcm_ctx->gcm_processed_data_len = 0; 620*983a1033SMark Powers 621*983a1033SMark Powers /* these values are in bits */ 622*983a1033SMark Powers gcm_ctx->gcm_len_a_len_c[0] = htonll(gmac_param->ulAADLen << 3); 623*983a1033SMark Powers 624*983a1033SMark Powers rv = CRYPTO_SUCCESS; 625*983a1033SMark Powers gcm_ctx->gcm_flags |= GMAC_MODE; 626*983a1033SMark Powers } else { 627*983a1033SMark Powers rv = CRYPTO_MECHANISM_PARAM_INVALID; 628*983a1033SMark Powers goto out; 629*983a1033SMark Powers } 630*983a1033SMark Powers 631*983a1033SMark Powers if (gcm_init(gcm_ctx, gmac_param->pIv, AES_GMAC_IV_LEN, 632*983a1033SMark Powers gmac_param->pAAD, gmac_param->ulAADLen, block_size, 633*983a1033SMark Powers encrypt_block, copy_block, xor_block) != 0) { 634*983a1033SMark Powers rv = CRYPTO_MECHANISM_PARAM_INVALID; 635*983a1033SMark Powers } 636*983a1033SMark Powers out: 637*983a1033SMark Powers return (rv); 638*983a1033SMark Powers } 639*983a1033SMark Powers 6404d703b5cSMark Powers void * 6414d703b5cSMark Powers gcm_alloc_ctx(int kmflag) 6424d703b5cSMark Powers { 6434d703b5cSMark Powers gcm_ctx_t *gcm_ctx; 6444d703b5cSMark Powers 6454d703b5cSMark Powers #ifdef _KERNEL 6464d703b5cSMark Powers if ((gcm_ctx = kmem_zalloc(sizeof (gcm_ctx_t), kmflag)) == NULL) 6474d703b5cSMark Powers #else 6484d703b5cSMark Powers if ((gcm_ctx = calloc(1, sizeof (gcm_ctx_t))) == NULL) 6494d703b5cSMark Powers #endif 6504d703b5cSMark Powers return (NULL); 6514d703b5cSMark Powers 6524d703b5cSMark Powers gcm_ctx->gcm_flags = GCM_MODE; 6534d703b5cSMark Powers return (gcm_ctx); 6544d703b5cSMark Powers } 6554d703b5cSMark Powers 656*983a1033SMark Powers void * 657*983a1033SMark Powers gmac_alloc_ctx(int kmflag) 658*983a1033SMark Powers { 659*983a1033SMark Powers gcm_ctx_t *gcm_ctx; 660*983a1033SMark Powers 661*983a1033SMark Powers #ifdef _KERNEL 662*983a1033SMark Powers if ((gcm_ctx = kmem_zalloc(sizeof (gcm_ctx_t), kmflag)) == NULL) 663*983a1033SMark Powers #else 664*983a1033SMark Powers if ((gcm_ctx = calloc(1, sizeof (gcm_ctx_t))) == NULL) 665*983a1033SMark Powers #endif 666*983a1033SMark Powers return (NULL); 667*983a1033SMark Powers 668*983a1033SMark Powers gcm_ctx->gcm_flags = GMAC_MODE; 669*983a1033SMark Powers return (gcm_ctx); 670*983a1033SMark Powers } 671*983a1033SMark Powers 6724d703b5cSMark Powers void 6734d703b5cSMark Powers gcm_set_kmflag(gcm_ctx_t *ctx, int kmflag) 6744d703b5cSMark Powers { 6754d703b5cSMark Powers ctx->gcm_kmflag = kmflag; 6764d703b5cSMark Powers } 677