]> git.proxmox.com Git - mirror_zfs.git/blob - module/icp/algs/modes/ctr.c
Illumos Crypto Port module added to enable native encryption in zfs
[mirror_zfs.git] / module / icp / algs / modes / ctr.c
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
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 if (out != NULL)
65 crypto_init_ptrs(out, &iov_or_mp, &offset);
66
67 do {
68 /* Unprocessed data from last call. */
69 if (ctx->ctr_remainder_len > 0) {
70 need = block_size - ctx->ctr_remainder_len;
71
72 if (need > remainder)
73 return (CRYPTO_DATA_LEN_RANGE);
74
75 bcopy(datap, &((uint8_t *)ctx->ctr_remainder)
76 [ctx->ctr_remainder_len], need);
77
78 blockp = (uint8_t *)ctx->ctr_remainder;
79 } else {
80 blockp = datap;
81 }
82
83 /* ctr_cb is the counter block */
84 cipher(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb,
85 (uint8_t *)ctx->ctr_tmp);
86
87 lastp = (uint8_t *)ctx->ctr_tmp;
88
89 /*
90 * Increment Counter.
91 */
92 lower_counter = ntohll(ctx->ctr_cb[1] & ctx->ctr_lower_mask);
93 lower_counter = htonll(lower_counter + 1);
94 lower_counter &= ctx->ctr_lower_mask;
95 ctx->ctr_cb[1] = (ctx->ctr_cb[1] & ~(ctx->ctr_lower_mask)) |
96 lower_counter;
97
98 /* wrap around */
99 if (lower_counter == 0) {
100 upper_counter =
101 ntohll(ctx->ctr_cb[0] & ctx->ctr_upper_mask);
102 upper_counter = htonll(upper_counter + 1);
103 upper_counter &= ctx->ctr_upper_mask;
104 ctx->ctr_cb[0] =
105 (ctx->ctr_cb[0] & ~(ctx->ctr_upper_mask)) |
106 upper_counter;
107 }
108
109 /*
110 * XOR encrypted counter block with the current clear block.
111 */
112 xor_block(blockp, lastp);
113
114 if (out == NULL) {
115 if (ctx->ctr_remainder_len > 0) {
116 bcopy(lastp, ctx->ctr_copy_to,
117 ctx->ctr_remainder_len);
118 bcopy(lastp + ctx->ctr_remainder_len, datap,
119 need);
120 }
121 } else {
122 crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
123 &out_data_1_len, &out_data_2, block_size);
124
125 /* copy block to where it belongs */
126 bcopy(lastp, out_data_1, out_data_1_len);
127 if (out_data_2 != NULL) {
128 bcopy(lastp + out_data_1_len, out_data_2,
129 block_size - out_data_1_len);
130 }
131 /* update offset */
132 out->cd_offset += block_size;
133 }
134
135 /* Update pointer to next block of data to be processed. */
136 if (ctx->ctr_remainder_len != 0) {
137 datap += need;
138 ctx->ctr_remainder_len = 0;
139 } else {
140 datap += block_size;
141 }
142
143 remainder = (size_t)&data[length] - (size_t)datap;
144
145 /* Incomplete last block. */
146 if (remainder > 0 && remainder < block_size) {
147 bcopy(datap, ctx->ctr_remainder, remainder);
148 ctx->ctr_remainder_len = remainder;
149 ctx->ctr_copy_to = datap;
150 goto out;
151 }
152 ctx->ctr_copy_to = NULL;
153
154 } while (remainder > 0);
155
156 out:
157 return (CRYPTO_SUCCESS);
158 }
159
160 int
161 ctr_mode_final(ctr_ctx_t *ctx, crypto_data_t *out,
162 int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))
163 {
164 uint8_t *lastp;
165 void *iov_or_mp;
166 offset_t offset;
167 uint8_t *out_data_1;
168 uint8_t *out_data_2;
169 size_t out_data_1_len;
170 uint8_t *p;
171 int i;
172
173 if (out->cd_length < ctx->ctr_remainder_len)
174 return (CRYPTO_DATA_LEN_RANGE);
175
176 encrypt_block(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb,
177 (uint8_t *)ctx->ctr_tmp);
178
179 lastp = (uint8_t *)ctx->ctr_tmp;
180 p = (uint8_t *)ctx->ctr_remainder;
181 for (i = 0; i < ctx->ctr_remainder_len; i++) {
182 p[i] ^= lastp[i];
183 }
184
185 crypto_init_ptrs(out, &iov_or_mp, &offset);
186 crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
187 &out_data_1_len, &out_data_2, ctx->ctr_remainder_len);
188
189 bcopy(p, out_data_1, out_data_1_len);
190 if (out_data_2 != NULL) {
191 bcopy((uint8_t *)p + out_data_1_len,
192 out_data_2, ctx->ctr_remainder_len - out_data_1_len);
193 }
194 out->cd_offset += ctx->ctr_remainder_len;
195 ctx->ctr_remainder_len = 0;
196 return (CRYPTO_SUCCESS);
197 }
198
199 int
200 ctr_init_ctx(ctr_ctx_t *ctr_ctx, ulong_t count, uint8_t *cb,
201 void (*copy_block)(uint8_t *, uint8_t *))
202 {
203 uint64_t upper_mask = 0;
204 uint64_t lower_mask = 0;
205
206 if (count == 0 || count > 128) {
207 return (CRYPTO_MECHANISM_PARAM_INVALID);
208 }
209 /* upper 64 bits of the mask */
210 if (count >= 64) {
211 count -= 64;
212 upper_mask = (count == 64) ? UINT64_MAX : (1ULL << count) - 1;
213 lower_mask = UINT64_MAX;
214 } else {
215 /* now the lower 63 bits */
216 lower_mask = (1ULL << count) - 1;
217 }
218 ctr_ctx->ctr_lower_mask = htonll(lower_mask);
219 ctr_ctx->ctr_upper_mask = htonll(upper_mask);
220
221 copy_block(cb, (uchar_t *)ctr_ctx->ctr_cb);
222 ctr_ctx->ctr_lastp = (uint8_t *)&ctr_ctx->ctr_cb[0];
223 ctr_ctx->ctr_flags |= CTR_MODE;
224 return (CRYPTO_SUCCESS);
225 }
226
227 /* ARGSUSED */
228 void *
229 ctr_alloc_ctx(int kmflag)
230 {
231 ctr_ctx_t *ctr_ctx;
232
233 if ((ctr_ctx = kmem_zalloc(sizeof (ctr_ctx_t), kmflag)) == NULL)
234 return (NULL);
235
236 ctr_ctx->ctr_flags = CTR_MODE;
237 return (ctr_ctx);
238 }