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 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 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 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 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 * 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