xref: /titanic_50/usr/src/common/crypto/modes/gcm.c (revision 553d52d4675c67a5de5a10ad30305be1a208e218)
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 /*
2295014fbbSDan OpenSolaris Anderson  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
234d703b5cSMark Powers  * Use is subject to license terms.
244d703b5cSMark Powers  */
254d703b5cSMark Powers 
26104d3bdeSDan OpenSolaris Anderson 
274d703b5cSMark Powers #ifndef _KERNEL
284d703b5cSMark Powers #include <strings.h>
294d703b5cSMark Powers #include <limits.h>
304d703b5cSMark Powers #include <assert.h>
314d703b5cSMark Powers #include <security/cryptoki.h>
32104d3bdeSDan OpenSolaris Anderson #endif	/* _KERNEL */
33104d3bdeSDan OpenSolaris Anderson 
344d703b5cSMark Powers 
354d703b5cSMark Powers #include <sys/types.h>
364d703b5cSMark Powers #include <sys/kmem.h>
374d703b5cSMark Powers #include <modes/modes.h>
384d703b5cSMark Powers #include <sys/crypto/common.h>
394d703b5cSMark Powers #include <sys/crypto/impl.h>
404d703b5cSMark Powers #include <sys/byteorder.h>
414d703b5cSMark Powers 
42104d3bdeSDan OpenSolaris Anderson #ifdef __amd64
43104d3bdeSDan OpenSolaris Anderson 
4495fddab5SDan OpenSolaris Anderson #ifdef _KERNEL
45104d3bdeSDan OpenSolaris Anderson #include <sys/cpuvar.h>		/* cpu_t, CPU */
4695fddab5SDan OpenSolaris Anderson #include <sys/x86_archext.h>	/* x86_feature, X86_*, CPUID_* */
47104d3bdeSDan OpenSolaris Anderson #include <sys/disp.h>		/* kpreempt_disable(), kpreempt_enable */
48104d3bdeSDan OpenSolaris Anderson /* Workaround for no XMM kernel thread save/restore */
49104d3bdeSDan OpenSolaris Anderson #define	KPREEMPT_DISABLE	kpreempt_disable()
50104d3bdeSDan OpenSolaris Anderson #define	KPREEMPT_ENABLE		kpreempt_enable()
51104d3bdeSDan OpenSolaris Anderson 
52104d3bdeSDan OpenSolaris Anderson #else
53104d3bdeSDan OpenSolaris Anderson #include <sys/auxv.h>		/* getisax() */
54104d3bdeSDan OpenSolaris Anderson #include <sys/auxv_386.h>	/* AV_386_PCLMULQDQ bit */
55104d3bdeSDan OpenSolaris Anderson #define	KPREEMPT_DISABLE
56104d3bdeSDan OpenSolaris Anderson #define	KPREEMPT_ENABLE
57104d3bdeSDan OpenSolaris Anderson #endif	/* _KERNEL */
58104d3bdeSDan OpenSolaris Anderson 
59104d3bdeSDan OpenSolaris Anderson extern void gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res);
60104d3bdeSDan OpenSolaris Anderson static int intel_pclmulqdq_instruction_present(void);
61104d3bdeSDan OpenSolaris Anderson #endif	/* __amd64 */
62104d3bdeSDan OpenSolaris Anderson 
634d703b5cSMark Powers struct aes_block {
644d703b5cSMark Powers 	uint64_t a;
654d703b5cSMark Powers 	uint64_t b;
664d703b5cSMark Powers };
674d703b5cSMark Powers 
68104d3bdeSDan OpenSolaris Anderson 
69104d3bdeSDan OpenSolaris Anderson /*
70104d3bdeSDan OpenSolaris Anderson  * gcm_mul()
71104d3bdeSDan OpenSolaris Anderson  * Perform a carry-less multiplication (that is, use XOR instead of the
72104d3bdeSDan OpenSolaris Anderson  * multiply operator) on *x_in and *y and place the result in *res.
73104d3bdeSDan OpenSolaris Anderson  *
74104d3bdeSDan OpenSolaris Anderson  * Byte swap the input (*x_in and *y) and the output (*res).
75104d3bdeSDan OpenSolaris Anderson  *
76104d3bdeSDan OpenSolaris Anderson  * Note: x_in, y, and res all point to 16-byte numbers (an array of two
77104d3bdeSDan OpenSolaris Anderson  * 64-bit integers).
78104d3bdeSDan OpenSolaris Anderson  */
79e8c016efSMark Powers void
804d703b5cSMark Powers gcm_mul(uint64_t *x_in, uint64_t *y, uint64_t *res)
814d703b5cSMark Powers {
82104d3bdeSDan OpenSolaris Anderson #ifdef __amd64
83104d3bdeSDan OpenSolaris Anderson 	if (intel_pclmulqdq_instruction_present()) {
84104d3bdeSDan OpenSolaris Anderson 		KPREEMPT_DISABLE;
85104d3bdeSDan OpenSolaris Anderson 		gcm_mul_pclmulqdq(x_in, y, res);
86104d3bdeSDan OpenSolaris Anderson 		KPREEMPT_ENABLE;
87104d3bdeSDan OpenSolaris Anderson 	} else
88104d3bdeSDan OpenSolaris Anderson #endif	/* __amd64 */
89104d3bdeSDan OpenSolaris Anderson 	{
90104d3bdeSDan OpenSolaris Anderson 		static const uint64_t R = 0xe100000000000000ULL;
914d703b5cSMark Powers 		struct aes_block z = {0, 0};
924d703b5cSMark Powers 		struct aes_block v;
934d703b5cSMark Powers 		uint64_t x;
944d703b5cSMark Powers 		int i, j;
954d703b5cSMark Powers 
964d703b5cSMark Powers 		v.a = ntohll(y[0]);
974d703b5cSMark Powers 		v.b = ntohll(y[1]);
984d703b5cSMark Powers 
994d703b5cSMark Powers 		for (j = 0; j < 2; j++) {
1004d703b5cSMark Powers 			x = ntohll(x_in[j]);
1014d703b5cSMark Powers 			for (i = 0; i < 64; i++, x <<= 1) {
1024d703b5cSMark Powers 				if (x & 0x8000000000000000ULL) {
1034d703b5cSMark Powers 					z.a ^= v.a;
1044d703b5cSMark Powers 					z.b ^= v.b;
1054d703b5cSMark Powers 				}
1064d703b5cSMark Powers 				if (v.b & 1ULL) {
1074d703b5cSMark Powers 					v.b = (v.a << 63)|(v.b >> 1);
1084d703b5cSMark Powers 					v.a = (v.a >> 1) ^ R;
1094d703b5cSMark Powers 				} else {
1104d703b5cSMark Powers 					v.b = (v.a << 63)|(v.b >> 1);
1114d703b5cSMark Powers 					v.a = v.a >> 1;
1124d703b5cSMark Powers 				}
1134d703b5cSMark Powers 			}
1144d703b5cSMark Powers 		}
1154d703b5cSMark Powers 		res[0] = htonll(z.a);
1164d703b5cSMark Powers 		res[1] = htonll(z.b);
1174d703b5cSMark Powers 	}
118104d3bdeSDan OpenSolaris Anderson }
119104d3bdeSDan OpenSolaris Anderson 
1204d703b5cSMark Powers 
1214d703b5cSMark Powers #define	GHASH(c, d, t) \
1224d703b5cSMark Powers 	xor_block((uint8_t *)(d), (uint8_t *)(c)->gcm_ghash); \
12395014fbbSDan OpenSolaris Anderson 	gcm_mul((uint64_t *)(void *)(c)->gcm_ghash, (c)->gcm_H, \
12495014fbbSDan OpenSolaris Anderson 	(uint64_t *)(void *)(t));
12595014fbbSDan OpenSolaris Anderson 
1264d703b5cSMark Powers 
1274d703b5cSMark Powers /*
1284d703b5cSMark Powers  * Encrypt multiple blocks of data in GCM mode.  Decrypt for GCM mode
1294d703b5cSMark Powers  * is done in another function.
1304d703b5cSMark Powers  */
1314d703b5cSMark Powers int
1324d703b5cSMark Powers gcm_mode_encrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length,
1334d703b5cSMark Powers     crypto_data_t *out, size_t block_size,
1344d703b5cSMark Powers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
1354d703b5cSMark Powers     void (*copy_block)(uint8_t *, uint8_t *),
1364d703b5cSMark Powers     void (*xor_block)(uint8_t *, uint8_t *))
1374d703b5cSMark Powers {
1384d703b5cSMark Powers 	size_t remainder = length;
1394d703b5cSMark Powers 	size_t need;
1404d703b5cSMark Powers 	uint8_t *datap = (uint8_t *)data;
1414d703b5cSMark Powers 	uint8_t *blockp;
1424d703b5cSMark Powers 	uint8_t *lastp;
1434d703b5cSMark Powers 	void *iov_or_mp;
1444d703b5cSMark Powers 	offset_t offset;
1454d703b5cSMark Powers 	uint8_t *out_data_1;
1464d703b5cSMark Powers 	uint8_t *out_data_2;
1474d703b5cSMark Powers 	size_t out_data_1_len;
1484d703b5cSMark Powers 	uint64_t counter;
1494d703b5cSMark Powers 	uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
1504d703b5cSMark Powers 
1514d703b5cSMark Powers 	if (length + ctx->gcm_remainder_len < block_size) {
1524d703b5cSMark Powers 		/* accumulate bytes here and return */
1534d703b5cSMark Powers 		bcopy(datap,
1544d703b5cSMark Powers 		    (uint8_t *)ctx->gcm_remainder + ctx->gcm_remainder_len,
1554d703b5cSMark Powers 		    length);
1564d703b5cSMark Powers 		ctx->gcm_remainder_len += length;
1574d703b5cSMark Powers 		ctx->gcm_copy_to = datap;
1584d703b5cSMark Powers 		return (CRYPTO_SUCCESS);
1594d703b5cSMark Powers 	}
1604d703b5cSMark Powers 
1614d703b5cSMark Powers 	lastp = (uint8_t *)ctx->gcm_cb;
1624d703b5cSMark Powers 	if (out != NULL)
1634d703b5cSMark Powers 		crypto_init_ptrs(out, &iov_or_mp, &offset);
1644d703b5cSMark Powers 
1654d703b5cSMark Powers 	do {
1664d703b5cSMark Powers 		/* Unprocessed data from last call. */
1674d703b5cSMark Powers 		if (ctx->gcm_remainder_len > 0) {
1684d703b5cSMark Powers 			need = block_size - ctx->gcm_remainder_len;
1694d703b5cSMark Powers 
1704d703b5cSMark Powers 			if (need > remainder)
1714d703b5cSMark Powers 				return (CRYPTO_DATA_LEN_RANGE);
1724d703b5cSMark Powers 
1734d703b5cSMark Powers 			bcopy(datap, &((uint8_t *)ctx->gcm_remainder)
1744d703b5cSMark Powers 			    [ctx->gcm_remainder_len], need);
1754d703b5cSMark Powers 
1764d703b5cSMark Powers 			blockp = (uint8_t *)ctx->gcm_remainder;
1774d703b5cSMark Powers 		} else {
1784d703b5cSMark Powers 			blockp = datap;
1794d703b5cSMark Powers 		}
1804d703b5cSMark Powers 
1814d703b5cSMark Powers 		/*
1824d703b5cSMark Powers 		 * Increment counter. Counter bits are confined
1834d703b5cSMark Powers 		 * to the bottom 32 bits of the counter block.
1844d703b5cSMark Powers 		 */
1854d703b5cSMark Powers 		counter = ntohll(ctx->gcm_cb[1] & counter_mask);
1864d703b5cSMark Powers 		counter = htonll(counter + 1);
1874d703b5cSMark Powers 		counter &= counter_mask;
1884d703b5cSMark Powers 		ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
1894d703b5cSMark Powers 
1904d703b5cSMark Powers 		encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb,
1914d703b5cSMark Powers 		    (uint8_t *)ctx->gcm_tmp);
1924d703b5cSMark Powers 		xor_block(blockp, (uint8_t *)ctx->gcm_tmp);
1934d703b5cSMark Powers 
1944d703b5cSMark Powers 		lastp = (uint8_t *)ctx->gcm_tmp;
1954d703b5cSMark Powers 
1964d703b5cSMark Powers 		ctx->gcm_processed_data_len += block_size;
1974d703b5cSMark Powers 
1984d703b5cSMark Powers 		if (out == NULL) {
1994d703b5cSMark Powers 			if (ctx->gcm_remainder_len > 0) {
2004d703b5cSMark Powers 				bcopy(blockp, ctx->gcm_copy_to,
2014d703b5cSMark Powers 				    ctx->gcm_remainder_len);
2024d703b5cSMark Powers 				bcopy(blockp + ctx->gcm_remainder_len, datap,
2034d703b5cSMark Powers 				    need);
2044d703b5cSMark Powers 			}
2054d703b5cSMark Powers 		} else {
2064d703b5cSMark Powers 			crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
2074d703b5cSMark Powers 			    &out_data_1_len, &out_data_2, block_size);
2084d703b5cSMark Powers 
2094d703b5cSMark Powers 			/* copy block to where it belongs */
2104d703b5cSMark Powers 			if (out_data_1_len == block_size) {
2114d703b5cSMark Powers 				copy_block(lastp, out_data_1);
2124d703b5cSMark Powers 			} else {
2134d703b5cSMark Powers 				bcopy(lastp, out_data_1, out_data_1_len);
2144d703b5cSMark Powers 				if (out_data_2 != NULL) {
2154d703b5cSMark Powers 					bcopy(lastp + out_data_1_len,
2164d703b5cSMark Powers 					    out_data_2,
2174d703b5cSMark Powers 					    block_size - out_data_1_len);
2184d703b5cSMark Powers 				}
2194d703b5cSMark Powers 			}
2204d703b5cSMark Powers 			/* update offset */
2214d703b5cSMark Powers 			out->cd_offset += block_size;
2224d703b5cSMark Powers 		}
2234d703b5cSMark Powers 
2244d703b5cSMark Powers 		/* add ciphertext to the hash */
2254d703b5cSMark Powers 		GHASH(ctx, ctx->gcm_tmp, ctx->gcm_ghash);
2264d703b5cSMark Powers 
2274d703b5cSMark Powers 		/* Update pointer to next block of data to be processed. */
2284d703b5cSMark Powers 		if (ctx->gcm_remainder_len != 0) {
2294d703b5cSMark Powers 			datap += need;
2304d703b5cSMark Powers 			ctx->gcm_remainder_len = 0;
2314d703b5cSMark Powers 		} else {
2324d703b5cSMark Powers 			datap += block_size;
2334d703b5cSMark Powers 		}
2344d703b5cSMark Powers 
2354d703b5cSMark Powers 		remainder = (size_t)&data[length] - (size_t)datap;
2364d703b5cSMark Powers 
2374d703b5cSMark Powers 		/* Incomplete last block. */
2384d703b5cSMark Powers 		if (remainder > 0 && remainder < block_size) {
2394d703b5cSMark Powers 			bcopy(datap, ctx->gcm_remainder, remainder);
2404d703b5cSMark Powers 			ctx->gcm_remainder_len = remainder;
2414d703b5cSMark Powers 			ctx->gcm_copy_to = datap;
2424d703b5cSMark Powers 			goto out;
2434d703b5cSMark Powers 		}
2444d703b5cSMark Powers 		ctx->gcm_copy_to = NULL;
2454d703b5cSMark Powers 
2464d703b5cSMark Powers 	} while (remainder > 0);
2474d703b5cSMark Powers out:
2484d703b5cSMark Powers 	return (CRYPTO_SUCCESS);
2494d703b5cSMark Powers }
2504d703b5cSMark Powers 
2514d703b5cSMark Powers /* ARGSUSED */
2524d703b5cSMark Powers int
2534d703b5cSMark Powers gcm_encrypt_final(gcm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
2544d703b5cSMark Powers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
2554d703b5cSMark Powers     void (*copy_block)(uint8_t *, uint8_t *),
2564d703b5cSMark Powers     void (*xor_block)(uint8_t *, uint8_t *))
2574d703b5cSMark Powers {
2584d703b5cSMark Powers 	uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
2594d703b5cSMark Powers 	uint8_t *ghash, *macp;
2604d703b5cSMark Powers 	int i, rv;
2614d703b5cSMark Powers 
2624d703b5cSMark Powers 	if (out->cd_length <
2634d703b5cSMark Powers 	    (ctx->gcm_remainder_len + ctx->gcm_tag_len)) {
2644d703b5cSMark Powers 		return (CRYPTO_DATA_LEN_RANGE);
2654d703b5cSMark Powers 	}
2664d703b5cSMark Powers 
2674d703b5cSMark Powers 	ghash = (uint8_t *)ctx->gcm_ghash;
2684d703b5cSMark Powers 
2694d703b5cSMark Powers 	if (ctx->gcm_remainder_len > 0) {
2704d703b5cSMark Powers 		uint64_t counter;
2714d703b5cSMark Powers 		uint8_t *tmpp = (uint8_t *)ctx->gcm_tmp;
2724d703b5cSMark Powers 
2734d703b5cSMark Powers 		/*
2744d703b5cSMark Powers 		 * Here is where we deal with data that is not a
2754d703b5cSMark Powers 		 * multiple of the block size.
2764d703b5cSMark Powers 		 */
2774d703b5cSMark Powers 
2784d703b5cSMark Powers 		/*
2794d703b5cSMark Powers 		 * Increment counter.
2804d703b5cSMark Powers 		 */
2814d703b5cSMark Powers 		counter = ntohll(ctx->gcm_cb[1] & counter_mask);
2824d703b5cSMark Powers 		counter = htonll(counter + 1);
2834d703b5cSMark Powers 		counter &= counter_mask;
2844d703b5cSMark Powers 		ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
2854d703b5cSMark Powers 
2864d703b5cSMark Powers 		encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb,
2874d703b5cSMark Powers 		    (uint8_t *)ctx->gcm_tmp);
2884d703b5cSMark Powers 
2894d703b5cSMark Powers 		macp = (uint8_t *)ctx->gcm_remainder;
2904d703b5cSMark Powers 		bzero(macp + ctx->gcm_remainder_len,
2914d703b5cSMark Powers 		    block_size - ctx->gcm_remainder_len);
2924d703b5cSMark Powers 
2934d703b5cSMark Powers 		/* XOR with counter block */
2944d703b5cSMark Powers 		for (i = 0; i < ctx->gcm_remainder_len; i++) {
2954d703b5cSMark Powers 			macp[i] ^= tmpp[i];
2964d703b5cSMark Powers 		}
2974d703b5cSMark Powers 
2984d703b5cSMark Powers 		/* add ciphertext to the hash */
2994d703b5cSMark Powers 		GHASH(ctx, macp, ghash);
3004d703b5cSMark Powers 
3014d703b5cSMark Powers 		ctx->gcm_processed_data_len += ctx->gcm_remainder_len;
3024d703b5cSMark Powers 	}
3034d703b5cSMark Powers 
30495014fbbSDan OpenSolaris Anderson 	ctx->gcm_len_a_len_c[1] =
30595014fbbSDan OpenSolaris Anderson 	    htonll(CRYPTO_BYTES2BITS(ctx->gcm_processed_data_len));
3064d703b5cSMark Powers 	GHASH(ctx, ctx->gcm_len_a_len_c, ghash);
3074d703b5cSMark Powers 	encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_J0,
3084d703b5cSMark Powers 	    (uint8_t *)ctx->gcm_J0);
3094d703b5cSMark Powers 	xor_block((uint8_t *)ctx->gcm_J0, ghash);
3104d703b5cSMark Powers 
3114d703b5cSMark Powers 	if (ctx->gcm_remainder_len > 0) {
3124d703b5cSMark Powers 		rv = crypto_put_output_data(macp, out, ctx->gcm_remainder_len);
3134d703b5cSMark Powers 		if (rv != CRYPTO_SUCCESS)
3144d703b5cSMark Powers 			return (rv);
3154d703b5cSMark Powers 	}
3164d703b5cSMark Powers 	out->cd_offset += ctx->gcm_remainder_len;
3174d703b5cSMark Powers 	ctx->gcm_remainder_len = 0;
3184d703b5cSMark Powers 	rv = crypto_put_output_data(ghash, out, ctx->gcm_tag_len);
3194d703b5cSMark Powers 	if (rv != CRYPTO_SUCCESS)
3204d703b5cSMark Powers 		return (rv);
3214d703b5cSMark Powers 	out->cd_offset += ctx->gcm_tag_len;
3224d703b5cSMark Powers 
3234d703b5cSMark Powers 	return (CRYPTO_SUCCESS);
3244d703b5cSMark Powers }
3254d703b5cSMark Powers 
3264d703b5cSMark Powers /*
3274d703b5cSMark Powers  * This will only deal with decrypting the last block of the input that
3284d703b5cSMark Powers  * might not be a multiple of block length.
3294d703b5cSMark Powers  */
3304d703b5cSMark Powers static void
3314d703b5cSMark Powers gcm_decrypt_incomplete_block(gcm_ctx_t *ctx, size_t block_size, size_t index,
3324d703b5cSMark Powers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
3334d703b5cSMark Powers     void (*xor_block)(uint8_t *, uint8_t *))
3344d703b5cSMark Powers {
3354d703b5cSMark Powers 	uint8_t *datap, *outp, *counterp;
3364d703b5cSMark Powers 	uint64_t counter;
3374d703b5cSMark Powers 	uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
3384d703b5cSMark Powers 	int i;
3394d703b5cSMark Powers 
3404d703b5cSMark Powers 	/*
3414d703b5cSMark Powers 	 * Increment counter.
3424d703b5cSMark Powers 	 * Counter bits are confined to the bottom 32 bits
3434d703b5cSMark Powers 	 */
3444d703b5cSMark Powers 	counter = ntohll(ctx->gcm_cb[1] & counter_mask);
3454d703b5cSMark Powers 	counter = htonll(counter + 1);
3464d703b5cSMark Powers 	counter &= counter_mask;
3474d703b5cSMark Powers 	ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
3484d703b5cSMark Powers 
3494d703b5cSMark Powers 	datap = (uint8_t *)ctx->gcm_remainder;
3504d703b5cSMark Powers 	outp = &((ctx->gcm_pt_buf)[index]);
3514d703b5cSMark Powers 	counterp = (uint8_t *)ctx->gcm_tmp;
3524d703b5cSMark Powers 
3534d703b5cSMark Powers 	/* authentication tag */
3544d703b5cSMark Powers 	bzero((uint8_t *)ctx->gcm_tmp, block_size);
3554d703b5cSMark Powers 	bcopy(datap, (uint8_t *)ctx->gcm_tmp, ctx->gcm_remainder_len);
3564d703b5cSMark Powers 
3574d703b5cSMark Powers 	/* add ciphertext to the hash */
3584d703b5cSMark Powers 	GHASH(ctx, ctx->gcm_tmp, ctx->gcm_ghash);
3594d703b5cSMark Powers 
3604d703b5cSMark Powers 	/* decrypt remaining ciphertext */
3614d703b5cSMark Powers 	encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, counterp);
3624d703b5cSMark Powers 
3634d703b5cSMark Powers 	/* XOR with counter block */
3644d703b5cSMark Powers 	for (i = 0; i < ctx->gcm_remainder_len; i++) {
3654d703b5cSMark Powers 		outp[i] = datap[i] ^ counterp[i];
3664d703b5cSMark Powers 	}
3674d703b5cSMark Powers }
3684d703b5cSMark Powers 
3694d703b5cSMark Powers /* ARGSUSED */
3704d703b5cSMark Powers int
3714d703b5cSMark Powers gcm_mode_decrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length,
3724d703b5cSMark Powers     crypto_data_t *out, size_t block_size,
3734d703b5cSMark Powers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
3744d703b5cSMark Powers     void (*copy_block)(uint8_t *, uint8_t *),
3754d703b5cSMark Powers     void (*xor_block)(uint8_t *, uint8_t *))
3764d703b5cSMark Powers {
3774d703b5cSMark Powers 	size_t new_len;
3784d703b5cSMark Powers 	uint8_t *new;
3794d703b5cSMark Powers 
3804d703b5cSMark Powers 	/*
3814d703b5cSMark Powers 	 * Copy contiguous ciphertext input blocks to plaintext buffer.
3824d703b5cSMark Powers 	 * Ciphertext will be decrypted in the final.
3834d703b5cSMark Powers 	 */
3844d703b5cSMark Powers 	if (length > 0) {
3854d703b5cSMark Powers 		new_len = ctx->gcm_pt_buf_len + length;
3864d703b5cSMark Powers #ifdef _KERNEL
3874d703b5cSMark Powers 		new = kmem_alloc(new_len, ctx->gcm_kmflag);
3884d703b5cSMark Powers 		bcopy(ctx->gcm_pt_buf, new, ctx->gcm_pt_buf_len);
3894d703b5cSMark Powers 		kmem_free(ctx->gcm_pt_buf, ctx->gcm_pt_buf_len);
3904d703b5cSMark Powers #else
3914d703b5cSMark Powers 		new = malloc(new_len);
3924d703b5cSMark Powers 		bcopy(ctx->gcm_pt_buf, new, ctx->gcm_pt_buf_len);
3934d703b5cSMark Powers 		free(ctx->gcm_pt_buf);
3944d703b5cSMark Powers #endif
3954d703b5cSMark Powers 		if (new == NULL)
3964d703b5cSMark Powers 			return (CRYPTO_HOST_MEMORY);
3974d703b5cSMark Powers 
3984d703b5cSMark Powers 		ctx->gcm_pt_buf = new;
3994d703b5cSMark Powers 		ctx->gcm_pt_buf_len = new_len;
4004d703b5cSMark Powers 		bcopy(data, &ctx->gcm_pt_buf[ctx->gcm_processed_data_len],
4014d703b5cSMark Powers 		    length);
4024d703b5cSMark Powers 		ctx->gcm_processed_data_len += length;
4034d703b5cSMark Powers 	}
4044d703b5cSMark Powers 
4054d703b5cSMark Powers 	ctx->gcm_remainder_len = 0;
4064d703b5cSMark Powers 	return (CRYPTO_SUCCESS);
4074d703b5cSMark Powers }
4084d703b5cSMark Powers 
4094d703b5cSMark Powers int
4104d703b5cSMark Powers gcm_decrypt_final(gcm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
4114d703b5cSMark Powers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
4124d703b5cSMark Powers     void (*xor_block)(uint8_t *, uint8_t *))
4134d703b5cSMark Powers {
4144d703b5cSMark Powers 	size_t pt_len;
4154d703b5cSMark Powers 	size_t remainder;
4164d703b5cSMark Powers 	uint8_t *ghash;
4174d703b5cSMark Powers 	uint8_t *blockp;
4184d703b5cSMark Powers 	uint8_t *cbp;
4194d703b5cSMark Powers 	uint64_t counter;
4204d703b5cSMark Powers 	uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
4214d703b5cSMark Powers 	int processed = 0, rv;
4224d703b5cSMark Powers 
4234d703b5cSMark Powers 	ASSERT(ctx->gcm_processed_data_len == ctx->gcm_pt_buf_len);
4244d703b5cSMark Powers 
4254d703b5cSMark Powers 	pt_len = ctx->gcm_processed_data_len - ctx->gcm_tag_len;
4264d703b5cSMark Powers 	ghash = (uint8_t *)ctx->gcm_ghash;
4274d703b5cSMark Powers 	blockp = ctx->gcm_pt_buf;
4284d703b5cSMark Powers 	remainder = pt_len;
4294d703b5cSMark Powers 	while (remainder > 0) {
430*553d52d4SMark Fenwick 		/* Incomplete last block */
431*553d52d4SMark Fenwick 		if (remainder < block_size) {
432*553d52d4SMark Fenwick 			bcopy(blockp, ctx->gcm_remainder, remainder);
433*553d52d4SMark Fenwick 			ctx->gcm_remainder_len = remainder;
434*553d52d4SMark Fenwick 			/*
435*553d52d4SMark Fenwick 			 * not expecting anymore ciphertext, just
436*553d52d4SMark Fenwick 			 * compute plaintext for the remaining input
437*553d52d4SMark Fenwick 			 */
438*553d52d4SMark Fenwick 			gcm_decrypt_incomplete_block(ctx, block_size,
439*553d52d4SMark Fenwick 			    processed, encrypt_block, xor_block);
440*553d52d4SMark Fenwick 			ctx->gcm_remainder_len = 0;
441*553d52d4SMark Fenwick 			goto out;
442*553d52d4SMark Fenwick 		}
4434d703b5cSMark Powers 		/* add ciphertext to the hash */
4444d703b5cSMark Powers 		GHASH(ctx, blockp, ghash);
4454d703b5cSMark Powers 
4464d703b5cSMark Powers 		/*
4474d703b5cSMark Powers 		 * Increment counter.
4484d703b5cSMark Powers 		 * Counter bits are confined to the bottom 32 bits
4494d703b5cSMark Powers 		 */
4504d703b5cSMark Powers 		counter = ntohll(ctx->gcm_cb[1] & counter_mask);
4514d703b5cSMark Powers 		counter = htonll(counter + 1);
4524d703b5cSMark Powers 		counter &= counter_mask;
4534d703b5cSMark Powers 		ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
4544d703b5cSMark Powers 
4554d703b5cSMark Powers 		cbp = (uint8_t *)ctx->gcm_tmp;
4564d703b5cSMark Powers 		encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, cbp);
4574d703b5cSMark Powers 
4584d703b5cSMark Powers 		/* XOR with ciphertext */
4594d703b5cSMark Powers 		xor_block(cbp, blockp);
4604d703b5cSMark Powers 
4614d703b5cSMark Powers 		processed += block_size;
4624d703b5cSMark Powers 		blockp += block_size;
4634d703b5cSMark Powers 		remainder -= block_size;
4644d703b5cSMark Powers 	}
4654d703b5cSMark Powers out:
46695014fbbSDan OpenSolaris Anderson 	ctx->gcm_len_a_len_c[1] = htonll(CRYPTO_BYTES2BITS(pt_len));
4674d703b5cSMark Powers 	GHASH(ctx, ctx->gcm_len_a_len_c, ghash);
4684d703b5cSMark Powers 	encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_J0,
4694d703b5cSMark Powers 	    (uint8_t *)ctx->gcm_J0);
4704d703b5cSMark Powers 	xor_block((uint8_t *)ctx->gcm_J0, ghash);
4714d703b5cSMark Powers 
4724d703b5cSMark Powers 	/* compare the input authentication tag with what we calculated */
4734d703b5cSMark Powers 	if (bcmp(&ctx->gcm_pt_buf[pt_len], ghash, ctx->gcm_tag_len)) {
4744d703b5cSMark Powers 		/* They don't match */
4754d703b5cSMark Powers 		return (CRYPTO_INVALID_MAC);
4764d703b5cSMark Powers 	} else {
4774d703b5cSMark Powers 		rv = crypto_put_output_data(ctx->gcm_pt_buf, out, pt_len);
4784d703b5cSMark Powers 		if (rv != CRYPTO_SUCCESS)
4794d703b5cSMark Powers 			return (rv);
4804d703b5cSMark Powers 		out->cd_offset += pt_len;
4814d703b5cSMark Powers 	}
4824d703b5cSMark Powers 	return (CRYPTO_SUCCESS);
4834d703b5cSMark Powers }
4844d703b5cSMark Powers 
4854d703b5cSMark Powers static int
4864d703b5cSMark Powers gcm_validate_args(CK_AES_GCM_PARAMS *gcm_param)
4874d703b5cSMark Powers {
4884d703b5cSMark Powers 	size_t tag_len;
4894d703b5cSMark Powers 
4904d703b5cSMark Powers 	/*
4914d703b5cSMark Powers 	 * Check the length of the authentication tag (in bits).
4924d703b5cSMark Powers 	 */
4934d703b5cSMark Powers 	tag_len = gcm_param->ulTagBits;
4944d703b5cSMark Powers 	switch (tag_len) {
4954d703b5cSMark Powers 	case 32:
4964d703b5cSMark Powers 	case 64:
4974d703b5cSMark Powers 	case 96:
4984d703b5cSMark Powers 	case 104:
4994d703b5cSMark Powers 	case 112:
5004d703b5cSMark Powers 	case 120:
5014d703b5cSMark Powers 	case 128:
5024d703b5cSMark Powers 		break;
5034d703b5cSMark Powers 	default:
5044d703b5cSMark Powers 		return (CRYPTO_MECHANISM_PARAM_INVALID);
5054d703b5cSMark Powers 	}
5064d703b5cSMark Powers 
5074d703b5cSMark Powers 	if (gcm_param->ulIvLen == 0)
5084d703b5cSMark Powers 		return (CRYPTO_MECHANISM_PARAM_INVALID);
5094d703b5cSMark Powers 
5104d703b5cSMark Powers 	return (CRYPTO_SUCCESS);
5114d703b5cSMark Powers }
5124d703b5cSMark Powers 
5134d703b5cSMark Powers static void
5144d703b5cSMark Powers gcm_format_initial_blocks(uchar_t *iv, ulong_t iv_len,
5154d703b5cSMark Powers     gcm_ctx_t *ctx, size_t block_size,
5164d703b5cSMark Powers     void (*copy_block)(uint8_t *, uint8_t *),
5174d703b5cSMark Powers     void (*xor_block)(uint8_t *, uint8_t *))
5184d703b5cSMark Powers {
5194d703b5cSMark Powers 	uint8_t *cb;
5204d703b5cSMark Powers 	ulong_t remainder = iv_len;
5214d703b5cSMark Powers 	ulong_t processed = 0;
5224d703b5cSMark Powers 	uint8_t *datap, *ghash;
5234d703b5cSMark Powers 	uint64_t len_a_len_c[2];
5244d703b5cSMark Powers 
5254d703b5cSMark Powers 	ghash = (uint8_t *)ctx->gcm_ghash;
5264d703b5cSMark Powers 	cb = (uint8_t *)ctx->gcm_cb;
5274d703b5cSMark Powers 	if (iv_len == 12) {
5284d703b5cSMark Powers 		bcopy(iv, cb, 12);
5294d703b5cSMark Powers 		cb[12] = 0;
5304d703b5cSMark Powers 		cb[13] = 0;
5314d703b5cSMark Powers 		cb[14] = 0;
5324d703b5cSMark Powers 		cb[15] = 1;
5334d703b5cSMark Powers 		/* J0 will be used again in the final */
5344d703b5cSMark Powers 		copy_block(cb, (uint8_t *)ctx->gcm_J0);
5354d703b5cSMark Powers 	} else {
5364d703b5cSMark Powers 		/* GHASH the IV */
5374d703b5cSMark Powers 		do {
5384d703b5cSMark Powers 			if (remainder < block_size) {
5394d703b5cSMark Powers 				bzero(cb, block_size);
5404d703b5cSMark Powers 				bcopy(&(iv[processed]), cb, remainder);
5414d703b5cSMark Powers 				datap = (uint8_t *)cb;
5424d703b5cSMark Powers 				remainder = 0;
5434d703b5cSMark Powers 			} else {
5444d703b5cSMark Powers 				datap = (uint8_t *)(&(iv[processed]));
5454d703b5cSMark Powers 				processed += block_size;
5464d703b5cSMark Powers 				remainder -= block_size;
5474d703b5cSMark Powers 			}
5484d703b5cSMark Powers 			GHASH(ctx, datap, ghash);
5494d703b5cSMark Powers 		} while (remainder > 0);
5504d703b5cSMark Powers 
5514d703b5cSMark Powers 		len_a_len_c[0] = 0;
55295014fbbSDan OpenSolaris Anderson 		len_a_len_c[1] = htonll(CRYPTO_BYTES2BITS(iv_len));
5534d703b5cSMark Powers 		GHASH(ctx, len_a_len_c, ctx->gcm_J0);
5544d703b5cSMark Powers 
5554d703b5cSMark Powers 		/* J0 will be used again in the final */
5564d703b5cSMark Powers 		copy_block((uint8_t *)ctx->gcm_J0, (uint8_t *)cb);
5574d703b5cSMark Powers 	}
5584d703b5cSMark Powers }
5594d703b5cSMark Powers 
5604d703b5cSMark Powers /*
5614d703b5cSMark Powers  * The following function is called at encrypt or decrypt init time
5624d703b5cSMark Powers  * for AES GCM mode.
5634d703b5cSMark Powers  */
5644d703b5cSMark Powers int
5654d703b5cSMark Powers gcm_init(gcm_ctx_t *ctx, unsigned char *iv, size_t iv_len,
5664d703b5cSMark Powers     unsigned char *auth_data, size_t auth_data_len, size_t block_size,
5674d703b5cSMark Powers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
5684d703b5cSMark Powers     void (*copy_block)(uint8_t *, uint8_t *),
5694d703b5cSMark Powers     void (*xor_block)(uint8_t *, uint8_t *))
5704d703b5cSMark Powers {
5714d703b5cSMark Powers 	uint8_t *ghash, *datap, *authp;
5724d703b5cSMark Powers 	size_t remainder, processed;
5734d703b5cSMark Powers 
5744d703b5cSMark Powers 	/* encrypt zero block to get subkey H */
5754d703b5cSMark Powers 	bzero(ctx->gcm_H, sizeof (ctx->gcm_H));
5764d703b5cSMark Powers 	encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_H,
5774d703b5cSMark Powers 	    (uint8_t *)ctx->gcm_H);
5784d703b5cSMark Powers 
5794d703b5cSMark Powers 	gcm_format_initial_blocks(iv, iv_len, ctx, block_size,
5804d703b5cSMark Powers 	    copy_block, xor_block);
5814d703b5cSMark Powers 
5824d703b5cSMark Powers 	authp = (uint8_t *)ctx->gcm_tmp;
5834d703b5cSMark Powers 	ghash = (uint8_t *)ctx->gcm_ghash;
5844d703b5cSMark Powers 	bzero(authp, block_size);
5854d703b5cSMark Powers 	bzero(ghash, block_size);
5864d703b5cSMark Powers 
5874d703b5cSMark Powers 	processed = 0;
5884d703b5cSMark Powers 	remainder = auth_data_len;
5894d703b5cSMark Powers 	do {
5904d703b5cSMark Powers 		if (remainder < block_size) {
5914d703b5cSMark Powers 			/*
5924d703b5cSMark Powers 			 * There's not a block full of data, pad rest of
5934d703b5cSMark Powers 			 * buffer with zero
5944d703b5cSMark Powers 			 */
5954d703b5cSMark Powers 			bzero(authp, block_size);
5964d703b5cSMark Powers 			bcopy(&(auth_data[processed]), authp, remainder);
5974d703b5cSMark Powers 			datap = (uint8_t *)authp;
5984d703b5cSMark Powers 			remainder = 0;
5994d703b5cSMark Powers 		} else {
6004d703b5cSMark Powers 			datap = (uint8_t *)(&(auth_data[processed]));
6014d703b5cSMark Powers 			processed += block_size;
6024d703b5cSMark Powers 			remainder -= block_size;
6034d703b5cSMark Powers 		}
6044d703b5cSMark Powers 
6054d703b5cSMark Powers 		/* add auth data to the hash */
6064d703b5cSMark Powers 		GHASH(ctx, datap, ghash);
6074d703b5cSMark Powers 
6084d703b5cSMark Powers 	} while (remainder > 0);
6094d703b5cSMark Powers 
6104d703b5cSMark Powers 	return (CRYPTO_SUCCESS);
6114d703b5cSMark Powers }
6124d703b5cSMark Powers 
6134d703b5cSMark Powers int
6144d703b5cSMark Powers gcm_init_ctx(gcm_ctx_t *gcm_ctx, char *param, size_t block_size,
6154d703b5cSMark Powers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
6164d703b5cSMark Powers     void (*copy_block)(uint8_t *, uint8_t *),
6174d703b5cSMark Powers     void (*xor_block)(uint8_t *, uint8_t *))
6184d703b5cSMark Powers {
6194d703b5cSMark Powers 	int rv;
6204d703b5cSMark Powers 	CK_AES_GCM_PARAMS *gcm_param;
6214d703b5cSMark Powers 
6224d703b5cSMark Powers 	if (param != NULL) {
62395014fbbSDan OpenSolaris Anderson 		gcm_param = (CK_AES_GCM_PARAMS *)(void *)param;
6244d703b5cSMark Powers 
6254d703b5cSMark Powers 		if ((rv = gcm_validate_args(gcm_param)) != 0) {
6264d703b5cSMark Powers 			return (rv);
6274d703b5cSMark Powers 		}
6284d703b5cSMark Powers 
6294d703b5cSMark Powers 		gcm_ctx->gcm_tag_len = gcm_param->ulTagBits;
6304d703b5cSMark Powers 		gcm_ctx->gcm_tag_len >>= 3;
6314d703b5cSMark Powers 		gcm_ctx->gcm_processed_data_len = 0;
6324d703b5cSMark Powers 
6334d703b5cSMark Powers 		/* these values are in bits */
63495014fbbSDan OpenSolaris Anderson 		gcm_ctx->gcm_len_a_len_c[0]
63595014fbbSDan OpenSolaris Anderson 		    = htonll(CRYPTO_BYTES2BITS(gcm_param->ulAADLen));
6364d703b5cSMark Powers 
6374d703b5cSMark Powers 		rv = CRYPTO_SUCCESS;
6384d703b5cSMark Powers 		gcm_ctx->gcm_flags |= GCM_MODE;
6394d703b5cSMark Powers 	} else {
6404d703b5cSMark Powers 		rv = CRYPTO_MECHANISM_PARAM_INVALID;
6414d703b5cSMark Powers 		goto out;
6424d703b5cSMark Powers 	}
6434d703b5cSMark Powers 
6444d703b5cSMark Powers 	if (gcm_init(gcm_ctx, gcm_param->pIv, gcm_param->ulIvLen,
6454d703b5cSMark Powers 	    gcm_param->pAAD, gcm_param->ulAADLen, block_size,
6464d703b5cSMark Powers 	    encrypt_block, copy_block, xor_block) != 0) {
6474d703b5cSMark Powers 		rv = CRYPTO_MECHANISM_PARAM_INVALID;
6484d703b5cSMark Powers 	}
6494d703b5cSMark Powers out:
6504d703b5cSMark Powers 	return (rv);
6514d703b5cSMark Powers }
6524d703b5cSMark Powers 
653983a1033SMark Powers int
654983a1033SMark Powers gmac_init_ctx(gcm_ctx_t *gcm_ctx, char *param, size_t block_size,
655983a1033SMark Powers     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
656983a1033SMark Powers     void (*copy_block)(uint8_t *, uint8_t *),
657983a1033SMark Powers     void (*xor_block)(uint8_t *, uint8_t *))
658983a1033SMark Powers {
659983a1033SMark Powers 	int rv;
660983a1033SMark Powers 	CK_AES_GMAC_PARAMS *gmac_param;
661983a1033SMark Powers 
662983a1033SMark Powers 	if (param != NULL) {
66395014fbbSDan OpenSolaris Anderson 		gmac_param = (CK_AES_GMAC_PARAMS *)(void *)param;
664983a1033SMark Powers 
665983a1033SMark Powers 		gcm_ctx->gcm_tag_len = CRYPTO_BITS2BYTES(AES_GMAC_TAG_BITS);
666983a1033SMark Powers 		gcm_ctx->gcm_processed_data_len = 0;
667983a1033SMark Powers 
668983a1033SMark Powers 		/* these values are in bits */
66995014fbbSDan OpenSolaris Anderson 		gcm_ctx->gcm_len_a_len_c[0]
67095014fbbSDan OpenSolaris Anderson 		    = htonll(CRYPTO_BYTES2BITS(gmac_param->ulAADLen));
671983a1033SMark Powers 
672983a1033SMark Powers 		rv = CRYPTO_SUCCESS;
673983a1033SMark Powers 		gcm_ctx->gcm_flags |= GMAC_MODE;
674983a1033SMark Powers 	} else {
675983a1033SMark Powers 		rv = CRYPTO_MECHANISM_PARAM_INVALID;
676983a1033SMark Powers 		goto out;
677983a1033SMark Powers 	}
678983a1033SMark Powers 
679983a1033SMark Powers 	if (gcm_init(gcm_ctx, gmac_param->pIv, AES_GMAC_IV_LEN,
680983a1033SMark Powers 	    gmac_param->pAAD, gmac_param->ulAADLen, block_size,
681983a1033SMark Powers 	    encrypt_block, copy_block, xor_block) != 0) {
682983a1033SMark Powers 		rv = CRYPTO_MECHANISM_PARAM_INVALID;
683983a1033SMark Powers 	}
684983a1033SMark Powers out:
685983a1033SMark Powers 	return (rv);
686983a1033SMark Powers }
687983a1033SMark Powers 
6884d703b5cSMark Powers void *
6894d703b5cSMark Powers gcm_alloc_ctx(int kmflag)
6904d703b5cSMark Powers {
6914d703b5cSMark Powers 	gcm_ctx_t *gcm_ctx;
6924d703b5cSMark Powers 
6934d703b5cSMark Powers #ifdef _KERNEL
6944d703b5cSMark Powers 	if ((gcm_ctx = kmem_zalloc(sizeof (gcm_ctx_t), kmflag)) == NULL)
6954d703b5cSMark Powers #else
6964d703b5cSMark Powers 	if ((gcm_ctx = calloc(1, sizeof (gcm_ctx_t))) == NULL)
6974d703b5cSMark Powers #endif
6984d703b5cSMark Powers 		return (NULL);
6994d703b5cSMark Powers 
7004d703b5cSMark Powers 	gcm_ctx->gcm_flags = GCM_MODE;
7014d703b5cSMark Powers 	return (gcm_ctx);
7024d703b5cSMark Powers }
7034d703b5cSMark Powers 
704983a1033SMark Powers void *
705983a1033SMark Powers gmac_alloc_ctx(int kmflag)
706983a1033SMark Powers {
707983a1033SMark Powers 	gcm_ctx_t *gcm_ctx;
708983a1033SMark Powers 
709983a1033SMark Powers #ifdef _KERNEL
710983a1033SMark Powers 	if ((gcm_ctx = kmem_zalloc(sizeof (gcm_ctx_t), kmflag)) == NULL)
711983a1033SMark Powers #else
712983a1033SMark Powers 	if ((gcm_ctx = calloc(1, sizeof (gcm_ctx_t))) == NULL)
713983a1033SMark Powers #endif
714983a1033SMark Powers 		return (NULL);
715983a1033SMark Powers 
716983a1033SMark Powers 	gcm_ctx->gcm_flags = GMAC_MODE;
717983a1033SMark Powers 	return (gcm_ctx);
718983a1033SMark Powers }
719983a1033SMark Powers 
7204d703b5cSMark Powers void
7214d703b5cSMark Powers gcm_set_kmflag(gcm_ctx_t *ctx, int kmflag)
7224d703b5cSMark Powers {
7234d703b5cSMark Powers 	ctx->gcm_kmflag = kmflag;
7244d703b5cSMark Powers }
725104d3bdeSDan OpenSolaris Anderson 
726104d3bdeSDan OpenSolaris Anderson 
727104d3bdeSDan OpenSolaris Anderson #ifdef __amd64
728104d3bdeSDan OpenSolaris Anderson /*
729104d3bdeSDan OpenSolaris Anderson  * Return 1 if executing on Intel with PCLMULQDQ instructions,
730104d3bdeSDan OpenSolaris Anderson  * otherwise 0 (i.e., Intel without PCLMULQDQ or AMD64).
731104d3bdeSDan OpenSolaris Anderson  * Cache the result, as the CPU can't change.
732104d3bdeSDan OpenSolaris Anderson  *
733104d3bdeSDan OpenSolaris Anderson  * Note: the userland version uses getisax().  The kernel version uses
734104d3bdeSDan OpenSolaris Anderson  * global variable x86_feature or the output of cpuid_insn().
735104d3bdeSDan OpenSolaris Anderson  */
736104d3bdeSDan OpenSolaris Anderson static int
737104d3bdeSDan OpenSolaris Anderson intel_pclmulqdq_instruction_present(void)
738104d3bdeSDan OpenSolaris Anderson {
739104d3bdeSDan OpenSolaris Anderson 	static int	cached_result = -1;
740104d3bdeSDan OpenSolaris Anderson 
741104d3bdeSDan OpenSolaris Anderson 	if (cached_result == -1) { /* first time */
742104d3bdeSDan OpenSolaris Anderson #ifdef _KERNEL
743104d3bdeSDan OpenSolaris Anderson #ifdef X86_PCLMULQDQ
744104d3bdeSDan OpenSolaris Anderson 		cached_result = (x86_feature & X86_PCLMULQDQ) != 0;
745104d3bdeSDan OpenSolaris Anderson #else
746104d3bdeSDan OpenSolaris Anderson 		if (cpuid_getvendor(CPU) == X86_VENDOR_Intel) {
747104d3bdeSDan OpenSolaris Anderson 			struct cpuid_regs	cpr;
748104d3bdeSDan OpenSolaris Anderson 			cpu_t			*cp = CPU;
749104d3bdeSDan OpenSolaris Anderson 
750104d3bdeSDan OpenSolaris Anderson 			cpr.cp_eax = 1; /* Function 1: get processor info */
751104d3bdeSDan OpenSolaris Anderson 			(void) cpuid_insn(cp, &cpr);
752104d3bdeSDan OpenSolaris Anderson 			cached_result = ((cpr.cp_ecx &
753104d3bdeSDan OpenSolaris Anderson 			    CPUID_INTC_ECX_PCLMULQDQ) != 0);
754104d3bdeSDan OpenSolaris Anderson 		} else {
755104d3bdeSDan OpenSolaris Anderson 			cached_result = 0;
756104d3bdeSDan OpenSolaris Anderson 		}
757104d3bdeSDan OpenSolaris Anderson #endif	/* X86_PCLMULQDQ */
758104d3bdeSDan OpenSolaris Anderson #else
759104d3bdeSDan OpenSolaris Anderson 		uint_t		ui = 0;
760104d3bdeSDan OpenSolaris Anderson 
761104d3bdeSDan OpenSolaris Anderson 		(void) getisax(&ui, 1);
762104d3bdeSDan OpenSolaris Anderson 		cached_result = (ui & AV_386_PCLMULQDQ) != 0;
763104d3bdeSDan OpenSolaris Anderson #endif	/* _KERNEL */
764104d3bdeSDan OpenSolaris Anderson 	}
765104d3bdeSDan OpenSolaris Anderson 
766104d3bdeSDan OpenSolaris Anderson 	return (cached_result);
767104d3bdeSDan OpenSolaris Anderson }
768104d3bdeSDan OpenSolaris Anderson #endif	/* __amd64 */
769