xref: /onnv-gate/usr/src/common/crypto/modes/gcm.c (revision 8005:73d30d28ca93)
1*8005SMark.Powers@Sun.COM /*
2*8005SMark.Powers@Sun.COM  * CDDL HEADER START
3*8005SMark.Powers@Sun.COM  *
4*8005SMark.Powers@Sun.COM  * The contents of this file are subject to the terms of the
5*8005SMark.Powers@Sun.COM  * Common Development and Distribution License (the "License").
6*8005SMark.Powers@Sun.COM  * You may not use this file except in compliance with the License.
7*8005SMark.Powers@Sun.COM  *
8*8005SMark.Powers@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8005SMark.Powers@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*8005SMark.Powers@Sun.COM  * See the License for the specific language governing permissions
11*8005SMark.Powers@Sun.COM  * and limitations under the License.
12*8005SMark.Powers@Sun.COM  *
13*8005SMark.Powers@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*8005SMark.Powers@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8005SMark.Powers@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*8005SMark.Powers@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*8005SMark.Powers@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*8005SMark.Powers@Sun.COM  *
19*8005SMark.Powers@Sun.COM  * CDDL HEADER END
20*8005SMark.Powers@Sun.COM  */
21*8005SMark.Powers@Sun.COM /*
22*8005SMark.Powers@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*8005SMark.Powers@Sun.COM  * Use is subject to license terms.
24*8005SMark.Powers@Sun.COM  */
25*8005SMark.Powers@Sun.COM 
26*8005SMark.Powers@Sun.COM #ifndef _KERNEL
27*8005SMark.Powers@Sun.COM #include <strings.h>
28*8005SMark.Powers@Sun.COM #include <limits.h>
29*8005SMark.Powers@Sun.COM #include <assert.h>
30*8005SMark.Powers@Sun.COM #include <security/cryptoki.h>
31*8005SMark.Powers@Sun.COM #endif
32*8005SMark.Powers@Sun.COM 
33*8005SMark.Powers@Sun.COM #include <sys/types.h>
34*8005SMark.Powers@Sun.COM #include <sys/kmem.h>
35*8005SMark.Powers@Sun.COM #include <modes/modes.h>
36*8005SMark.Powers@Sun.COM #include <sys/crypto/common.h>
37*8005SMark.Powers@Sun.COM #include <sys/crypto/impl.h>
38*8005SMark.Powers@Sun.COM #include <sys/byteorder.h>
39*8005SMark.Powers@Sun.COM 
40*8005SMark.Powers@Sun.COM struct aes_block {
41*8005SMark.Powers@Sun.COM 	uint64_t a;
42*8005SMark.Powers@Sun.COM 	uint64_t b;
43*8005SMark.Powers@Sun.COM };
44*8005SMark.Powers@Sun.COM 
45*8005SMark.Powers@Sun.COM static void
46*8005SMark.Powers@Sun.COM gcm_mul(uint64_t *x_in, uint64_t *y, uint64_t *res)
47*8005SMark.Powers@Sun.COM {
48*8005SMark.Powers@Sun.COM 	uint64_t R = { 0xe100000000000000ULL };
49*8005SMark.Powers@Sun.COM 	struct aes_block z = { 0, 0 };
50*8005SMark.Powers@Sun.COM 	struct aes_block v;
51*8005SMark.Powers@Sun.COM 	uint64_t x;
52*8005SMark.Powers@Sun.COM 	int i, j;
53*8005SMark.Powers@Sun.COM 
54*8005SMark.Powers@Sun.COM 	v.a = ntohll(y[0]);
55*8005SMark.Powers@Sun.COM 	v.b = ntohll(y[1]);
56*8005SMark.Powers@Sun.COM 
57*8005SMark.Powers@Sun.COM 	for (j = 0; j < 2; j++) {
58*8005SMark.Powers@Sun.COM 		x = ntohll(x_in[j]);
59*8005SMark.Powers@Sun.COM 		for (i = 0; i < 64; i++, x <<= 1) {
60*8005SMark.Powers@Sun.COM 			if (x & 0x8000000000000000ULL) {
61*8005SMark.Powers@Sun.COM 				z.a ^= v.a;
62*8005SMark.Powers@Sun.COM 				z.b ^= v.b;
63*8005SMark.Powers@Sun.COM 			}
64*8005SMark.Powers@Sun.COM 			if (v.b & 1ULL) {
65*8005SMark.Powers@Sun.COM 				v.b = (v.a << 63)|(v.b >> 1);
66*8005SMark.Powers@Sun.COM 				v.a = (v.a >> 1) ^ R;
67*8005SMark.Powers@Sun.COM 			} else {
68*8005SMark.Powers@Sun.COM 				v.b = (v.a << 63)|(v.b >> 1);
69*8005SMark.Powers@Sun.COM 				v.a = v.a >> 1;
70*8005SMark.Powers@Sun.COM 			}
71*8005SMark.Powers@Sun.COM 		}
72*8005SMark.Powers@Sun.COM 	}
73*8005SMark.Powers@Sun.COM 	res[0] = htonll(z.a);
74*8005SMark.Powers@Sun.COM 	res[1] = htonll(z.b);
75*8005SMark.Powers@Sun.COM }
76*8005SMark.Powers@Sun.COM 
77*8005SMark.Powers@Sun.COM #define	GHASH(c, d, t) \
78*8005SMark.Powers@Sun.COM 	xor_block((uint8_t *)(d), (uint8_t *)(c)->gcm_ghash); \
79*8005SMark.Powers@Sun.COM 	gcm_mul((uint64_t *)(c)->gcm_ghash, (c)->gcm_H, (uint64_t *)(t));
80*8005SMark.Powers@Sun.COM 
81*8005SMark.Powers@Sun.COM /*
82*8005SMark.Powers@Sun.COM  * Encrypt multiple blocks of data in GCM mode.  Decrypt for GCM mode
83*8005SMark.Powers@Sun.COM  * is done in another function.
84*8005SMark.Powers@Sun.COM  */
85*8005SMark.Powers@Sun.COM int
86*8005SMark.Powers@Sun.COM gcm_mode_encrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length,
87*8005SMark.Powers@Sun.COM     crypto_data_t *out, size_t block_size,
88*8005SMark.Powers@Sun.COM     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
89*8005SMark.Powers@Sun.COM     void (*copy_block)(uint8_t *, uint8_t *),
90*8005SMark.Powers@Sun.COM     void (*xor_block)(uint8_t *, uint8_t *))
91*8005SMark.Powers@Sun.COM {
92*8005SMark.Powers@Sun.COM 	size_t remainder = length;
93*8005SMark.Powers@Sun.COM 	size_t need;
94*8005SMark.Powers@Sun.COM 	uint8_t *datap = (uint8_t *)data;
95*8005SMark.Powers@Sun.COM 	uint8_t *blockp;
96*8005SMark.Powers@Sun.COM 	uint8_t *lastp;
97*8005SMark.Powers@Sun.COM 	void *iov_or_mp;
98*8005SMark.Powers@Sun.COM 	offset_t offset;
99*8005SMark.Powers@Sun.COM 	uint8_t *out_data_1;
100*8005SMark.Powers@Sun.COM 	uint8_t *out_data_2;
101*8005SMark.Powers@Sun.COM 	size_t out_data_1_len;
102*8005SMark.Powers@Sun.COM 	uint64_t counter;
103*8005SMark.Powers@Sun.COM 	uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
104*8005SMark.Powers@Sun.COM 
105*8005SMark.Powers@Sun.COM 	if (length + ctx->gcm_remainder_len < block_size) {
106*8005SMark.Powers@Sun.COM 		/* accumulate bytes here and return */
107*8005SMark.Powers@Sun.COM 		bcopy(datap,
108*8005SMark.Powers@Sun.COM 		    (uint8_t *)ctx->gcm_remainder + ctx->gcm_remainder_len,
109*8005SMark.Powers@Sun.COM 		    length);
110*8005SMark.Powers@Sun.COM 		ctx->gcm_remainder_len += length;
111*8005SMark.Powers@Sun.COM 		ctx->gcm_copy_to = datap;
112*8005SMark.Powers@Sun.COM 		return (CRYPTO_SUCCESS);
113*8005SMark.Powers@Sun.COM 	}
114*8005SMark.Powers@Sun.COM 
115*8005SMark.Powers@Sun.COM 	lastp = (uint8_t *)ctx->gcm_cb;
116*8005SMark.Powers@Sun.COM 	if (out != NULL)
117*8005SMark.Powers@Sun.COM 		crypto_init_ptrs(out, &iov_or_mp, &offset);
118*8005SMark.Powers@Sun.COM 
119*8005SMark.Powers@Sun.COM 	do {
120*8005SMark.Powers@Sun.COM 		/* Unprocessed data from last call. */
121*8005SMark.Powers@Sun.COM 		if (ctx->gcm_remainder_len > 0) {
122*8005SMark.Powers@Sun.COM 			need = block_size - ctx->gcm_remainder_len;
123*8005SMark.Powers@Sun.COM 
124*8005SMark.Powers@Sun.COM 			if (need > remainder)
125*8005SMark.Powers@Sun.COM 				return (CRYPTO_DATA_LEN_RANGE);
126*8005SMark.Powers@Sun.COM 
127*8005SMark.Powers@Sun.COM 			bcopy(datap, &((uint8_t *)ctx->gcm_remainder)
128*8005SMark.Powers@Sun.COM 			    [ctx->gcm_remainder_len], need);
129*8005SMark.Powers@Sun.COM 
130*8005SMark.Powers@Sun.COM 			blockp = (uint8_t *)ctx->gcm_remainder;
131*8005SMark.Powers@Sun.COM 		} else {
132*8005SMark.Powers@Sun.COM 			blockp = datap;
133*8005SMark.Powers@Sun.COM 		}
134*8005SMark.Powers@Sun.COM 
135*8005SMark.Powers@Sun.COM 		/*
136*8005SMark.Powers@Sun.COM 		 * Increment counter. Counter bits are confined
137*8005SMark.Powers@Sun.COM 		 * to the bottom 32 bits of the counter block.
138*8005SMark.Powers@Sun.COM 		 */
139*8005SMark.Powers@Sun.COM 		counter = ntohll(ctx->gcm_cb[1] & counter_mask);
140*8005SMark.Powers@Sun.COM 		counter = htonll(counter + 1);
141*8005SMark.Powers@Sun.COM 		counter &= counter_mask;
142*8005SMark.Powers@Sun.COM 		ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
143*8005SMark.Powers@Sun.COM 
144*8005SMark.Powers@Sun.COM 		encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb,
145*8005SMark.Powers@Sun.COM 		    (uint8_t *)ctx->gcm_tmp);
146*8005SMark.Powers@Sun.COM 		xor_block(blockp, (uint8_t *)ctx->gcm_tmp);
147*8005SMark.Powers@Sun.COM 
148*8005SMark.Powers@Sun.COM 		lastp = (uint8_t *)ctx->gcm_tmp;
149*8005SMark.Powers@Sun.COM 
150*8005SMark.Powers@Sun.COM 		ctx->gcm_processed_data_len += block_size;
151*8005SMark.Powers@Sun.COM 
152*8005SMark.Powers@Sun.COM 		if (out == NULL) {
153*8005SMark.Powers@Sun.COM 			if (ctx->gcm_remainder_len > 0) {
154*8005SMark.Powers@Sun.COM 				bcopy(blockp, ctx->gcm_copy_to,
155*8005SMark.Powers@Sun.COM 				    ctx->gcm_remainder_len);
156*8005SMark.Powers@Sun.COM 				bcopy(blockp + ctx->gcm_remainder_len, datap,
157*8005SMark.Powers@Sun.COM 				    need);
158*8005SMark.Powers@Sun.COM 			}
159*8005SMark.Powers@Sun.COM 		} else {
160*8005SMark.Powers@Sun.COM 			crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
161*8005SMark.Powers@Sun.COM 			    &out_data_1_len, &out_data_2, block_size);
162*8005SMark.Powers@Sun.COM 
163*8005SMark.Powers@Sun.COM 			/* copy block to where it belongs */
164*8005SMark.Powers@Sun.COM 			if (out_data_1_len == block_size) {
165*8005SMark.Powers@Sun.COM 				copy_block(lastp, out_data_1);
166*8005SMark.Powers@Sun.COM 			} else {
167*8005SMark.Powers@Sun.COM 				bcopy(lastp, out_data_1, out_data_1_len);
168*8005SMark.Powers@Sun.COM 				if (out_data_2 != NULL) {
169*8005SMark.Powers@Sun.COM 					bcopy(lastp + out_data_1_len,
170*8005SMark.Powers@Sun.COM 					    out_data_2,
171*8005SMark.Powers@Sun.COM 					    block_size - out_data_1_len);
172*8005SMark.Powers@Sun.COM 				}
173*8005SMark.Powers@Sun.COM 			}
174*8005SMark.Powers@Sun.COM 			/* update offset */
175*8005SMark.Powers@Sun.COM 			out->cd_offset += block_size;
176*8005SMark.Powers@Sun.COM 		}
177*8005SMark.Powers@Sun.COM 
178*8005SMark.Powers@Sun.COM 		/* add ciphertext to the hash */
179*8005SMark.Powers@Sun.COM 		GHASH(ctx, ctx->gcm_tmp, ctx->gcm_ghash);
180*8005SMark.Powers@Sun.COM 
181*8005SMark.Powers@Sun.COM 		/* Update pointer to next block of data to be processed. */
182*8005SMark.Powers@Sun.COM 		if (ctx->gcm_remainder_len != 0) {
183*8005SMark.Powers@Sun.COM 			datap += need;
184*8005SMark.Powers@Sun.COM 			ctx->gcm_remainder_len = 0;
185*8005SMark.Powers@Sun.COM 		} else {
186*8005SMark.Powers@Sun.COM 			datap += block_size;
187*8005SMark.Powers@Sun.COM 		}
188*8005SMark.Powers@Sun.COM 
189*8005SMark.Powers@Sun.COM 		remainder = (size_t)&data[length] - (size_t)datap;
190*8005SMark.Powers@Sun.COM 
191*8005SMark.Powers@Sun.COM 		/* Incomplete last block. */
192*8005SMark.Powers@Sun.COM 		if (remainder > 0 && remainder < block_size) {
193*8005SMark.Powers@Sun.COM 			bcopy(datap, ctx->gcm_remainder, remainder);
194*8005SMark.Powers@Sun.COM 			ctx->gcm_remainder_len = remainder;
195*8005SMark.Powers@Sun.COM 			ctx->gcm_copy_to = datap;
196*8005SMark.Powers@Sun.COM 			goto out;
197*8005SMark.Powers@Sun.COM 		}
198*8005SMark.Powers@Sun.COM 		ctx->gcm_copy_to = NULL;
199*8005SMark.Powers@Sun.COM 
200*8005SMark.Powers@Sun.COM 	} while (remainder > 0);
201*8005SMark.Powers@Sun.COM out:
202*8005SMark.Powers@Sun.COM 	return (CRYPTO_SUCCESS);
203*8005SMark.Powers@Sun.COM }
204*8005SMark.Powers@Sun.COM 
205*8005SMark.Powers@Sun.COM /* ARGSUSED */
206*8005SMark.Powers@Sun.COM int
207*8005SMark.Powers@Sun.COM gcm_encrypt_final(gcm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
208*8005SMark.Powers@Sun.COM     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
209*8005SMark.Powers@Sun.COM     void (*copy_block)(uint8_t *, uint8_t *),
210*8005SMark.Powers@Sun.COM     void (*xor_block)(uint8_t *, uint8_t *))
211*8005SMark.Powers@Sun.COM {
212*8005SMark.Powers@Sun.COM 	uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
213*8005SMark.Powers@Sun.COM 	uint8_t *ghash, *macp;
214*8005SMark.Powers@Sun.COM 	int i, rv;
215*8005SMark.Powers@Sun.COM 
216*8005SMark.Powers@Sun.COM 	if (out->cd_length <
217*8005SMark.Powers@Sun.COM 	    (ctx->gcm_remainder_len + ctx->gcm_tag_len)) {
218*8005SMark.Powers@Sun.COM 		return (CRYPTO_DATA_LEN_RANGE);
219*8005SMark.Powers@Sun.COM 	}
220*8005SMark.Powers@Sun.COM 
221*8005SMark.Powers@Sun.COM 	ghash = (uint8_t *)ctx->gcm_ghash;
222*8005SMark.Powers@Sun.COM 
223*8005SMark.Powers@Sun.COM 	if (ctx->gcm_remainder_len > 0) {
224*8005SMark.Powers@Sun.COM 		uint64_t counter;
225*8005SMark.Powers@Sun.COM 		uint8_t *tmpp = (uint8_t *)ctx->gcm_tmp;
226*8005SMark.Powers@Sun.COM 
227*8005SMark.Powers@Sun.COM 		/*
228*8005SMark.Powers@Sun.COM 		 * Here is where we deal with data that is not a
229*8005SMark.Powers@Sun.COM 		 * multiple of the block size.
230*8005SMark.Powers@Sun.COM 		 */
231*8005SMark.Powers@Sun.COM 
232*8005SMark.Powers@Sun.COM 		/*
233*8005SMark.Powers@Sun.COM 		 * Increment counter.
234*8005SMark.Powers@Sun.COM 		 */
235*8005SMark.Powers@Sun.COM 		counter = ntohll(ctx->gcm_cb[1] & counter_mask);
236*8005SMark.Powers@Sun.COM 		counter = htonll(counter + 1);
237*8005SMark.Powers@Sun.COM 		counter &= counter_mask;
238*8005SMark.Powers@Sun.COM 		ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
239*8005SMark.Powers@Sun.COM 
240*8005SMark.Powers@Sun.COM 		encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb,
241*8005SMark.Powers@Sun.COM 		    (uint8_t *)ctx->gcm_tmp);
242*8005SMark.Powers@Sun.COM 
243*8005SMark.Powers@Sun.COM 		macp = (uint8_t *)ctx->gcm_remainder;
244*8005SMark.Powers@Sun.COM 		bzero(macp + ctx->gcm_remainder_len,
245*8005SMark.Powers@Sun.COM 		    block_size - ctx->gcm_remainder_len);
246*8005SMark.Powers@Sun.COM 
247*8005SMark.Powers@Sun.COM 		/* XOR with counter block */
248*8005SMark.Powers@Sun.COM 		for (i = 0; i < ctx->gcm_remainder_len; i++) {
249*8005SMark.Powers@Sun.COM 			macp[i] ^= tmpp[i];
250*8005SMark.Powers@Sun.COM 		}
251*8005SMark.Powers@Sun.COM 
252*8005SMark.Powers@Sun.COM 		/* add ciphertext to the hash */
253*8005SMark.Powers@Sun.COM 		GHASH(ctx, macp, ghash);
254*8005SMark.Powers@Sun.COM 
255*8005SMark.Powers@Sun.COM 		ctx->gcm_processed_data_len += ctx->gcm_remainder_len;
256*8005SMark.Powers@Sun.COM 	}
257*8005SMark.Powers@Sun.COM 
258*8005SMark.Powers@Sun.COM 	ctx->gcm_len_a_len_c[1] = htonll(ctx->gcm_processed_data_len << 3);
259*8005SMark.Powers@Sun.COM 	GHASH(ctx, ctx->gcm_len_a_len_c, ghash);
260*8005SMark.Powers@Sun.COM 	encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_J0,
261*8005SMark.Powers@Sun.COM 	    (uint8_t *)ctx->gcm_J0);
262*8005SMark.Powers@Sun.COM 	xor_block((uint8_t *)ctx->gcm_J0, ghash);
263*8005SMark.Powers@Sun.COM 
264*8005SMark.Powers@Sun.COM 	if (ctx->gcm_remainder_len > 0) {
265*8005SMark.Powers@Sun.COM 		rv = crypto_put_output_data(macp, out, ctx->gcm_remainder_len);
266*8005SMark.Powers@Sun.COM 		if (rv != CRYPTO_SUCCESS)
267*8005SMark.Powers@Sun.COM 			return (rv);
268*8005SMark.Powers@Sun.COM 	}
269*8005SMark.Powers@Sun.COM 	out->cd_offset += ctx->gcm_remainder_len;
270*8005SMark.Powers@Sun.COM 	ctx->gcm_remainder_len = 0;
271*8005SMark.Powers@Sun.COM 	rv = crypto_put_output_data(ghash, out, ctx->gcm_tag_len);
272*8005SMark.Powers@Sun.COM 	if (rv != CRYPTO_SUCCESS)
273*8005SMark.Powers@Sun.COM 		return (rv);
274*8005SMark.Powers@Sun.COM 	out->cd_offset += ctx->gcm_tag_len;
275*8005SMark.Powers@Sun.COM 
276*8005SMark.Powers@Sun.COM 	return (CRYPTO_SUCCESS);
277*8005SMark.Powers@Sun.COM }
278*8005SMark.Powers@Sun.COM 
279*8005SMark.Powers@Sun.COM /*
280*8005SMark.Powers@Sun.COM  * This will only deal with decrypting the last block of the input that
281*8005SMark.Powers@Sun.COM  * might not be a multiple of block length.
282*8005SMark.Powers@Sun.COM  */
283*8005SMark.Powers@Sun.COM static void
284*8005SMark.Powers@Sun.COM gcm_decrypt_incomplete_block(gcm_ctx_t *ctx, size_t block_size, size_t index,
285*8005SMark.Powers@Sun.COM     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
286*8005SMark.Powers@Sun.COM     void (*xor_block)(uint8_t *, uint8_t *))
287*8005SMark.Powers@Sun.COM {
288*8005SMark.Powers@Sun.COM 	uint8_t *datap, *outp, *counterp;
289*8005SMark.Powers@Sun.COM 	uint64_t counter;
290*8005SMark.Powers@Sun.COM 	uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
291*8005SMark.Powers@Sun.COM 	int i;
292*8005SMark.Powers@Sun.COM 
293*8005SMark.Powers@Sun.COM 	/*
294*8005SMark.Powers@Sun.COM 	 * Increment counter.
295*8005SMark.Powers@Sun.COM 	 * Counter bits are confined to the bottom 32 bits
296*8005SMark.Powers@Sun.COM 	 */
297*8005SMark.Powers@Sun.COM 	counter = ntohll(ctx->gcm_cb[1] & counter_mask);
298*8005SMark.Powers@Sun.COM 	counter = htonll(counter + 1);
299*8005SMark.Powers@Sun.COM 	counter &= counter_mask;
300*8005SMark.Powers@Sun.COM 	ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
301*8005SMark.Powers@Sun.COM 
302*8005SMark.Powers@Sun.COM 	datap = (uint8_t *)ctx->gcm_remainder;
303*8005SMark.Powers@Sun.COM 	outp = &((ctx->gcm_pt_buf)[index]);
304*8005SMark.Powers@Sun.COM 	counterp = (uint8_t *)ctx->gcm_tmp;
305*8005SMark.Powers@Sun.COM 
306*8005SMark.Powers@Sun.COM 	/* authentication tag */
307*8005SMark.Powers@Sun.COM 	bzero((uint8_t *)ctx->gcm_tmp, block_size);
308*8005SMark.Powers@Sun.COM 	bcopy(datap, (uint8_t *)ctx->gcm_tmp, ctx->gcm_remainder_len);
309*8005SMark.Powers@Sun.COM 
310*8005SMark.Powers@Sun.COM 	/* add ciphertext to the hash */
311*8005SMark.Powers@Sun.COM 	GHASH(ctx, ctx->gcm_tmp, ctx->gcm_ghash);
312*8005SMark.Powers@Sun.COM 
313*8005SMark.Powers@Sun.COM 	/* decrypt remaining ciphertext */
314*8005SMark.Powers@Sun.COM 	encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, counterp);
315*8005SMark.Powers@Sun.COM 
316*8005SMark.Powers@Sun.COM 	/* XOR with counter block */
317*8005SMark.Powers@Sun.COM 	for (i = 0; i < ctx->gcm_remainder_len; i++) {
318*8005SMark.Powers@Sun.COM 		outp[i] = datap[i] ^ counterp[i];
319*8005SMark.Powers@Sun.COM 	}
320*8005SMark.Powers@Sun.COM }
321*8005SMark.Powers@Sun.COM 
322*8005SMark.Powers@Sun.COM /* ARGSUSED */
323*8005SMark.Powers@Sun.COM int
324*8005SMark.Powers@Sun.COM gcm_mode_decrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length,
325*8005SMark.Powers@Sun.COM     crypto_data_t *out, size_t block_size,
326*8005SMark.Powers@Sun.COM     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
327*8005SMark.Powers@Sun.COM     void (*copy_block)(uint8_t *, uint8_t *),
328*8005SMark.Powers@Sun.COM     void (*xor_block)(uint8_t *, uint8_t *))
329*8005SMark.Powers@Sun.COM {
330*8005SMark.Powers@Sun.COM 	size_t new_len;
331*8005SMark.Powers@Sun.COM 	uint8_t *new;
332*8005SMark.Powers@Sun.COM 
333*8005SMark.Powers@Sun.COM 	/*
334*8005SMark.Powers@Sun.COM 	 * Copy contiguous ciphertext input blocks to plaintext buffer.
335*8005SMark.Powers@Sun.COM 	 * Ciphertext will be decrypted in the final.
336*8005SMark.Powers@Sun.COM 	 */
337*8005SMark.Powers@Sun.COM 	if (length > 0) {
338*8005SMark.Powers@Sun.COM 		new_len = ctx->gcm_pt_buf_len + length;
339*8005SMark.Powers@Sun.COM #ifdef _KERNEL
340*8005SMark.Powers@Sun.COM 		new = kmem_alloc(new_len, ctx->gcm_kmflag);
341*8005SMark.Powers@Sun.COM 		bcopy(ctx->gcm_pt_buf, new, ctx->gcm_pt_buf_len);
342*8005SMark.Powers@Sun.COM 		kmem_free(ctx->gcm_pt_buf, ctx->gcm_pt_buf_len);
343*8005SMark.Powers@Sun.COM #else
344*8005SMark.Powers@Sun.COM 		new = malloc(new_len);
345*8005SMark.Powers@Sun.COM 		bcopy(ctx->gcm_pt_buf, new, ctx->gcm_pt_buf_len);
346*8005SMark.Powers@Sun.COM 		free(ctx->gcm_pt_buf);
347*8005SMark.Powers@Sun.COM #endif
348*8005SMark.Powers@Sun.COM 		if (new == NULL)
349*8005SMark.Powers@Sun.COM 			return (CRYPTO_HOST_MEMORY);
350*8005SMark.Powers@Sun.COM 
351*8005SMark.Powers@Sun.COM 		ctx->gcm_pt_buf = new;
352*8005SMark.Powers@Sun.COM 		ctx->gcm_pt_buf_len = new_len;
353*8005SMark.Powers@Sun.COM 		bcopy(data, &ctx->gcm_pt_buf[ctx->gcm_processed_data_len],
354*8005SMark.Powers@Sun.COM 		    length);
355*8005SMark.Powers@Sun.COM 		ctx->gcm_processed_data_len += length;
356*8005SMark.Powers@Sun.COM 	}
357*8005SMark.Powers@Sun.COM 
358*8005SMark.Powers@Sun.COM 	ctx->gcm_remainder_len = 0;
359*8005SMark.Powers@Sun.COM 	return (CRYPTO_SUCCESS);
360*8005SMark.Powers@Sun.COM }
361*8005SMark.Powers@Sun.COM 
362*8005SMark.Powers@Sun.COM int
363*8005SMark.Powers@Sun.COM gcm_decrypt_final(gcm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
364*8005SMark.Powers@Sun.COM     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
365*8005SMark.Powers@Sun.COM     void (*xor_block)(uint8_t *, uint8_t *))
366*8005SMark.Powers@Sun.COM {
367*8005SMark.Powers@Sun.COM 	size_t pt_len;
368*8005SMark.Powers@Sun.COM 	size_t remainder;
369*8005SMark.Powers@Sun.COM 	uint8_t *ghash;
370*8005SMark.Powers@Sun.COM 	uint8_t *blockp;
371*8005SMark.Powers@Sun.COM 	uint8_t *cbp;
372*8005SMark.Powers@Sun.COM 	uint64_t counter;
373*8005SMark.Powers@Sun.COM 	uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
374*8005SMark.Powers@Sun.COM 	int processed = 0, rv;
375*8005SMark.Powers@Sun.COM 
376*8005SMark.Powers@Sun.COM 	ASSERT(ctx->gcm_processed_data_len == ctx->gcm_pt_buf_len);
377*8005SMark.Powers@Sun.COM 
378*8005SMark.Powers@Sun.COM 	pt_len = ctx->gcm_processed_data_len - ctx->gcm_tag_len;
379*8005SMark.Powers@Sun.COM 	ghash = (uint8_t *)ctx->gcm_ghash;
380*8005SMark.Powers@Sun.COM 	blockp = ctx->gcm_pt_buf;
381*8005SMark.Powers@Sun.COM 	remainder = pt_len;
382*8005SMark.Powers@Sun.COM 	while (remainder > 0) {
383*8005SMark.Powers@Sun.COM 		/* add ciphertext to the hash */
384*8005SMark.Powers@Sun.COM 		GHASH(ctx, blockp, ghash);
385*8005SMark.Powers@Sun.COM 
386*8005SMark.Powers@Sun.COM 		/*
387*8005SMark.Powers@Sun.COM 		 * Increment counter.
388*8005SMark.Powers@Sun.COM 		 * Counter bits are confined to the bottom 32 bits
389*8005SMark.Powers@Sun.COM 		 */
390*8005SMark.Powers@Sun.COM 		counter = ntohll(ctx->gcm_cb[1] & counter_mask);
391*8005SMark.Powers@Sun.COM 		counter = htonll(counter + 1);
392*8005SMark.Powers@Sun.COM 		counter &= counter_mask;
393*8005SMark.Powers@Sun.COM 		ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
394*8005SMark.Powers@Sun.COM 
395*8005SMark.Powers@Sun.COM 		cbp = (uint8_t *)ctx->gcm_tmp;
396*8005SMark.Powers@Sun.COM 		encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, cbp);
397*8005SMark.Powers@Sun.COM 
398*8005SMark.Powers@Sun.COM 		/* XOR with ciphertext */
399*8005SMark.Powers@Sun.COM 		xor_block(cbp, blockp);
400*8005SMark.Powers@Sun.COM 
401*8005SMark.Powers@Sun.COM 		processed += block_size;
402*8005SMark.Powers@Sun.COM 		blockp += block_size;
403*8005SMark.Powers@Sun.COM 		remainder -= block_size;
404*8005SMark.Powers@Sun.COM 
405*8005SMark.Powers@Sun.COM 		/* Incomplete last block */
406*8005SMark.Powers@Sun.COM 		if (remainder > 0 && remainder < block_size) {
407*8005SMark.Powers@Sun.COM 			bcopy(blockp, ctx->gcm_remainder, remainder);
408*8005SMark.Powers@Sun.COM 			ctx->gcm_remainder_len = remainder;
409*8005SMark.Powers@Sun.COM 			/*
410*8005SMark.Powers@Sun.COM 			 * not expecting anymore ciphertext, just
411*8005SMark.Powers@Sun.COM 			 * compute plaintext for the remaining input
412*8005SMark.Powers@Sun.COM 			 */
413*8005SMark.Powers@Sun.COM 			gcm_decrypt_incomplete_block(ctx, block_size,
414*8005SMark.Powers@Sun.COM 			    processed, encrypt_block, xor_block);
415*8005SMark.Powers@Sun.COM 			ctx->gcm_remainder_len = 0;
416*8005SMark.Powers@Sun.COM 			goto out;
417*8005SMark.Powers@Sun.COM 		}
418*8005SMark.Powers@Sun.COM 	}
419*8005SMark.Powers@Sun.COM out:
420*8005SMark.Powers@Sun.COM 	ctx->gcm_len_a_len_c[1] = htonll(pt_len << 3);
421*8005SMark.Powers@Sun.COM 	GHASH(ctx, ctx->gcm_len_a_len_c, ghash);
422*8005SMark.Powers@Sun.COM 	encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_J0,
423*8005SMark.Powers@Sun.COM 	    (uint8_t *)ctx->gcm_J0);
424*8005SMark.Powers@Sun.COM 	xor_block((uint8_t *)ctx->gcm_J0, ghash);
425*8005SMark.Powers@Sun.COM 
426*8005SMark.Powers@Sun.COM 	/* compare the input authentication tag with what we calculated */
427*8005SMark.Powers@Sun.COM 	if (bcmp(&ctx->gcm_pt_buf[pt_len], ghash, ctx->gcm_tag_len)) {
428*8005SMark.Powers@Sun.COM 		/* They don't match */
429*8005SMark.Powers@Sun.COM 		return (CRYPTO_INVALID_MAC);
430*8005SMark.Powers@Sun.COM 	} else {
431*8005SMark.Powers@Sun.COM 		rv = crypto_put_output_data(ctx->gcm_pt_buf, out, pt_len);
432*8005SMark.Powers@Sun.COM 		if (rv != CRYPTO_SUCCESS)
433*8005SMark.Powers@Sun.COM 			return (rv);
434*8005SMark.Powers@Sun.COM 		out->cd_offset += pt_len;
435*8005SMark.Powers@Sun.COM 	}
436*8005SMark.Powers@Sun.COM 	return (CRYPTO_SUCCESS);
437*8005SMark.Powers@Sun.COM }
438*8005SMark.Powers@Sun.COM 
439*8005SMark.Powers@Sun.COM static int
440*8005SMark.Powers@Sun.COM gcm_validate_args(CK_AES_GCM_PARAMS *gcm_param)
441*8005SMark.Powers@Sun.COM {
442*8005SMark.Powers@Sun.COM 	size_t tag_len;
443*8005SMark.Powers@Sun.COM 
444*8005SMark.Powers@Sun.COM 	/*
445*8005SMark.Powers@Sun.COM 	 * Check the length of the authentication tag (in bits).
446*8005SMark.Powers@Sun.COM 	 */
447*8005SMark.Powers@Sun.COM 	tag_len = gcm_param->ulTagBits;
448*8005SMark.Powers@Sun.COM 	switch (tag_len) {
449*8005SMark.Powers@Sun.COM 	case 32:
450*8005SMark.Powers@Sun.COM 	case 64:
451*8005SMark.Powers@Sun.COM 	case 96:
452*8005SMark.Powers@Sun.COM 	case 104:
453*8005SMark.Powers@Sun.COM 	case 112:
454*8005SMark.Powers@Sun.COM 	case 120:
455*8005SMark.Powers@Sun.COM 	case 128:
456*8005SMark.Powers@Sun.COM 		break;
457*8005SMark.Powers@Sun.COM 	default:
458*8005SMark.Powers@Sun.COM 		return (CRYPTO_MECHANISM_PARAM_INVALID);
459*8005SMark.Powers@Sun.COM 	}
460*8005SMark.Powers@Sun.COM 
461*8005SMark.Powers@Sun.COM 	if (gcm_param->ulIvLen == 0)
462*8005SMark.Powers@Sun.COM 		return (CRYPTO_MECHANISM_PARAM_INVALID);
463*8005SMark.Powers@Sun.COM 
464*8005SMark.Powers@Sun.COM 	return (CRYPTO_SUCCESS);
465*8005SMark.Powers@Sun.COM }
466*8005SMark.Powers@Sun.COM 
467*8005SMark.Powers@Sun.COM static void
468*8005SMark.Powers@Sun.COM gcm_format_initial_blocks(uchar_t *iv, ulong_t iv_len,
469*8005SMark.Powers@Sun.COM     gcm_ctx_t *ctx, size_t block_size,
470*8005SMark.Powers@Sun.COM     void (*copy_block)(uint8_t *, uint8_t *),
471*8005SMark.Powers@Sun.COM     void (*xor_block)(uint8_t *, uint8_t *))
472*8005SMark.Powers@Sun.COM {
473*8005SMark.Powers@Sun.COM 	uint8_t *cb;
474*8005SMark.Powers@Sun.COM 	ulong_t remainder = iv_len;
475*8005SMark.Powers@Sun.COM 	ulong_t processed = 0;
476*8005SMark.Powers@Sun.COM 	uint8_t *datap, *ghash;
477*8005SMark.Powers@Sun.COM 	uint64_t len_a_len_c[2];
478*8005SMark.Powers@Sun.COM 
479*8005SMark.Powers@Sun.COM 	ghash = (uint8_t *)ctx->gcm_ghash;
480*8005SMark.Powers@Sun.COM 	cb = (uint8_t *)ctx->gcm_cb;
481*8005SMark.Powers@Sun.COM 	if (iv_len == 12) {
482*8005SMark.Powers@Sun.COM 		bcopy(iv, cb, 12);
483*8005SMark.Powers@Sun.COM 		cb[12] = 0;
484*8005SMark.Powers@Sun.COM 		cb[13] = 0;
485*8005SMark.Powers@Sun.COM 		cb[14] = 0;
486*8005SMark.Powers@Sun.COM 		cb[15] = 1;
487*8005SMark.Powers@Sun.COM 		/* J0 will be used again in the final */
488*8005SMark.Powers@Sun.COM 		copy_block(cb, (uint8_t *)ctx->gcm_J0);
489*8005SMark.Powers@Sun.COM 	} else {
490*8005SMark.Powers@Sun.COM 		/* GHASH the IV */
491*8005SMark.Powers@Sun.COM 		do {
492*8005SMark.Powers@Sun.COM 			if (remainder < block_size) {
493*8005SMark.Powers@Sun.COM 				bzero(cb, block_size);
494*8005SMark.Powers@Sun.COM 				bcopy(&(iv[processed]), cb, remainder);
495*8005SMark.Powers@Sun.COM 				datap = (uint8_t *)cb;
496*8005SMark.Powers@Sun.COM 				remainder = 0;
497*8005SMark.Powers@Sun.COM 			} else {
498*8005SMark.Powers@Sun.COM 				datap = (uint8_t *)(&(iv[processed]));
499*8005SMark.Powers@Sun.COM 				processed += block_size;
500*8005SMark.Powers@Sun.COM 				remainder -= block_size;
501*8005SMark.Powers@Sun.COM 			}
502*8005SMark.Powers@Sun.COM 			GHASH(ctx, datap, ghash);
503*8005SMark.Powers@Sun.COM 		} while (remainder > 0);
504*8005SMark.Powers@Sun.COM 
505*8005SMark.Powers@Sun.COM 		len_a_len_c[0] = 0;
506*8005SMark.Powers@Sun.COM 		len_a_len_c[1] = htonll(iv_len << 3);
507*8005SMark.Powers@Sun.COM 		GHASH(ctx, len_a_len_c, ctx->gcm_J0);
508*8005SMark.Powers@Sun.COM 
509*8005SMark.Powers@Sun.COM 		/* J0 will be used again in the final */
510*8005SMark.Powers@Sun.COM 		copy_block((uint8_t *)ctx->gcm_J0, (uint8_t *)cb);
511*8005SMark.Powers@Sun.COM 	}
512*8005SMark.Powers@Sun.COM }
513*8005SMark.Powers@Sun.COM 
514*8005SMark.Powers@Sun.COM /*
515*8005SMark.Powers@Sun.COM  * The following function is called at encrypt or decrypt init time
516*8005SMark.Powers@Sun.COM  * for AES GCM mode.
517*8005SMark.Powers@Sun.COM  */
518*8005SMark.Powers@Sun.COM int
519*8005SMark.Powers@Sun.COM gcm_init(gcm_ctx_t *ctx, unsigned char *iv, size_t iv_len,
520*8005SMark.Powers@Sun.COM     unsigned char *auth_data, size_t auth_data_len, size_t block_size,
521*8005SMark.Powers@Sun.COM     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
522*8005SMark.Powers@Sun.COM     void (*copy_block)(uint8_t *, uint8_t *),
523*8005SMark.Powers@Sun.COM     void (*xor_block)(uint8_t *, uint8_t *))
524*8005SMark.Powers@Sun.COM {
525*8005SMark.Powers@Sun.COM 	uint8_t *ghash, *datap, *authp;
526*8005SMark.Powers@Sun.COM 	size_t remainder, processed;
527*8005SMark.Powers@Sun.COM 
528*8005SMark.Powers@Sun.COM 	/* encrypt zero block to get subkey H */
529*8005SMark.Powers@Sun.COM 	bzero(ctx->gcm_H, sizeof (ctx->gcm_H));
530*8005SMark.Powers@Sun.COM 	encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_H,
531*8005SMark.Powers@Sun.COM 	    (uint8_t *)ctx->gcm_H);
532*8005SMark.Powers@Sun.COM 
533*8005SMark.Powers@Sun.COM 	gcm_format_initial_blocks(iv, iv_len, ctx, block_size,
534*8005SMark.Powers@Sun.COM 	    copy_block, xor_block);
535*8005SMark.Powers@Sun.COM 
536*8005SMark.Powers@Sun.COM 	authp = (uint8_t *)ctx->gcm_tmp;
537*8005SMark.Powers@Sun.COM 	ghash = (uint8_t *)ctx->gcm_ghash;
538*8005SMark.Powers@Sun.COM 	bzero(authp, block_size);
539*8005SMark.Powers@Sun.COM 	bzero(ghash, block_size);
540*8005SMark.Powers@Sun.COM 
541*8005SMark.Powers@Sun.COM 	processed = 0;
542*8005SMark.Powers@Sun.COM 	remainder = auth_data_len;
543*8005SMark.Powers@Sun.COM 	do {
544*8005SMark.Powers@Sun.COM 		if (remainder < block_size) {
545*8005SMark.Powers@Sun.COM 			/*
546*8005SMark.Powers@Sun.COM 			 * There's not a block full of data, pad rest of
547*8005SMark.Powers@Sun.COM 			 * buffer with zero
548*8005SMark.Powers@Sun.COM 			 */
549*8005SMark.Powers@Sun.COM 			bzero(authp, block_size);
550*8005SMark.Powers@Sun.COM 			bcopy(&(auth_data[processed]), authp, remainder);
551*8005SMark.Powers@Sun.COM 			datap = (uint8_t *)authp;
552*8005SMark.Powers@Sun.COM 			remainder = 0;
553*8005SMark.Powers@Sun.COM 		} else {
554*8005SMark.Powers@Sun.COM 			datap = (uint8_t *)(&(auth_data[processed]));
555*8005SMark.Powers@Sun.COM 			processed += block_size;
556*8005SMark.Powers@Sun.COM 			remainder -= block_size;
557*8005SMark.Powers@Sun.COM 		}
558*8005SMark.Powers@Sun.COM 
559*8005SMark.Powers@Sun.COM 		/* add auth data to the hash */
560*8005SMark.Powers@Sun.COM 		GHASH(ctx, datap, ghash);
561*8005SMark.Powers@Sun.COM 
562*8005SMark.Powers@Sun.COM 	} while (remainder > 0);
563*8005SMark.Powers@Sun.COM 
564*8005SMark.Powers@Sun.COM 	return (CRYPTO_SUCCESS);
565*8005SMark.Powers@Sun.COM }
566*8005SMark.Powers@Sun.COM 
567*8005SMark.Powers@Sun.COM int
568*8005SMark.Powers@Sun.COM gcm_init_ctx(gcm_ctx_t *gcm_ctx, char *param, size_t block_size,
569*8005SMark.Powers@Sun.COM     int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
570*8005SMark.Powers@Sun.COM     void (*copy_block)(uint8_t *, uint8_t *),
571*8005SMark.Powers@Sun.COM     void (*xor_block)(uint8_t *, uint8_t *))
572*8005SMark.Powers@Sun.COM {
573*8005SMark.Powers@Sun.COM 	int rv;
574*8005SMark.Powers@Sun.COM 	CK_AES_GCM_PARAMS *gcm_param;
575*8005SMark.Powers@Sun.COM 
576*8005SMark.Powers@Sun.COM 	if (param != NULL) {
577*8005SMark.Powers@Sun.COM 		gcm_param = (CK_AES_GCM_PARAMS *)param;
578*8005SMark.Powers@Sun.COM 
579*8005SMark.Powers@Sun.COM 		if ((rv = gcm_validate_args(gcm_param)) != 0) {
580*8005SMark.Powers@Sun.COM 			return (rv);
581*8005SMark.Powers@Sun.COM 		}
582*8005SMark.Powers@Sun.COM 
583*8005SMark.Powers@Sun.COM 		gcm_ctx->gcm_tag_len = gcm_param->ulTagBits;
584*8005SMark.Powers@Sun.COM 		gcm_ctx->gcm_tag_len >>= 3;
585*8005SMark.Powers@Sun.COM 		gcm_ctx->gcm_processed_data_len = 0;
586*8005SMark.Powers@Sun.COM 
587*8005SMark.Powers@Sun.COM 		/* these values are in bits */
588*8005SMark.Powers@Sun.COM 		gcm_ctx->gcm_len_a_len_c[0] = htonll(gcm_param->ulAADLen << 3);
589*8005SMark.Powers@Sun.COM 
590*8005SMark.Powers@Sun.COM 		rv = CRYPTO_SUCCESS;
591*8005SMark.Powers@Sun.COM 		gcm_ctx->gcm_flags |= GCM_MODE;
592*8005SMark.Powers@Sun.COM 	} else {
593*8005SMark.Powers@Sun.COM 		rv = CRYPTO_MECHANISM_PARAM_INVALID;
594*8005SMark.Powers@Sun.COM 		goto out;
595*8005SMark.Powers@Sun.COM 	}
596*8005SMark.Powers@Sun.COM 
597*8005SMark.Powers@Sun.COM 	if (gcm_init(gcm_ctx, gcm_param->pIv, gcm_param->ulIvLen,
598*8005SMark.Powers@Sun.COM 	    gcm_param->pAAD, gcm_param->ulAADLen, block_size,
599*8005SMark.Powers@Sun.COM 	    encrypt_block, copy_block, xor_block) != 0) {
600*8005SMark.Powers@Sun.COM 		rv = CRYPTO_MECHANISM_PARAM_INVALID;
601*8005SMark.Powers@Sun.COM 	}
602*8005SMark.Powers@Sun.COM out:
603*8005SMark.Powers@Sun.COM 	return (rv);
604*8005SMark.Powers@Sun.COM }
605*8005SMark.Powers@Sun.COM 
606*8005SMark.Powers@Sun.COM void *
607*8005SMark.Powers@Sun.COM gcm_alloc_ctx(int kmflag)
608*8005SMark.Powers@Sun.COM {
609*8005SMark.Powers@Sun.COM 	gcm_ctx_t *gcm_ctx;
610*8005SMark.Powers@Sun.COM 
611*8005SMark.Powers@Sun.COM #ifdef _KERNEL
612*8005SMark.Powers@Sun.COM 	if ((gcm_ctx = kmem_zalloc(sizeof (gcm_ctx_t), kmflag)) == NULL)
613*8005SMark.Powers@Sun.COM #else
614*8005SMark.Powers@Sun.COM 	if ((gcm_ctx = calloc(1, sizeof (gcm_ctx_t))) == NULL)
615*8005SMark.Powers@Sun.COM #endif
616*8005SMark.Powers@Sun.COM 		return (NULL);
617*8005SMark.Powers@Sun.COM 
618*8005SMark.Powers@Sun.COM 	gcm_ctx->gcm_flags = GCM_MODE;
619*8005SMark.Powers@Sun.COM 	return (gcm_ctx);
620*8005SMark.Powers@Sun.COM }
621*8005SMark.Powers@Sun.COM 
622*8005SMark.Powers@Sun.COM void
623*8005SMark.Powers@Sun.COM gcm_set_kmflag(gcm_ctx_t *ctx, int kmflag)
624*8005SMark.Powers@Sun.COM {
625*8005SMark.Powers@Sun.COM 	ctx->gcm_kmflag = kmflag;
626*8005SMark.Powers@Sun.COM }
627