xref: /titanic_50/usr/src/common/crypto/modes/gcm.c (revision 983a10335731bc55a0b7a37f195575fa109e30d4)
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