1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2020 Netflix, Inc 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer, 11 * without modification. 12 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 13 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 14 * redistribution must be conditioned upon including a substantially 15 * similar Disclaimer requirement for further binary redistribution. 16 * 17 * NO WARRANTY 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 21 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 23 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGES. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/endian.h> 33 #include <sys/malloc.h> 34 #include <sys/time.h> 35 36 #include <opencrypto/cryptodev.h> 37 38 #include <crypto/openssl/ossl.h> 39 #include <crypto/openssl/ossl_chacha.h> 40 #include <crypto/openssl/ossl_cipher.h> 41 #include <crypto/openssl/ossl_poly1305.h> 42 43 static ossl_cipher_process_t ossl_chacha20; 44 45 struct ossl_cipher ossl_cipher_chacha20 = { 46 .type = CRYPTO_CHACHA20, 47 .blocksize = CHACHA_BLK_SIZE, 48 .ivsize = CHACHA_CTR_SIZE, 49 50 .set_encrypt_key = NULL, 51 .set_decrypt_key = NULL, 52 .process = ossl_chacha20 53 }; 54 55 static int 56 ossl_chacha20(struct ossl_session_cipher *s, struct cryptop *crp, 57 const struct crypto_session_params *csp) 58 { 59 _Alignas(8) unsigned int key[CHACHA_KEY_SIZE / 4]; 60 unsigned int counter[CHACHA_CTR_SIZE / 4]; 61 unsigned char block[CHACHA_BLK_SIZE]; 62 struct crypto_buffer_cursor cc_in, cc_out; 63 const unsigned char *in, *inseg, *cipher_key; 64 unsigned char *out, *outseg; 65 size_t resid, todo, inlen, outlen; 66 uint32_t next_counter; 67 u_int i; 68 69 if (crp->crp_cipher_key != NULL) 70 cipher_key = crp->crp_cipher_key; 71 else 72 cipher_key = csp->csp_cipher_key; 73 for (i = 0; i < nitems(key); i++) 74 key[i] = CHACHA_U8TOU32(cipher_key + i * 4); 75 crypto_read_iv(crp, counter); 76 for (i = 0; i < nitems(counter); i++) 77 counter[i] = le32toh(counter[i]); 78 79 resid = crp->crp_payload_length; 80 crypto_cursor_init(&cc_in, &crp->crp_buf); 81 crypto_cursor_advance(&cc_in, crp->crp_payload_start); 82 inseg = crypto_cursor_segment(&cc_in, &inlen); 83 if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { 84 crypto_cursor_init(&cc_out, &crp->crp_obuf); 85 crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); 86 } else 87 cc_out = cc_in; 88 outseg = crypto_cursor_segment(&cc_out, &outlen); 89 while (resid >= CHACHA_BLK_SIZE) { 90 if (inlen < CHACHA_BLK_SIZE) { 91 crypto_cursor_copydata(&cc_in, CHACHA_BLK_SIZE, block); 92 in = block; 93 inlen = CHACHA_BLK_SIZE; 94 } else 95 in = inseg; 96 if (outlen < CHACHA_BLK_SIZE) { 97 out = block; 98 outlen = CHACHA_BLK_SIZE; 99 } else 100 out = outseg; 101 102 /* Figure out how many blocks we can encrypt/decrypt at once. */ 103 todo = rounddown(MIN(resid, MIN(inlen, outlen)), 104 CHACHA_BLK_SIZE); 105 106 #ifdef __LP64__ 107 /* ChaCha20_ctr32() assumes length is <= 4GB. */ 108 todo = (uint32_t)todo; 109 #endif 110 111 /* Truncate if the 32-bit counter would roll over. */ 112 next_counter = counter[0] + todo / CHACHA_BLK_SIZE; 113 if (next_counter < counter[0]) { 114 todo -= next_counter * CHACHA_BLK_SIZE; 115 next_counter = 0; 116 } 117 118 ChaCha20_ctr32(out, in, todo, key, counter); 119 120 counter[0] = next_counter; 121 if (counter[0] == 0) 122 counter[1]++; 123 124 if (out == block) { 125 crypto_cursor_copyback(&cc_out, CHACHA_BLK_SIZE, block); 126 outseg = crypto_cursor_segment(&cc_out, &outlen); 127 } else { 128 crypto_cursor_advance(&cc_out, todo); 129 outseg += todo; 130 outlen -= todo; 131 } 132 if (in == block) { 133 inseg = crypto_cursor_segment(&cc_in, &inlen); 134 } else { 135 crypto_cursor_advance(&cc_in, todo); 136 inseg += todo; 137 inlen -= todo; 138 } 139 resid -= todo; 140 } 141 142 if (resid > 0) { 143 memset(block, 0, sizeof(block)); 144 crypto_cursor_copydata(&cc_in, resid, block); 145 ChaCha20_ctr32(block, block, CHACHA_BLK_SIZE, key, counter); 146 crypto_cursor_copyback(&cc_out, resid, block); 147 } 148 149 explicit_bzero(block, sizeof(block)); 150 explicit_bzero(counter, sizeof(counter)); 151 explicit_bzero(key, sizeof(key)); 152 return (0); 153 } 154 155 int 156 ossl_chacha20_poly1305_encrypt(struct cryptop *crp, 157 const struct crypto_session_params *csp) 158 { 159 _Alignas(8) unsigned int key[CHACHA_KEY_SIZE / 4]; 160 unsigned int counter[CHACHA_CTR_SIZE / 4]; 161 _Alignas(8) unsigned char block[CHACHA_BLK_SIZE]; 162 unsigned char tag[POLY1305_HASH_LEN]; 163 POLY1305 auth_ctx; 164 struct crypto_buffer_cursor cc_in, cc_out; 165 const unsigned char *in, *inseg, *cipher_key; 166 unsigned char *out, *outseg; 167 size_t resid, todo, inlen, outlen; 168 uint32_t next_counter; 169 u_int i; 170 171 if (crp->crp_cipher_key != NULL) 172 cipher_key = crp->crp_cipher_key; 173 else 174 cipher_key = csp->csp_cipher_key; 175 for (i = 0; i < nitems(key); i++) 176 key[i] = CHACHA_U8TOU32(cipher_key + i * 4); 177 178 memset(counter, 0, sizeof(counter)); 179 crypto_read_iv(crp, counter + (CHACHA_CTR_SIZE - csp->csp_ivlen) / 4); 180 for (i = 1; i < nitems(counter); i++) 181 counter[i] = le32toh(counter[i]); 182 183 /* Block 0 is used to generate the poly1305 key. */ 184 counter[0] = 0; 185 186 memset(block, 0, sizeof(block)); 187 ChaCha20_ctr32(block, block, sizeof(block), key, counter); 188 Poly1305_Init(&auth_ctx, block); 189 190 /* MAC the AAD. */ 191 if (crp->crp_aad != NULL) 192 Poly1305_Update(&auth_ctx, crp->crp_aad, crp->crp_aad_length); 193 else 194 crypto_apply(crp, crp->crp_aad_start, crp->crp_aad_length, 195 ossl_poly1305_update, &auth_ctx); 196 if (crp->crp_aad_length % 16 != 0) { 197 /* padding1 */ 198 memset(block, 0, 16); 199 Poly1305_Update(&auth_ctx, block, 200 16 - crp->crp_aad_length % 16); 201 } 202 203 /* Encryption starts with block 1. */ 204 counter[0] = 1; 205 206 /* Do encryption with MAC */ 207 resid = crp->crp_payload_length; 208 crypto_cursor_init(&cc_in, &crp->crp_buf); 209 crypto_cursor_advance(&cc_in, crp->crp_payload_start); 210 inseg = crypto_cursor_segment(&cc_in, &inlen); 211 if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { 212 crypto_cursor_init(&cc_out, &crp->crp_obuf); 213 crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); 214 } else 215 cc_out = cc_in; 216 outseg = crypto_cursor_segment(&cc_out, &outlen); 217 while (resid >= CHACHA_BLK_SIZE) { 218 if (inlen < CHACHA_BLK_SIZE) { 219 crypto_cursor_copydata(&cc_in, CHACHA_BLK_SIZE, block); 220 in = block; 221 inlen = CHACHA_BLK_SIZE; 222 } else 223 in = inseg; 224 if (outlen < CHACHA_BLK_SIZE) { 225 out = block; 226 outlen = CHACHA_BLK_SIZE; 227 } else 228 out = outseg; 229 230 /* Figure out how many blocks we can encrypt/decrypt at once. */ 231 todo = rounddown(MIN(resid, MIN(inlen, outlen)), 232 CHACHA_BLK_SIZE); 233 234 #ifdef __LP64__ 235 /* ChaCha20_ctr32() assumes length is <= 4GB. */ 236 todo = (uint32_t)todo; 237 #endif 238 239 /* Truncate if the 32-bit counter would roll over. */ 240 next_counter = counter[0] + todo / CHACHA_BLK_SIZE; 241 if (csp->csp_ivlen == 8 && next_counter < counter[0]) { 242 todo -= next_counter * CHACHA_BLK_SIZE; 243 next_counter = 0; 244 } 245 246 ChaCha20_ctr32(out, in, todo, key, counter); 247 Poly1305_Update(&auth_ctx, out, todo); 248 249 counter[0] = next_counter; 250 if (csp->csp_ivlen == 8 && counter[0] == 0) 251 counter[1]++; 252 253 if (out == block) { 254 crypto_cursor_copyback(&cc_out, CHACHA_BLK_SIZE, block); 255 outseg = crypto_cursor_segment(&cc_out, &outlen); 256 } else { 257 crypto_cursor_advance(&cc_out, todo); 258 outseg += todo; 259 outlen -= todo; 260 } 261 if (in == block) { 262 inseg = crypto_cursor_segment(&cc_in, &inlen); 263 } else { 264 crypto_cursor_advance(&cc_in, todo); 265 inseg += todo; 266 inlen -= todo; 267 } 268 resid -= todo; 269 } 270 271 if (resid > 0) { 272 memset(block, 0, sizeof(block)); 273 crypto_cursor_copydata(&cc_in, resid, block); 274 ChaCha20_ctr32(block, block, CHACHA_BLK_SIZE, key, counter); 275 crypto_cursor_copyback(&cc_out, resid, block); 276 277 /* padding2 */ 278 todo = roundup2(resid, 16); 279 memset(block + resid, 0, todo - resid); 280 Poly1305_Update(&auth_ctx, block, todo); 281 } 282 283 /* lengths */ 284 le64enc(block, crp->crp_aad_length); 285 le64enc(block + 8, crp->crp_payload_length); 286 Poly1305_Update(&auth_ctx, block, sizeof(uint64_t) * 2); 287 288 Poly1305_Final(&auth_ctx, tag); 289 crypto_copyback(crp, crp->crp_digest_start, csp->csp_auth_mlen == 0 ? 290 POLY1305_HASH_LEN : csp->csp_auth_mlen, tag); 291 292 explicit_bzero(&auth_ctx, sizeof(auth_ctx)); 293 explicit_bzero(tag, sizeof(tag)); 294 explicit_bzero(block, sizeof(block)); 295 explicit_bzero(counter, sizeof(counter)); 296 explicit_bzero(key, sizeof(key)); 297 return (0); 298 } 299 300 301 int 302 ossl_chacha20_poly1305_decrypt(struct cryptop *crp, 303 const struct crypto_session_params *csp) 304 { 305 _Alignas(8) unsigned int key[CHACHA_KEY_SIZE / 4]; 306 unsigned int counter[CHACHA_CTR_SIZE / 4]; 307 _Alignas(8) unsigned char block[CHACHA_BLK_SIZE]; 308 unsigned char tag[POLY1305_HASH_LEN], tag2[POLY1305_HASH_LEN]; 309 struct poly1305_context auth_ctx; 310 struct crypto_buffer_cursor cc_in, cc_out; 311 const unsigned char *in, *inseg, *cipher_key; 312 unsigned char *out, *outseg; 313 size_t resid, todo, inlen, outlen; 314 uint32_t next_counter; 315 int error; 316 u_int i, mlen; 317 318 if (crp->crp_cipher_key != NULL) 319 cipher_key = crp->crp_cipher_key; 320 else 321 cipher_key = csp->csp_cipher_key; 322 for (i = 0; i < nitems(key); i++) 323 key[i] = CHACHA_U8TOU32(cipher_key + i * 4); 324 325 memset(counter, 0, sizeof(counter)); 326 crypto_read_iv(crp, counter + (CHACHA_CTR_SIZE - csp->csp_ivlen) / 4); 327 for (i = 1; i < nitems(counter); i++) 328 counter[i] = le32toh(counter[i]); 329 330 /* Block 0 is used to generate the poly1305 key. */ 331 counter[0] = 0; 332 333 memset(block, 0, sizeof(block)); 334 ChaCha20_ctr32(block, block, sizeof(block), key, counter); 335 Poly1305_Init(&auth_ctx, block); 336 337 /* MAC the AAD. */ 338 if (crp->crp_aad != NULL) 339 Poly1305_Update(&auth_ctx, crp->crp_aad, crp->crp_aad_length); 340 else 341 crypto_apply(crp, crp->crp_aad_start, crp->crp_aad_length, 342 ossl_poly1305_update, &auth_ctx); 343 if (crp->crp_aad_length % 16 != 0) { 344 /* padding1 */ 345 memset(block, 0, 16); 346 Poly1305_Update(&auth_ctx, block, 347 16 - crp->crp_aad_length % 16); 348 } 349 350 /* Mac the ciphertext. */ 351 crypto_apply(crp, crp->crp_payload_start, crp->crp_payload_length, 352 ossl_poly1305_update, &auth_ctx); 353 if (crp->crp_payload_length % 16 != 0) { 354 /* padding2 */ 355 memset(block, 0, 16); 356 Poly1305_Update(&auth_ctx, block, 357 16 - crp->crp_payload_length % 16); 358 } 359 360 /* lengths */ 361 le64enc(block, crp->crp_aad_length); 362 le64enc(block + 8, crp->crp_payload_length); 363 Poly1305_Update(&auth_ctx, block, sizeof(uint64_t) * 2); 364 365 Poly1305_Final(&auth_ctx, tag); 366 mlen = csp->csp_auth_mlen == 0 ? POLY1305_HASH_LEN : csp->csp_auth_mlen; 367 crypto_copydata(crp, crp->crp_digest_start, mlen, tag2); 368 if (timingsafe_bcmp(tag, tag2, mlen) != 0) { 369 error = EBADMSG; 370 goto out; 371 } 372 373 /* Decryption starts with block 1. */ 374 counter[0] = 1; 375 376 resid = crp->crp_payload_length; 377 crypto_cursor_init(&cc_in, &crp->crp_buf); 378 crypto_cursor_advance(&cc_in, crp->crp_payload_start); 379 inseg = crypto_cursor_segment(&cc_in, &inlen); 380 if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { 381 crypto_cursor_init(&cc_out, &crp->crp_obuf); 382 crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); 383 } else 384 cc_out = cc_in; 385 outseg = crypto_cursor_segment(&cc_out, &outlen); 386 while (resid >= CHACHA_BLK_SIZE) { 387 if (inlen < CHACHA_BLK_SIZE) { 388 crypto_cursor_copydata(&cc_in, CHACHA_BLK_SIZE, block); 389 in = block; 390 inlen = CHACHA_BLK_SIZE; 391 } else 392 in = inseg; 393 if (outlen < CHACHA_BLK_SIZE) { 394 out = block; 395 outlen = CHACHA_BLK_SIZE; 396 } else 397 out = outseg; 398 399 /* Figure out how many blocks we can encrypt/decrypt at once. */ 400 todo = rounddown(MIN(resid, MIN(inlen, outlen)), 401 CHACHA_BLK_SIZE); 402 403 #ifdef __LP64__ 404 /* ChaCha20_ctr32() assumes length is <= 4GB. */ 405 todo = (uint32_t)todo; 406 #endif 407 408 /* Truncate if the 32-bit counter would roll over. */ 409 next_counter = counter[0] + todo / CHACHA_BLK_SIZE; 410 if (csp->csp_ivlen == 8 && next_counter < counter[0]) { 411 todo -= next_counter * CHACHA_BLK_SIZE; 412 next_counter = 0; 413 } 414 415 ChaCha20_ctr32(out, in, todo, key, counter); 416 417 counter[0] = next_counter; 418 if (csp->csp_ivlen == 8 && counter[0] == 0) 419 counter[1]++; 420 421 if (out == block) { 422 crypto_cursor_copyback(&cc_out, CHACHA_BLK_SIZE, block); 423 outseg = crypto_cursor_segment(&cc_out, &outlen); 424 } else { 425 crypto_cursor_advance(&cc_out, todo); 426 outseg += todo; 427 outlen -= todo; 428 } 429 if (in == block) { 430 inseg = crypto_cursor_segment(&cc_in, &inlen); 431 } else { 432 crypto_cursor_advance(&cc_in, todo); 433 inseg += todo; 434 inlen -= todo; 435 } 436 resid -= todo; 437 } 438 439 if (resid > 0) { 440 memset(block, 0, sizeof(block)); 441 crypto_cursor_copydata(&cc_in, resid, block); 442 ChaCha20_ctr32(block, block, CHACHA_BLK_SIZE, key, counter); 443 crypto_cursor_copyback(&cc_out, resid, block); 444 } 445 446 error = 0; 447 out: 448 explicit_bzero(&auth_ctx, sizeof(auth_ctx)); 449 explicit_bzero(tag, sizeof(tag)); 450 explicit_bzero(block, sizeof(block)); 451 explicit_bzero(counter, sizeof(counter)); 452 explicit_bzero(key, sizeof(key)); 453 return (error); 454 } 455