4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
30 #include <security/cryptoki.h>
33 #include <sys/types.h>
34 #include <modes/modes.h>
35 #include <sys/crypto/common.h>
36 #include <sys/crypto/impl.h>
39 * Algorithm independent CBC functions.
42 cbc_encrypt_contiguous_blocks(cbc_ctx_t
*ctx
, char *data
, size_t length
,
43 crypto_data_t
*out
, size_t block_size
,
44 int (*encrypt
)(const void *, const uint8_t *, uint8_t *),
45 void (*copy_block
)(uint8_t *, uint8_t *),
46 void (*xor_block
)(uint8_t *, uint8_t *))
48 size_t remainder
= length
;
50 uint8_t *datap
= (uint8_t *)data
;
57 size_t out_data_1_len
;
59 if (length
+ ctx
->cbc_remainder_len
< block_size
) {
60 /* accumulate bytes here and return */
62 (uint8_t *)ctx
->cbc_remainder
+ ctx
->cbc_remainder_len
,
64 ctx
->cbc_remainder_len
+= length
;
65 ctx
->cbc_copy_to
= datap
;
66 return (CRYPTO_SUCCESS
);
69 lastp
= (uint8_t *)ctx
->cbc_iv
;
71 crypto_init_ptrs(out
, &iov_or_mp
, &offset
);
74 /* Unprocessed data from last call. */
75 if (ctx
->cbc_remainder_len
> 0) {
76 need
= block_size
- ctx
->cbc_remainder_len
;
79 return (CRYPTO_DATA_LEN_RANGE
);
81 bcopy(datap
, &((uint8_t *)ctx
->cbc_remainder
)
82 [ctx
->cbc_remainder_len
], need
);
84 blockp
= (uint8_t *)ctx
->cbc_remainder
;
91 * XOR the previous cipher block or IV with the
92 * current clear block.
94 xor_block(lastp
, blockp
);
95 encrypt(ctx
->cbc_keysched
, blockp
, blockp
);
97 ctx
->cbc_lastp
= blockp
;
100 if (ctx
->cbc_remainder_len
> 0) {
101 bcopy(blockp
, ctx
->cbc_copy_to
,
102 ctx
->cbc_remainder_len
);
103 bcopy(blockp
+ ctx
->cbc_remainder_len
, datap
,
108 * XOR the previous cipher block or IV with the
109 * current clear block.
111 xor_block(blockp
, lastp
);
112 encrypt(ctx
->cbc_keysched
, lastp
, lastp
);
113 crypto_get_ptrs(out
, &iov_or_mp
, &offset
, &out_data_1
,
114 &out_data_1_len
, &out_data_2
, block_size
);
116 /* copy block to where it belongs */
117 if (out_data_1_len
== block_size
) {
118 copy_block(lastp
, out_data_1
);
120 bcopy(lastp
, out_data_1
, out_data_1_len
);
121 if (out_data_2
!= NULL
) {
122 bcopy(lastp
+ out_data_1_len
,
124 block_size
- out_data_1_len
);
128 out
->cd_offset
+= block_size
;
131 /* Update pointer to next block of data to be processed. */
132 if (ctx
->cbc_remainder_len
!= 0) {
134 ctx
->cbc_remainder_len
= 0;
139 remainder
= (size_t)&data
[length
] - (size_t)datap
;
141 /* Incomplete last block. */
142 if (remainder
> 0 && remainder
< block_size
) {
143 bcopy(datap
, ctx
->cbc_remainder
, remainder
);
144 ctx
->cbc_remainder_len
= remainder
;
145 ctx
->cbc_copy_to
= datap
;
148 ctx
->cbc_copy_to
= NULL
;
150 } while (remainder
> 0);
154 * Save the last encrypted block in the context.
156 if (ctx
->cbc_lastp
!= NULL
) {
157 copy_block((uint8_t *)ctx
->cbc_lastp
, (uint8_t *)ctx
->cbc_iv
);
158 ctx
->cbc_lastp
= (uint8_t *)ctx
->cbc_iv
;
161 return (CRYPTO_SUCCESS
);
164 #define OTHER(a, ctx) \
165 (((a) == (ctx)->cbc_lastblock) ? (ctx)->cbc_iv : (ctx)->cbc_lastblock)
169 cbc_decrypt_contiguous_blocks(cbc_ctx_t
*ctx
, char *data
, size_t length
,
170 crypto_data_t
*out
, size_t block_size
,
171 int (*decrypt
)(const void *, const uint8_t *, uint8_t *),
172 void (*copy_block
)(uint8_t *, uint8_t *),
173 void (*xor_block
)(uint8_t *, uint8_t *))
175 size_t remainder
= length
;
177 uint8_t *datap
= (uint8_t *)data
;
184 size_t out_data_1_len
;
186 if (length
+ ctx
->cbc_remainder_len
< block_size
) {
187 /* accumulate bytes here and return */
189 (uint8_t *)ctx
->cbc_remainder
+ ctx
->cbc_remainder_len
,
191 ctx
->cbc_remainder_len
+= length
;
192 ctx
->cbc_copy_to
= datap
;
193 return (CRYPTO_SUCCESS
);
196 lastp
= ctx
->cbc_lastp
;
198 crypto_init_ptrs(out
, &iov_or_mp
, &offset
);
201 /* Unprocessed data from last call. */
202 if (ctx
->cbc_remainder_len
> 0) {
203 need
= block_size
- ctx
->cbc_remainder_len
;
205 if (need
> remainder
)
206 return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE
);
208 bcopy(datap
, &((uint8_t *)ctx
->cbc_remainder
)
209 [ctx
->cbc_remainder_len
], need
);
211 blockp
= (uint8_t *)ctx
->cbc_remainder
;
216 /* LINTED: pointer alignment */
217 copy_block(blockp
, (uint8_t *)OTHER((uint64_t *)lastp
, ctx
));
220 decrypt(ctx
->cbc_keysched
, blockp
,
221 (uint8_t *)ctx
->cbc_remainder
);
222 blockp
= (uint8_t *)ctx
->cbc_remainder
;
224 decrypt(ctx
->cbc_keysched
, blockp
, blockp
);
228 * XOR the previous cipher block or IV with the
229 * currently decrypted block.
231 xor_block(lastp
, blockp
);
233 /* LINTED: pointer alignment */
234 lastp
= (uint8_t *)OTHER((uint64_t *)lastp
, ctx
);
237 crypto_get_ptrs(out
, &iov_or_mp
, &offset
, &out_data_1
,
238 &out_data_1_len
, &out_data_2
, block_size
);
240 bcopy(blockp
, out_data_1
, out_data_1_len
);
241 if (out_data_2
!= NULL
) {
242 bcopy(blockp
+ out_data_1_len
, out_data_2
,
243 block_size
- out_data_1_len
);
247 out
->cd_offset
+= block_size
;
249 } else if (ctx
->cbc_remainder_len
> 0) {
250 /* copy temporary block to where it belongs */
251 bcopy(blockp
, ctx
->cbc_copy_to
, ctx
->cbc_remainder_len
);
252 bcopy(blockp
+ ctx
->cbc_remainder_len
, datap
, need
);
255 /* Update pointer to next block of data to be processed. */
256 if (ctx
->cbc_remainder_len
!= 0) {
258 ctx
->cbc_remainder_len
= 0;
263 remainder
= (size_t)&data
[length
] - (size_t)datap
;
265 /* Incomplete last block. */
266 if (remainder
> 0 && remainder
< block_size
) {
267 bcopy(datap
, ctx
->cbc_remainder
, remainder
);
268 ctx
->cbc_remainder_len
= remainder
;
269 ctx
->cbc_lastp
= lastp
;
270 ctx
->cbc_copy_to
= datap
;
271 return (CRYPTO_SUCCESS
);
273 ctx
->cbc_copy_to
= NULL
;
275 } while (remainder
> 0);
277 ctx
->cbc_lastp
= lastp
;
278 return (CRYPTO_SUCCESS
);
282 cbc_init_ctx(cbc_ctx_t
*cbc_ctx
, char *param
, size_t param_len
,
283 size_t block_size
, void (*copy_block
)(uint8_t *, uint64_t *))
286 * Copy IV into context.
288 * If cm_param == NULL then the IV comes from the
289 * cd_miscdata field in the crypto_data structure.
293 ASSERT(param_len
== block_size
);
295 assert(param_len
== block_size
);
297 copy_block((uchar_t
*)param
, cbc_ctx
->cbc_iv
);
300 cbc_ctx
->cbc_lastp
= (uint8_t *)&cbc_ctx
->cbc_iv
[0];
301 cbc_ctx
->cbc_flags
|= CBC_MODE
;
302 return (CRYPTO_SUCCESS
);
307 cbc_alloc_ctx(int kmflag
)
312 if ((cbc_ctx
= kmem_zalloc(sizeof (cbc_ctx_t
), kmflag
)) == NULL
)
314 if ((cbc_ctx
= calloc(1, sizeof (cbc_ctx_t
))) == NULL
)
318 cbc_ctx
->cbc_flags
= CBC_MODE
;