1197ff4c3SKornel Duleba /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3197ff4c3SKornel Duleba * 4197ff4c3SKornel Duleba * Copyright (c) 2021 Stormshield. 5197ff4c3SKornel Duleba * Copyright (c) 2021 Semihalf. 6197ff4c3SKornel Duleba * 7197ff4c3SKornel Duleba * Redistribution and use in source and binary forms, with or without 8197ff4c3SKornel Duleba * modification, are permitted provided that the following conditions 9197ff4c3SKornel Duleba * are met: 10197ff4c3SKornel Duleba * 1. Redistributions of source code must retain the above copyright 11197ff4c3SKornel Duleba * notice, this list of conditions and the following disclaimer. 12197ff4c3SKornel Duleba * 2. Redistributions in binary form must reproduce the above copyright 13197ff4c3SKornel Duleba * notice, this list of conditions and the following disclaimer in the 14197ff4c3SKornel Duleba * documentation and/or other materials provided with the distribution. 15197ff4c3SKornel Duleba * 16197ff4c3SKornel Duleba * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17197ff4c3SKornel Duleba * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18197ff4c3SKornel Duleba * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19197ff4c3SKornel Duleba * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20197ff4c3SKornel Duleba * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21197ff4c3SKornel Duleba * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22197ff4c3SKornel Duleba * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23197ff4c3SKornel Duleba * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24197ff4c3SKornel Duleba * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25197ff4c3SKornel Duleba * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26197ff4c3SKornel Duleba */ 27197ff4c3SKornel Duleba 28197ff4c3SKornel Duleba #include <sys/cdefs.h> 29197ff4c3SKornel Duleba __FBSDID("$FreeBSD$"); 30197ff4c3SKornel Duleba 31197ff4c3SKornel Duleba #include <sys/param.h> 32197ff4c3SKornel Duleba #include <sys/malloc.h> 33197ff4c3SKornel Duleba 34197ff4c3SKornel Duleba #include <opencrypto/cryptodev.h> 35197ff4c3SKornel Duleba 36197ff4c3SKornel Duleba #include <crypto/openssl/ossl.h> 37197ff4c3SKornel Duleba #include <crypto/openssl/ossl_cipher.h> 38197ff4c3SKornel Duleba 39197ff4c3SKornel Duleba #if defined(__amd64__) || defined(__i386__) 40197ff4c3SKornel Duleba #include <crypto/openssl/ossl_x86.h> 41197ff4c3SKornel Duleba #elif defined (__aarch64__) 42197ff4c3SKornel Duleba #include <crypto/openssl/ossl_aarch64.h> 43197ff4c3SKornel Duleba #endif 44197ff4c3SKornel Duleba 45197ff4c3SKornel Duleba static ossl_cipher_process_t ossl_aes_cbc; 46197ff4c3SKornel Duleba 47197ff4c3SKornel Duleba struct ossl_cipher ossl_cipher_aes_cbc = { 48197ff4c3SKornel Duleba .type = CRYPTO_AES_CBC, 49197ff4c3SKornel Duleba .blocksize = AES_BLOCK_LEN, 50197ff4c3SKornel Duleba .ivsize = AES_BLOCK_LEN, 51197ff4c3SKornel Duleba 52197ff4c3SKornel Duleba /* Filled during initialization based on CPU caps. */ 53197ff4c3SKornel Duleba .set_encrypt_key = NULL, 54197ff4c3SKornel Duleba .set_decrypt_key = NULL, 55197ff4c3SKornel Duleba .process = ossl_aes_cbc 56197ff4c3SKornel Duleba }; 57197ff4c3SKornel Duleba 58197ff4c3SKornel Duleba static int 59197ff4c3SKornel Duleba ossl_aes_cbc(struct ossl_session_cipher *s, struct cryptop *crp, 60197ff4c3SKornel Duleba const struct crypto_session_params *csp) 61197ff4c3SKornel Duleba { 62197ff4c3SKornel Duleba struct crypto_buffer_cursor cc_in, cc_out; 63197ff4c3SKornel Duleba unsigned char block[EALG_MAX_BLOCK_LEN]; 64197ff4c3SKornel Duleba unsigned char iv[EALG_MAX_BLOCK_LEN]; 65197ff4c3SKornel Duleba const unsigned char *in, *inseg; 66197ff4c3SKornel Duleba unsigned char *out, *outseg; 67197ff4c3SKornel Duleba size_t plen, seglen, inlen, outlen; 68197ff4c3SKornel Duleba struct ossl_cipher_context key; 69197ff4c3SKornel Duleba struct ossl_cipher *cipher; 70197ff4c3SKornel Duleba int blocklen, error; 71197ff4c3SKornel Duleba bool encrypt; 72197ff4c3SKornel Duleba 73197ff4c3SKornel Duleba cipher = s->cipher; 74197ff4c3SKornel Duleba encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op); 75197ff4c3SKornel Duleba plen = crp->crp_payload_length; 76197ff4c3SKornel Duleba blocklen = cipher->blocksize; 77197ff4c3SKornel Duleba 78197ff4c3SKornel Duleba if (plen % blocklen) 79197ff4c3SKornel Duleba return (EINVAL); 80197ff4c3SKornel Duleba 81197ff4c3SKornel Duleba if (crp->crp_cipher_key != NULL) { 82197ff4c3SKornel Duleba if (encrypt) 83197ff4c3SKornel Duleba error = cipher->set_encrypt_key(crp->crp_cipher_key, 84197ff4c3SKornel Duleba 8 * csp->csp_cipher_klen, &key); 85197ff4c3SKornel Duleba else 86197ff4c3SKornel Duleba error = cipher->set_decrypt_key(crp->crp_cipher_key, 87197ff4c3SKornel Duleba 8 * csp->csp_cipher_klen, &key); 88197ff4c3SKornel Duleba if (error) 89197ff4c3SKornel Duleba return (error); 90197ff4c3SKornel Duleba } else { 91197ff4c3SKornel Duleba if (encrypt) 92197ff4c3SKornel Duleba key = s->enc_ctx; 93197ff4c3SKornel Duleba else 94197ff4c3SKornel Duleba key = s->dec_ctx; 95197ff4c3SKornel Duleba } 96197ff4c3SKornel Duleba 97197ff4c3SKornel Duleba crypto_read_iv(crp, iv); 98197ff4c3SKornel Duleba 99197ff4c3SKornel Duleba /* Derived from ossl_chacha20.c */ 100197ff4c3SKornel Duleba crypto_cursor_init(&cc_in, &crp->crp_buf); 101197ff4c3SKornel Duleba crypto_cursor_advance(&cc_in, crp->crp_payload_start); 102197ff4c3SKornel Duleba inseg = crypto_cursor_segment(&cc_in, &inlen); 103197ff4c3SKornel Duleba if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { 104197ff4c3SKornel Duleba crypto_cursor_init(&cc_out, &crp->crp_obuf); 105197ff4c3SKornel Duleba crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); 106197ff4c3SKornel Duleba } else { 107197ff4c3SKornel Duleba cc_out = cc_in; 108197ff4c3SKornel Duleba } 109197ff4c3SKornel Duleba outseg = crypto_cursor_segment(&cc_out, &outlen); 110197ff4c3SKornel Duleba 111197ff4c3SKornel Duleba while (plen >= blocklen) { 112197ff4c3SKornel Duleba if (inlen < blocklen) { 113197ff4c3SKornel Duleba crypto_cursor_copydata(&cc_in, blocklen, block); 114197ff4c3SKornel Duleba in = block; 115197ff4c3SKornel Duleba inlen = blocklen; 116197ff4c3SKornel Duleba } else { 117197ff4c3SKornel Duleba in = inseg; 118197ff4c3SKornel Duleba } 119197ff4c3SKornel Duleba if (outlen < blocklen) { 120197ff4c3SKornel Duleba out = block; 121197ff4c3SKornel Duleba outlen = blocklen; 122197ff4c3SKornel Duleba } else { 123197ff4c3SKornel Duleba out = outseg; 124197ff4c3SKornel Duleba } 125197ff4c3SKornel Duleba 126197ff4c3SKornel Duleba /* Figure out how many blocks we can encrypt/decrypt at once. */ 127197ff4c3SKornel Duleba seglen = rounddown(MIN(plen, MIN(inlen, outlen)), blocklen); 128197ff4c3SKornel Duleba 129197ff4c3SKornel Duleba AES_CBC_ENCRYPT(in, out, seglen, &key, iv, encrypt); 130197ff4c3SKornel Duleba 131197ff4c3SKornel Duleba if (out == block) { 132197ff4c3SKornel Duleba crypto_cursor_copyback(&cc_out, blocklen, block); 133197ff4c3SKornel Duleba outseg = crypto_cursor_segment(&cc_out, &outlen); 134197ff4c3SKornel Duleba } else { 135197ff4c3SKornel Duleba crypto_cursor_advance(&cc_out, seglen); 136197ff4c3SKornel Duleba outseg += seglen; 137197ff4c3SKornel Duleba outlen -= seglen; 138197ff4c3SKornel Duleba } 139197ff4c3SKornel Duleba if (in == block) { 140197ff4c3SKornel Duleba inseg = crypto_cursor_segment(&cc_in, &inlen); 141197ff4c3SKornel Duleba } else { 142197ff4c3SKornel Duleba crypto_cursor_advance(&cc_in, seglen); 143197ff4c3SKornel Duleba inseg += seglen; 144197ff4c3SKornel Duleba inlen -= seglen; 145197ff4c3SKornel Duleba } 146197ff4c3SKornel Duleba plen -= seglen; 147197ff4c3SKornel Duleba } 148197ff4c3SKornel Duleba 149197ff4c3SKornel Duleba explicit_bzero(block, sizeof(block)); 150197ff4c3SKornel Duleba explicit_bzero(iv, sizeof(iv)); 151197ff4c3SKornel Duleba explicit_bzero(&key, sizeof(key)); 152197ff4c3SKornel Duleba return (0); 153197ff4c3SKornel Duleba } 154