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 * Copyright 2019 Joyent, Inc.
26 */
27
28 #ifndef _KERNEL
29 #include <strings.h>
30 #include <limits.h>
31 #include <assert.h>
32 #include <security/cryptoki.h>
33 #endif
34
35 #include <sys/debug.h>
36 #include <sys/types.h>
37 #include <modes/modes.h>
38 #include <sys/crypto/common.h>
39 #include <sys/crypto/impl.h>
40 #include <sys/byteorder.h>
41
42 /*
43 * CTR (counter mode) is a stream cipher. That is, it generates a
44 * pseudo-random keystream that is used to XOR with the input to
45 * encrypt or decrypt. The pseudo-random keystream is generated by
46 * concatenating a nonce (supplied during initialzation) and with a
47 * counter (initialized to zero) to form an input block to the cipher
48 * mechanism. The resulting output of the cipher is used as a chunk
49 * of the pseudo-random keystream. Once all of the bytes of the
50 * keystream block have been used, the counter is incremented and
51 * the process repeats.
52 *
53 * Since this is a stream cipher, we do not accumulate input cipher
54 * text like we do for block modes. Instead we use ctr_ctx_t->ctr_offset
55 * to track the amount of bytes used in the current keystream block.
56 */
57
58 static void
ctr_new_keyblock(ctr_ctx_t * ctx,int (* cipher)(const void * ks,const uint8_t * pt,uint8_t * ct))59 ctr_new_keyblock(ctr_ctx_t *ctx,
60 int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct))
61 {
62 uint64_t lower_counter, upper_counter;
63
64 /* increment the counter */
65 lower_counter = ntohll(ctx->ctr_cb[1] & ctx->ctr_lower_mask);
66 lower_counter = htonll(lower_counter + 1);
67 lower_counter &= ctx->ctr_lower_mask;
68 ctx->ctr_cb[1] = (ctx->ctr_cb[1] & ~(ctx->ctr_lower_mask)) |
69 lower_counter;
70
71 /* wrap around */
72 if (lower_counter == 0) {
73 upper_counter = ntohll(ctx->ctr_cb[0] & ctx->ctr_upper_mask);
74 upper_counter = htonll(upper_counter + 1);
75 upper_counter &= ctx->ctr_upper_mask;
76 ctx->ctr_cb[0] = (ctx->ctr_cb[0] & ~(ctx->ctr_upper_mask)) |
77 upper_counter;
78 }
79
80 /* generate the new keyblock */
81 cipher(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb,
82 (uint8_t *)ctx->ctr_keystream);
83 ctx->ctr_offset = 0;
84 }
85
86 /*
87 * XOR the input with the keystream and write the result to out.
88 * This requires that the amount of data in 'in' is >= outlen
89 * (ctr_mode_contiguous_blocks() guarantees this for us before we are
90 * called). As CTR mode is a stream cipher, we cannot use a cipher's
91 * xxx_xor_block function (e.g. aes_xor_block()) as we must handle
92 * arbitrary lengths of input and should not buffer/accumulate partial blocks
93 * between calls.
94 */
95 static void
ctr_xor(ctr_ctx_t * ctx,const uint8_t * in,uint8_t * out,size_t outlen,size_t block_size,int (* cipher)(const void * ks,const uint8_t * pt,uint8_t * ct))96 ctr_xor(ctr_ctx_t *ctx, const uint8_t *in, uint8_t *out, size_t outlen,
97 size_t block_size,
98 int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct))
99 {
100 const uint8_t *keyp;
101 size_t keyamt;
102
103 while (outlen > 0) {
104 /*
105 * This occurs once we've consumed all the bytes in the
106 * current block of the keystream. ctr_init_ctx() creates
107 * the initial block of the keystream, so we always start
108 * with a full block of key data.
109 */
110 if (ctx->ctr_offset == block_size) {
111 ctr_new_keyblock(ctx, cipher);
112 }
113
114 keyp = (uint8_t *)ctx->ctr_keystream + ctx->ctr_offset;
115 keyamt = block_size - ctx->ctr_offset;
116
117 /*
118 * xor a byte at a time (while we have data and output
119 * space) and try to get in, out, and keyp 32-bit aligned.
120 * If in, out, and keyp all do become 32-bit aligned,
121 * we switch to xor-ing 32-bits at a time until we run out
122 * of 32-bit chunks, then switch back to xor-ing a byte at
123 * a time for any remainder.
124 */
125 while (keyamt > 0 && outlen > 0 &&
126 !IS_P2ALIGNED(in, sizeof (uint32_t)) &&
127 !IS_P2ALIGNED(out, sizeof (uint32_t)) &&
128 !IS_P2ALIGNED(keyp, sizeof (uint32_t))) {
129 *out++ = *in++ ^ *keyp++;
130 keyamt--;
131 outlen--;
132 }
133
134 if (keyamt > 3 && outlen > 3 &&
135 IS_P2ALIGNED(in, sizeof (uint32_t)) &&
136 IS_P2ALIGNED(out, sizeof (uint32_t)) &&
137 IS_P2ALIGNED(keyp, sizeof (uint32_t))) {
138 const uint32_t *key32 = (const uint32_t *)keyp;
139 const uint32_t *in32 = (const uint32_t *)in;
140 uint32_t *out32 = (uint32_t *)out;
141
142 do {
143 *out32++ = *in32++ ^ *key32++;
144 keyamt -= sizeof (uint32_t);
145 outlen -= sizeof (uint32_t);
146 } while (keyamt > 3 && outlen > 3);
147
148 keyp = (const uint8_t *)key32;
149 in = (const uint8_t *)in32;
150 out = (uint8_t *)out32;
151 }
152
153 while (keyamt > 0 && outlen > 0) {
154 *out++ = *in++ ^ *keyp++;
155 keyamt--;
156 outlen--;
157 }
158
159 ctx->ctr_offset = block_size - keyamt;
160 }
161 }
162
163 /*
164 * Encrypt and decrypt multiple blocks of data in counter mode.
165 */
166 int
ctr_mode_contiguous_blocks(ctr_ctx_t * ctx,char * in,size_t in_length,crypto_data_t * out,size_t block_size,int (* cipher)(const void * ks,const uint8_t * pt,uint8_t * ct))167 ctr_mode_contiguous_blocks(ctr_ctx_t *ctx, char *in, size_t in_length,
168 crypto_data_t *out, size_t block_size,
169 int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct))
170 {
171 size_t in_remainder = in_length;
172 uint8_t *inp = (uint8_t *)in;
173 void *iov_or_mp;
174 offset_t offset;
175 uint8_t *out_data;
176 uint8_t *out_data_remainder;
177 size_t out_data_len;
178
179 if (block_size > sizeof (ctx->ctr_keystream))
180 return (CRYPTO_ARGUMENTS_BAD);
181
182 if (out == NULL)
183 return (CRYPTO_ARGUMENTS_BAD);
184
185 /* Make sure 'out->cd_offset + in_length' doesn't overflow. */
186 if (out->cd_offset < 0)
187 return (CRYPTO_DATA_LEN_RANGE);
188 if (SIZE_MAX - in_length < (size_t)out->cd_offset)
189 return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
190
191 /*
192 * This check guarantees 'out' contains sufficient space for
193 * the resulting output.
194 */
195 if (out->cd_offset + in_length > out->cd_length)
196 return (CRYPTO_BUFFER_TOO_SMALL);
197
198 crypto_init_ptrs(out, &iov_or_mp, &offset);
199
200 /* Now XOR the output with the keystream */
201 while (in_remainder > 0) {
202 /*
203 * If out is a uio_t or an mblk_t, in_remainder might be
204 * larger than an individual iovec_t or mblk_t in out.
205 * crypto_get_ptrs uses the value of offset to set the
206 * the value of out_data to the correct address for writing
207 * and sets out_data_len to reflect the largest amount of data
208 * (up to in_remainder) that can be written to out_data. It
209 * also increments offset by out_data_len. out_data_remainder
210 * is set to the start of the next segment for writing, however
211 * it is not used here since the updated value of offset
212 * will be used in the next loop iteration to locate the
213 * next mblk_t/iovec_t. Since the sum of the size of all data
214 * buffers in 'out' (out->cd_length) was checked immediately
215 * prior to starting the loop, we should always terminate
216 * the loop.
217 */
218 crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data,
219 &out_data_len, &out_data_remainder, in_remainder);
220
221 /*
222 * crypto_get_ptrs() should guarantee these, but act as a
223 * safeguard in case the behavior ever changes.
224 */
225 ASSERT3U(out_data_len, <=, in_remainder);
226 ASSERT3U(out_data_len, >, 0);
227
228 ctr_xor(ctx, inp, out_data, out_data_len, block_size, cipher);
229
230 inp += out_data_len;
231 in_remainder -= out_data_len;
232 }
233
234 out->cd_offset += in_length;
235
236 return (CRYPTO_SUCCESS);
237 }
238
239 int
ctr_init_ctx(ctr_ctx_t * ctr_ctx,ulong_t count,uint8_t * cb,int (* cipher)(const void * ks,const uint8_t * pt,uint8_t * ct),void (* copy_block)(uint8_t *,uint8_t *))240 ctr_init_ctx(ctr_ctx_t *ctr_ctx, ulong_t count, uint8_t *cb,
241 int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct),
242 void (*copy_block)(uint8_t *, uint8_t *))
243 {
244 uint64_t upper_mask = 0;
245 uint64_t lower_mask = 0;
246
247 if (count == 0 || count > 128) {
248 return (CRYPTO_MECHANISM_PARAM_INVALID);
249 }
250 /* upper 64 bits of the mask */
251 if (count >= 64) {
252 count -= 64;
253 upper_mask = (count == 64) ? UINT64_MAX : (1ULL << count) - 1;
254 lower_mask = UINT64_MAX;
255 } else {
256 /* now the lower 63 bits */
257 lower_mask = (1ULL << count) - 1;
258 }
259 ctr_ctx->ctr_lower_mask = htonll(lower_mask);
260 ctr_ctx->ctr_upper_mask = htonll(upper_mask);
261
262 copy_block(cb, (uchar_t *)ctr_ctx->ctr_cb);
263 ctr_ctx->ctr_lastp = (uint8_t *)&ctr_ctx->ctr_cb[0];
264
265 /* Generate the first block of the keystream */
266 cipher(ctr_ctx->ctr_keysched, (uint8_t *)ctr_ctx->ctr_cb,
267 (uint8_t *)ctr_ctx->ctr_keystream);
268
269 ctr_ctx->ctr_flags |= CTR_MODE;
270 return (CRYPTO_SUCCESS);
271 }
272
273 /* ARGSUSED */
274 void *
ctr_alloc_ctx(int kmflag)275 ctr_alloc_ctx(int kmflag)
276 {
277 ctr_ctx_t *ctr_ctx;
278
279 #ifdef _KERNEL
280 if ((ctr_ctx = kmem_zalloc(sizeof (ctr_ctx_t), kmflag)) == NULL)
281 #else
282 if ((ctr_ctx = calloc(1, sizeof (ctr_ctx_t))) == NULL)
283 #endif
284 return (NULL);
285
286 ctr_ctx->ctr_flags = CTR_MODE;
287 return (ctr_ctx);
288 }
289