xref: /titanic_53/usr/src/common/crypto/modes/cbc.c (revision 23c57df72989c916b3e98084eb88d48777999691)
1*23c57df7Smcpowers /*
2*23c57df7Smcpowers  * CDDL HEADER START
3*23c57df7Smcpowers  *
4*23c57df7Smcpowers  * The contents of this file are subject to the terms of the
5*23c57df7Smcpowers  * Common Development and Distribution License (the "License").
6*23c57df7Smcpowers  * You may not use this file except in compliance with the License.
7*23c57df7Smcpowers  *
8*23c57df7Smcpowers  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*23c57df7Smcpowers  * or http://www.opensolaris.org/os/licensing.
10*23c57df7Smcpowers  * See the License for the specific language governing permissions
11*23c57df7Smcpowers  * and limitations under the License.
12*23c57df7Smcpowers  *
13*23c57df7Smcpowers  * When distributing Covered Code, include this CDDL HEADER in each
14*23c57df7Smcpowers  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*23c57df7Smcpowers  * If applicable, add the following below this CDDL HEADER, with the
16*23c57df7Smcpowers  * fields enclosed by brackets "[]" replaced with your own identifying
17*23c57df7Smcpowers  * information: Portions Copyright [yyyy] [name of copyright owner]
18*23c57df7Smcpowers  *
19*23c57df7Smcpowers  * CDDL HEADER END
20*23c57df7Smcpowers  */
21*23c57df7Smcpowers /*
22*23c57df7Smcpowers  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*23c57df7Smcpowers  * Use is subject to license terms.
24*23c57df7Smcpowers  */
25*23c57df7Smcpowers 
26*23c57df7Smcpowers #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*23c57df7Smcpowers 
28*23c57df7Smcpowers #ifndef _KERNEL
29*23c57df7Smcpowers #include <strings.h>
30*23c57df7Smcpowers #include <limits.h>
31*23c57df7Smcpowers #include <assert.h>
32*23c57df7Smcpowers #include <security/cryptoki.h>
33*23c57df7Smcpowers #endif
34*23c57df7Smcpowers 
35*23c57df7Smcpowers #include <sys/types.h>
36*23c57df7Smcpowers #include <modes/modes.h>
37*23c57df7Smcpowers #include <sys/crypto/common.h>
38*23c57df7Smcpowers #include <sys/crypto/impl.h>
39*23c57df7Smcpowers 
40*23c57df7Smcpowers /*
41*23c57df7Smcpowers  * Algorithm independent CBC functions.
42*23c57df7Smcpowers  */
43*23c57df7Smcpowers int
44*23c57df7Smcpowers cbc_encrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
45*23c57df7Smcpowers     crypto_data_t *out, size_t block_size,
46*23c57df7Smcpowers     int (*encrypt)(const void *, const uint8_t *, uint8_t *),
47*23c57df7Smcpowers     void (*copy_block)(uint8_t *, uint8_t *),
48*23c57df7Smcpowers     void (*xor_block)(uint8_t *, uint8_t *))
49*23c57df7Smcpowers {
50*23c57df7Smcpowers 	size_t remainder = length;
51*23c57df7Smcpowers 	size_t need;
52*23c57df7Smcpowers 	uint8_t *datap = (uint8_t *)data;
53*23c57df7Smcpowers 	uint8_t *blockp;
54*23c57df7Smcpowers 	uint8_t *lastp;
55*23c57df7Smcpowers 	void *iov_or_mp;
56*23c57df7Smcpowers 	offset_t offset;
57*23c57df7Smcpowers 	uint8_t *out_data_1;
58*23c57df7Smcpowers 	uint8_t *out_data_2;
59*23c57df7Smcpowers 	size_t out_data_1_len;
60*23c57df7Smcpowers 
61*23c57df7Smcpowers 	if (length + ctx->cc_remainder_len < block_size) {
62*23c57df7Smcpowers 		/* accumulate bytes here and return */
63*23c57df7Smcpowers 		bcopy(datap,
64*23c57df7Smcpowers 		    (uint8_t *)ctx->cc_remainder + ctx->cc_remainder_len,
65*23c57df7Smcpowers 		    length);
66*23c57df7Smcpowers 		ctx->cc_remainder_len += length;
67*23c57df7Smcpowers 		ctx->cc_copy_to = datap;
68*23c57df7Smcpowers 		return (CRYPTO_SUCCESS);
69*23c57df7Smcpowers 	}
70*23c57df7Smcpowers 
71*23c57df7Smcpowers 	lastp = (uint8_t *)ctx->cc_iv;
72*23c57df7Smcpowers 	if (out != NULL)
73*23c57df7Smcpowers 		crypto_init_ptrs(out, &iov_or_mp, &offset);
74*23c57df7Smcpowers 
75*23c57df7Smcpowers 	do {
76*23c57df7Smcpowers 		/* Unprocessed data from last call. */
77*23c57df7Smcpowers 		if (ctx->cc_remainder_len > 0) {
78*23c57df7Smcpowers 			need = block_size - ctx->cc_remainder_len;
79*23c57df7Smcpowers 
80*23c57df7Smcpowers 			if (need > remainder)
81*23c57df7Smcpowers 				return (CRYPTO_DATA_LEN_RANGE);
82*23c57df7Smcpowers 
83*23c57df7Smcpowers 			bcopy(datap, &((uint8_t *)ctx->cc_remainder)
84*23c57df7Smcpowers 			    [ctx->cc_remainder_len], need);
85*23c57df7Smcpowers 
86*23c57df7Smcpowers 			blockp = (uint8_t *)ctx->cc_remainder;
87*23c57df7Smcpowers 		} else {
88*23c57df7Smcpowers 			blockp = datap;
89*23c57df7Smcpowers 		}
90*23c57df7Smcpowers 
91*23c57df7Smcpowers 		if (out == NULL) {
92*23c57df7Smcpowers 			/*
93*23c57df7Smcpowers 			 * XOR the previous cipher block or IV with the
94*23c57df7Smcpowers 			 * current clear block.
95*23c57df7Smcpowers 			 */
96*23c57df7Smcpowers 			xor_block(lastp, blockp);
97*23c57df7Smcpowers 			encrypt(ctx->cc_keysched, blockp, blockp);
98*23c57df7Smcpowers 
99*23c57df7Smcpowers 			ctx->cc_lastp = blockp;
100*23c57df7Smcpowers 			lastp = blockp;
101*23c57df7Smcpowers 
102*23c57df7Smcpowers 			if (ctx->cc_remainder_len > 0) {
103*23c57df7Smcpowers 				bcopy(blockp, ctx->cc_copy_to,
104*23c57df7Smcpowers 				    ctx->cc_remainder_len);
105*23c57df7Smcpowers 				bcopy(blockp + ctx->cc_remainder_len, datap,
106*23c57df7Smcpowers 				    need);
107*23c57df7Smcpowers 			}
108*23c57df7Smcpowers 		} else {
109*23c57df7Smcpowers 			/*
110*23c57df7Smcpowers 			 * XOR the previous cipher block or IV with the
111*23c57df7Smcpowers 			 * current clear block.
112*23c57df7Smcpowers 			 */
113*23c57df7Smcpowers 			xor_block(blockp, lastp);
114*23c57df7Smcpowers 			encrypt(ctx->cc_keysched, lastp, lastp);
115*23c57df7Smcpowers 			crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
116*23c57df7Smcpowers 			    &out_data_1_len, &out_data_2, block_size);
117*23c57df7Smcpowers 
118*23c57df7Smcpowers 			/* copy block to where it belongs */
119*23c57df7Smcpowers 			if (out_data_1_len == block_size) {
120*23c57df7Smcpowers 				copy_block(lastp, out_data_1);
121*23c57df7Smcpowers 			} else {
122*23c57df7Smcpowers 				bcopy(lastp, out_data_1, out_data_1_len);
123*23c57df7Smcpowers 				if (out_data_2 != NULL) {
124*23c57df7Smcpowers 					bcopy(lastp + out_data_1_len,
125*23c57df7Smcpowers 					    out_data_2,
126*23c57df7Smcpowers 					    block_size - out_data_1_len);
127*23c57df7Smcpowers 				}
128*23c57df7Smcpowers 			}
129*23c57df7Smcpowers 			/* update offset */
130*23c57df7Smcpowers 			out->cd_offset += block_size;
131*23c57df7Smcpowers 		}
132*23c57df7Smcpowers 
133*23c57df7Smcpowers 		/* Update pointer to next block of data to be processed. */
134*23c57df7Smcpowers 		if (ctx->cc_remainder_len != 0) {
135*23c57df7Smcpowers 			datap += need;
136*23c57df7Smcpowers 			ctx->cc_remainder_len = 0;
137*23c57df7Smcpowers 		} else {
138*23c57df7Smcpowers 			datap += block_size;
139*23c57df7Smcpowers 		}
140*23c57df7Smcpowers 
141*23c57df7Smcpowers 		remainder = (size_t)&data[length] - (size_t)datap;
142*23c57df7Smcpowers 
143*23c57df7Smcpowers 		/* Incomplete last block. */
144*23c57df7Smcpowers 		if (remainder > 0 && remainder < block_size) {
145*23c57df7Smcpowers 			bcopy(datap, ctx->cc_remainder, remainder);
146*23c57df7Smcpowers 			ctx->cc_remainder_len = remainder;
147*23c57df7Smcpowers 			ctx->cc_copy_to = datap;
148*23c57df7Smcpowers 			goto out;
149*23c57df7Smcpowers 		}
150*23c57df7Smcpowers 		ctx->cc_copy_to = NULL;
151*23c57df7Smcpowers 
152*23c57df7Smcpowers 	} while (remainder > 0);
153*23c57df7Smcpowers 
154*23c57df7Smcpowers out:
155*23c57df7Smcpowers 	/*
156*23c57df7Smcpowers 	 * Save the last encrypted block in the context.
157*23c57df7Smcpowers 	 */
158*23c57df7Smcpowers 	if (ctx->cc_lastp != NULL) {
159*23c57df7Smcpowers 		copy_block((uint8_t *)ctx->cc_lastp, (uint8_t *)ctx->cc_iv);
160*23c57df7Smcpowers 		ctx->cc_lastp = (uint8_t *)ctx->cc_iv;
161*23c57df7Smcpowers 	}
162*23c57df7Smcpowers 
163*23c57df7Smcpowers 	return (CRYPTO_SUCCESS);
164*23c57df7Smcpowers }
165*23c57df7Smcpowers 
166*23c57df7Smcpowers #define	OTHER(a, ctx) \
167*23c57df7Smcpowers 	(((a) == (ctx)->cc_lastblock) ? (ctx)->cc_iv : (ctx)->cc_lastblock)
168*23c57df7Smcpowers 
169*23c57df7Smcpowers /* ARGSUSED */
170*23c57df7Smcpowers int
171*23c57df7Smcpowers cbc_decrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
172*23c57df7Smcpowers     crypto_data_t *out, size_t block_size,
173*23c57df7Smcpowers     int (*decrypt)(const void *, const uint8_t *, uint8_t *),
174*23c57df7Smcpowers     void (*copy_block)(uint8_t *, uint8_t *),
175*23c57df7Smcpowers     void (*xor_block)(uint8_t *, uint8_t *))
176*23c57df7Smcpowers {
177*23c57df7Smcpowers 	size_t remainder = length;
178*23c57df7Smcpowers 	size_t need;
179*23c57df7Smcpowers 	uint8_t *datap = (uint8_t *)data;
180*23c57df7Smcpowers 	uint8_t *blockp;
181*23c57df7Smcpowers 	uint8_t *lastp;
182*23c57df7Smcpowers 	void *iov_or_mp;
183*23c57df7Smcpowers 	offset_t offset;
184*23c57df7Smcpowers 	uint8_t *out_data_1;
185*23c57df7Smcpowers 	uint8_t *out_data_2;
186*23c57df7Smcpowers 	size_t out_data_1_len;
187*23c57df7Smcpowers 
188*23c57df7Smcpowers 	if (length + ctx->cc_remainder_len < block_size) {
189*23c57df7Smcpowers 		/* accumulate bytes here and return */
190*23c57df7Smcpowers 		bcopy(datap,
191*23c57df7Smcpowers 		    (uint8_t *)ctx->cc_remainder + ctx->cc_remainder_len,
192*23c57df7Smcpowers 		    length);
193*23c57df7Smcpowers 		ctx->cc_remainder_len += length;
194*23c57df7Smcpowers 		ctx->cc_copy_to = datap;
195*23c57df7Smcpowers 		return (CRYPTO_SUCCESS);
196*23c57df7Smcpowers 	}
197*23c57df7Smcpowers 
198*23c57df7Smcpowers 	lastp = ctx->cc_lastp;
199*23c57df7Smcpowers 	if (out != NULL)
200*23c57df7Smcpowers 		crypto_init_ptrs(out, &iov_or_mp, &offset);
201*23c57df7Smcpowers 
202*23c57df7Smcpowers 	do {
203*23c57df7Smcpowers 		/* Unprocessed data from last call. */
204*23c57df7Smcpowers 		if (ctx->cc_remainder_len > 0) {
205*23c57df7Smcpowers 			need = block_size - ctx->cc_remainder_len;
206*23c57df7Smcpowers 
207*23c57df7Smcpowers 			if (need > remainder)
208*23c57df7Smcpowers 				return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
209*23c57df7Smcpowers 
210*23c57df7Smcpowers 			bcopy(datap, &((uint8_t *)ctx->cc_remainder)
211*23c57df7Smcpowers 			    [ctx->cc_remainder_len], need);
212*23c57df7Smcpowers 
213*23c57df7Smcpowers 			blockp = (uint8_t *)ctx->cc_remainder;
214*23c57df7Smcpowers 		} else {
215*23c57df7Smcpowers 			blockp = datap;
216*23c57df7Smcpowers 		}
217*23c57df7Smcpowers 
218*23c57df7Smcpowers 		/* LINTED: pointer alignment */
219*23c57df7Smcpowers 		copy_block(blockp, (uint8_t *)OTHER((uint64_t *)lastp, ctx));
220*23c57df7Smcpowers 
221*23c57df7Smcpowers 		if (out != NULL) {
222*23c57df7Smcpowers 			decrypt(ctx->cc_keysched, blockp,
223*23c57df7Smcpowers 			    (uint8_t *)ctx->cc_remainder);
224*23c57df7Smcpowers 			blockp = (uint8_t *)ctx->cc_remainder;
225*23c57df7Smcpowers 		} else {
226*23c57df7Smcpowers 			decrypt(ctx->cc_keysched, blockp, blockp);
227*23c57df7Smcpowers 		}
228*23c57df7Smcpowers 
229*23c57df7Smcpowers 		/*
230*23c57df7Smcpowers 		 * XOR the previous cipher block or IV with the
231*23c57df7Smcpowers 		 * currently decrypted block.
232*23c57df7Smcpowers 		 */
233*23c57df7Smcpowers 		xor_block(lastp, blockp);
234*23c57df7Smcpowers 
235*23c57df7Smcpowers 		/* LINTED: pointer alignment */
236*23c57df7Smcpowers 		lastp = (uint8_t *)OTHER((uint64_t *)lastp, ctx);
237*23c57df7Smcpowers 
238*23c57df7Smcpowers 		if (out != NULL) {
239*23c57df7Smcpowers 			crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
240*23c57df7Smcpowers 			    &out_data_1_len, &out_data_2, block_size);
241*23c57df7Smcpowers 
242*23c57df7Smcpowers 			bcopy(blockp, out_data_1, out_data_1_len);
243*23c57df7Smcpowers 			if (out_data_2 != NULL) {
244*23c57df7Smcpowers 				bcopy(blockp + out_data_1_len, out_data_2,
245*23c57df7Smcpowers 				    block_size - out_data_1_len);
246*23c57df7Smcpowers 			}
247*23c57df7Smcpowers 
248*23c57df7Smcpowers 			/* update offset */
249*23c57df7Smcpowers 			out->cd_offset += block_size;
250*23c57df7Smcpowers 
251*23c57df7Smcpowers 		} else if (ctx->cc_remainder_len > 0) {
252*23c57df7Smcpowers 			/* copy temporary block to where it belongs */
253*23c57df7Smcpowers 			bcopy(blockp, ctx->cc_copy_to, ctx->cc_remainder_len);
254*23c57df7Smcpowers 			bcopy(blockp + ctx->cc_remainder_len, datap, need);
255*23c57df7Smcpowers 		}
256*23c57df7Smcpowers 
257*23c57df7Smcpowers 		/* Update pointer to next block of data to be processed. */
258*23c57df7Smcpowers 		if (ctx->cc_remainder_len != 0) {
259*23c57df7Smcpowers 			datap += need;
260*23c57df7Smcpowers 			ctx->cc_remainder_len = 0;
261*23c57df7Smcpowers 		} else {
262*23c57df7Smcpowers 			datap += block_size;
263*23c57df7Smcpowers 		}
264*23c57df7Smcpowers 
265*23c57df7Smcpowers 		remainder = (size_t)&data[length] - (size_t)datap;
266*23c57df7Smcpowers 
267*23c57df7Smcpowers 		/* Incomplete last block. */
268*23c57df7Smcpowers 		if (remainder > 0 && remainder < block_size) {
269*23c57df7Smcpowers 			bcopy(datap, ctx->cc_remainder, remainder);
270*23c57df7Smcpowers 			ctx->cc_remainder_len = remainder;
271*23c57df7Smcpowers 			ctx->cc_lastp = lastp;
272*23c57df7Smcpowers 			ctx->cc_copy_to = datap;
273*23c57df7Smcpowers 			return (CRYPTO_SUCCESS);
274*23c57df7Smcpowers 		}
275*23c57df7Smcpowers 		ctx->cc_copy_to = NULL;
276*23c57df7Smcpowers 
277*23c57df7Smcpowers 	} while (remainder > 0);
278*23c57df7Smcpowers 
279*23c57df7Smcpowers 	ctx->cc_lastp = lastp;
280*23c57df7Smcpowers 	return (CRYPTO_SUCCESS);
281*23c57df7Smcpowers }
282*23c57df7Smcpowers 
283*23c57df7Smcpowers int
284*23c57df7Smcpowers cbc_init_ctx(cbc_ctx_t *cbc_ctx, char *param, size_t param_len,
285*23c57df7Smcpowers     size_t block_size, void (*copy_block)(uint8_t *, uint64_t *))
286*23c57df7Smcpowers {
287*23c57df7Smcpowers 	/*
288*23c57df7Smcpowers 	 * Copy IV into context.
289*23c57df7Smcpowers 	 *
290*23c57df7Smcpowers 	 * If cm_param == NULL then the IV comes from the
291*23c57df7Smcpowers 	 * cd_miscdata field in the crypto_data structure.
292*23c57df7Smcpowers 	 */
293*23c57df7Smcpowers 	if (param != NULL) {
294*23c57df7Smcpowers #ifdef _KERNEL
295*23c57df7Smcpowers 		ASSERT(param_len == block_size);
296*23c57df7Smcpowers #else
297*23c57df7Smcpowers 		assert(param_len == block_size);
298*23c57df7Smcpowers #endif
299*23c57df7Smcpowers 		copy_block((uchar_t *)param, cbc_ctx->cc_iv);
300*23c57df7Smcpowers 	}
301*23c57df7Smcpowers 
302*23c57df7Smcpowers 	cbc_ctx->cc_lastp = (uint8_t *)&cbc_ctx->cc_iv[0];
303*23c57df7Smcpowers 	cbc_ctx->cc_flags |= CBC_MODE;
304*23c57df7Smcpowers 	return (CRYPTO_SUCCESS);
305*23c57df7Smcpowers }
306*23c57df7Smcpowers 
307*23c57df7Smcpowers /* ARGSUSED */
308*23c57df7Smcpowers void *
309*23c57df7Smcpowers cbc_alloc_ctx(int kmflag)
310*23c57df7Smcpowers {
311*23c57df7Smcpowers 	cbc_ctx_t *cbc_ctx;
312*23c57df7Smcpowers 
313*23c57df7Smcpowers #ifdef _KERNEL
314*23c57df7Smcpowers 	if ((cbc_ctx = kmem_zalloc(sizeof (cbc_ctx_t), kmflag)) == NULL)
315*23c57df7Smcpowers #else
316*23c57df7Smcpowers 	if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
317*23c57df7Smcpowers #endif
318*23c57df7Smcpowers 		return (NULL);
319*23c57df7Smcpowers 
320*23c57df7Smcpowers 	cbc_ctx->cc_flags = CBC_MODE;
321*23c57df7Smcpowers 	return (cbc_ctx);
322*23c57df7Smcpowers }
323