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