1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/zfs_context.h>
27 #include <modes/modes.h>
28 #include <sys/crypto/common.h>
29 #include <sys/crypto/impl.h>
30 #include <sys/byteorder.h>
31
32 /*
33 * Encrypt and decrypt multiple blocks of data in counter mode.
34 */
35 int
ctr_mode_contiguous_blocks(ctr_ctx_t * ctx,char * data,size_t length,crypto_data_t * out,size_t block_size,int (* cipher)(const void * ks,const uint8_t * pt,uint8_t * ct),void (* xor_block)(uint8_t *,uint8_t *))36 ctr_mode_contiguous_blocks(ctr_ctx_t *ctx, char *data, size_t length,
37 crypto_data_t *out, size_t block_size,
38 int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct),
39 void (*xor_block)(uint8_t *, uint8_t *))
40 {
41 size_t remainder = length;
42 size_t need = 0;
43 uint8_t *datap = (uint8_t *)data;
44 uint8_t *blockp;
45 uint8_t *lastp;
46 void *iov_or_mp;
47 offset_t offset;
48 uint8_t *out_data_1;
49 uint8_t *out_data_2;
50 size_t out_data_1_len;
51 uint64_t lower_counter, upper_counter;
52
53 if (length + ctx->ctr_remainder_len < block_size) {
54 /* accumulate bytes here and return */
55 bcopy(datap,
56 (uint8_t *)ctx->ctr_remainder + ctx->ctr_remainder_len,
57 length);
58 ctx->ctr_remainder_len += length;
59 ctx->ctr_copy_to = datap;
60 return (CRYPTO_SUCCESS);
61 }
62
63 lastp = (uint8_t *)ctx->ctr_cb;
64 crypto_init_ptrs(out, &iov_or_mp, &offset);
65
66 do {
67 /* Unprocessed data from last call. */
68 if (ctx->ctr_remainder_len > 0) {
69 need = block_size - ctx->ctr_remainder_len;
70
71 if (need > remainder)
72 return (CRYPTO_DATA_LEN_RANGE);
73
74 bcopy(datap, &((uint8_t *)ctx->ctr_remainder)
75 [ctx->ctr_remainder_len], need);
76
77 blockp = (uint8_t *)ctx->ctr_remainder;
78 } else {
79 blockp = datap;
80 }
81
82 /* ctr_cb is the counter block */
83 cipher(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb,
84 (uint8_t *)ctx->ctr_tmp);
85
86 lastp = (uint8_t *)ctx->ctr_tmp;
87
88 /*
89 * Increment Counter.
90 */
91 lower_counter = ntohll(ctx->ctr_cb[1] & ctx->ctr_lower_mask);
92 lower_counter = htonll(lower_counter + 1);
93 lower_counter &= ctx->ctr_lower_mask;
94 ctx->ctr_cb[1] = (ctx->ctr_cb[1] & ~(ctx->ctr_lower_mask)) |
95 lower_counter;
96
97 /* wrap around */
98 if (lower_counter == 0) {
99 upper_counter =
100 ntohll(ctx->ctr_cb[0] & ctx->ctr_upper_mask);
101 upper_counter = htonll(upper_counter + 1);
102 upper_counter &= ctx->ctr_upper_mask;
103 ctx->ctr_cb[0] =
104 (ctx->ctr_cb[0] & ~(ctx->ctr_upper_mask)) |
105 upper_counter;
106 }
107
108 /*
109 * XOR encrypted counter block with the current clear block.
110 */
111 xor_block(blockp, lastp);
112
113 crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
114 &out_data_1_len, &out_data_2, block_size);
115
116 /* copy block to where it belongs */
117 bcopy(lastp, out_data_1, out_data_1_len);
118 if (out_data_2 != NULL) {
119 bcopy(lastp + out_data_1_len, out_data_2,
120 block_size - out_data_1_len);
121 }
122 /* update offset */
123 out->cd_offset += block_size;
124
125 /* Update pointer to next block of data to be processed. */
126 if (ctx->ctr_remainder_len != 0) {
127 datap += need;
128 ctx->ctr_remainder_len = 0;
129 } else {
130 datap += block_size;
131 }
132
133 remainder = (size_t)&data[length] - (size_t)datap;
134
135 /* Incomplete last block. */
136 if (remainder > 0 && remainder < block_size) {
137 bcopy(datap, ctx->ctr_remainder, remainder);
138 ctx->ctr_remainder_len = remainder;
139 ctx->ctr_copy_to = datap;
140 goto out;
141 }
142 ctx->ctr_copy_to = NULL;
143
144 } while (remainder > 0);
145
146 out:
147 return (CRYPTO_SUCCESS);
148 }
149
150 int
ctr_mode_final(ctr_ctx_t * ctx,crypto_data_t * out,int (* encrypt_block)(const void *,const uint8_t *,uint8_t *))151 ctr_mode_final(ctr_ctx_t *ctx, crypto_data_t *out,
152 int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))
153 {
154 uint8_t *lastp;
155 void *iov_or_mp;
156 offset_t offset;
157 uint8_t *out_data_1;
158 uint8_t *out_data_2;
159 size_t out_data_1_len;
160 uint8_t *p;
161 int i;
162
163 if (out->cd_length < ctx->ctr_remainder_len)
164 return (CRYPTO_DATA_LEN_RANGE);
165
166 encrypt_block(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb,
167 (uint8_t *)ctx->ctr_tmp);
168
169 lastp = (uint8_t *)ctx->ctr_tmp;
170 p = (uint8_t *)ctx->ctr_remainder;
171 for (i = 0; i < ctx->ctr_remainder_len; i++) {
172 p[i] ^= lastp[i];
173 }
174
175 crypto_init_ptrs(out, &iov_or_mp, &offset);
176 crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
177 &out_data_1_len, &out_data_2, ctx->ctr_remainder_len);
178
179 bcopy(p, out_data_1, out_data_1_len);
180 if (out_data_2 != NULL) {
181 bcopy((uint8_t *)p + out_data_1_len,
182 out_data_2, ctx->ctr_remainder_len - out_data_1_len);
183 }
184 out->cd_offset += ctx->ctr_remainder_len;
185 ctx->ctr_remainder_len = 0;
186 return (CRYPTO_SUCCESS);
187 }
188
189 int
ctr_init_ctx(ctr_ctx_t * ctr_ctx,ulong_t count,uint8_t * cb,void (* copy_block)(uint8_t *,uint8_t *))190 ctr_init_ctx(ctr_ctx_t *ctr_ctx, ulong_t count, uint8_t *cb,
191 void (*copy_block)(uint8_t *, uint8_t *))
192 {
193 uint64_t upper_mask = 0;
194 uint64_t lower_mask = 0;
195
196 if (count == 0 || count > 128) {
197 return (CRYPTO_MECHANISM_PARAM_INVALID);
198 }
199 /* upper 64 bits of the mask */
200 if (count >= 64) {
201 count -= 64;
202 upper_mask = (count == 64) ? UINT64_MAX : (1ULL << count) - 1;
203 lower_mask = UINT64_MAX;
204 } else {
205 /* now the lower 63 bits */
206 lower_mask = (1ULL << count) - 1;
207 }
208 ctr_ctx->ctr_lower_mask = htonll(lower_mask);
209 ctr_ctx->ctr_upper_mask = htonll(upper_mask);
210
211 copy_block(cb, (uchar_t *)ctr_ctx->ctr_cb);
212 ctr_ctx->ctr_lastp = (uint8_t *)&ctr_ctx->ctr_cb[0];
213 ctr_ctx->ctr_flags |= CTR_MODE;
214 return (CRYPTO_SUCCESS);
215 }
216
217 /* ARGSUSED */
218 void *
ctr_alloc_ctx(int kmflag)219 ctr_alloc_ctx(int kmflag)
220 {
221 ctr_ctx_t *ctr_ctx;
222
223 if ((ctr_ctx = kmem_zalloc(sizeof (ctr_ctx_t), kmflag)) == NULL)
224 return (NULL);
225
226 ctr_ctx->ctr_flags = CTR_MODE;
227 return (ctr_ctx);
228 }
229