1197ff4c3SKornel Duleba /*- 24d846d26SWarner 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/param.h> 29197ff4c3SKornel Duleba #include <sys/malloc.h> 30197ff4c3SKornel Duleba 31197ff4c3SKornel Duleba #include <opencrypto/cryptodev.h> 329a3444d9SMark Johnston #include <opencrypto/gmac.h> 33197ff4c3SKornel Duleba 34197ff4c3SKornel Duleba #include <crypto/openssl/ossl.h> 359a3444d9SMark Johnston #include <crypto/openssl/ossl_aes_gcm.h> 36197ff4c3SKornel Duleba #include <crypto/openssl/ossl_cipher.h> 37197ff4c3SKornel Duleba 38197ff4c3SKornel Duleba #if defined(__amd64__) || defined(__i386__) 39197ff4c3SKornel Duleba #include <crypto/openssl/ossl_x86.h> 40197ff4c3SKornel Duleba #elif defined (__aarch64__) 41197ff4c3SKornel Duleba #include <crypto/openssl/ossl_aarch64.h> 42197ff4c3SKornel Duleba #endif 43197ff4c3SKornel Duleba 44197ff4c3SKornel Duleba static ossl_cipher_process_t ossl_aes_cbc; 459a3444d9SMark Johnston static ossl_cipher_process_t ossl_aes_gcm; 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 589a3444d9SMark Johnston struct ossl_cipher ossl_cipher_aes_gcm = { 599a3444d9SMark Johnston .type = CRYPTO_AES_NIST_GCM_16, 609a3444d9SMark Johnston .blocksize = 1, 619a3444d9SMark Johnston .ivsize = AES_GCM_IV_LEN, 629a3444d9SMark Johnston 639a3444d9SMark Johnston /* Filled during initialization based on CPU caps. */ 649a3444d9SMark Johnston .set_encrypt_key = NULL, 659a3444d9SMark Johnston .set_decrypt_key = NULL, 669a3444d9SMark Johnston .process = ossl_aes_gcm, 679a3444d9SMark Johnston }; 689a3444d9SMark Johnston 69197ff4c3SKornel Duleba static int 70197ff4c3SKornel Duleba ossl_aes_cbc(struct ossl_session_cipher *s, struct cryptop *crp, 71197ff4c3SKornel Duleba const struct crypto_session_params *csp) 72197ff4c3SKornel Duleba { 73197ff4c3SKornel Duleba struct crypto_buffer_cursor cc_in, cc_out; 74197ff4c3SKornel Duleba unsigned char block[EALG_MAX_BLOCK_LEN]; 75197ff4c3SKornel Duleba unsigned char iv[EALG_MAX_BLOCK_LEN]; 76197ff4c3SKornel Duleba const unsigned char *in, *inseg; 77197ff4c3SKornel Duleba unsigned char *out, *outseg; 78197ff4c3SKornel Duleba size_t plen, seglen, inlen, outlen; 79197ff4c3SKornel Duleba struct ossl_cipher_context key; 80197ff4c3SKornel Duleba struct ossl_cipher *cipher; 81197ff4c3SKornel Duleba int blocklen, error; 82197ff4c3SKornel Duleba bool encrypt; 83197ff4c3SKornel Duleba 84197ff4c3SKornel Duleba cipher = s->cipher; 85197ff4c3SKornel Duleba encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op); 86197ff4c3SKornel Duleba plen = crp->crp_payload_length; 87197ff4c3SKornel Duleba blocklen = cipher->blocksize; 88197ff4c3SKornel Duleba 89197ff4c3SKornel Duleba if (plen % blocklen) 90197ff4c3SKornel Duleba return (EINVAL); 91197ff4c3SKornel Duleba 92197ff4c3SKornel Duleba if (crp->crp_cipher_key != NULL) { 93197ff4c3SKornel Duleba if (encrypt) 94197ff4c3SKornel Duleba error = cipher->set_encrypt_key(crp->crp_cipher_key, 95197ff4c3SKornel Duleba 8 * csp->csp_cipher_klen, &key); 96197ff4c3SKornel Duleba else 97197ff4c3SKornel Duleba error = cipher->set_decrypt_key(crp->crp_cipher_key, 98197ff4c3SKornel Duleba 8 * csp->csp_cipher_klen, &key); 99197ff4c3SKornel Duleba if (error) 100197ff4c3SKornel Duleba return (error); 101197ff4c3SKornel Duleba } else { 102197ff4c3SKornel Duleba if (encrypt) 103197ff4c3SKornel Duleba key = s->enc_ctx; 104197ff4c3SKornel Duleba else 105197ff4c3SKornel Duleba key = s->dec_ctx; 106197ff4c3SKornel Duleba } 107197ff4c3SKornel Duleba 108197ff4c3SKornel Duleba crypto_read_iv(crp, iv); 109197ff4c3SKornel Duleba 110197ff4c3SKornel Duleba /* Derived from ossl_chacha20.c */ 111197ff4c3SKornel Duleba crypto_cursor_init(&cc_in, &crp->crp_buf); 112197ff4c3SKornel Duleba crypto_cursor_advance(&cc_in, crp->crp_payload_start); 113197ff4c3SKornel Duleba inseg = crypto_cursor_segment(&cc_in, &inlen); 114197ff4c3SKornel Duleba if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { 115197ff4c3SKornel Duleba crypto_cursor_init(&cc_out, &crp->crp_obuf); 116197ff4c3SKornel Duleba crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); 117197ff4c3SKornel Duleba } else { 118197ff4c3SKornel Duleba cc_out = cc_in; 119197ff4c3SKornel Duleba } 120197ff4c3SKornel Duleba outseg = crypto_cursor_segment(&cc_out, &outlen); 121197ff4c3SKornel Duleba 122197ff4c3SKornel Duleba while (plen >= blocklen) { 123197ff4c3SKornel Duleba if (inlen < blocklen) { 124197ff4c3SKornel Duleba crypto_cursor_copydata(&cc_in, blocklen, block); 125197ff4c3SKornel Duleba in = block; 126197ff4c3SKornel Duleba inlen = blocklen; 127197ff4c3SKornel Duleba } else { 128197ff4c3SKornel Duleba in = inseg; 129197ff4c3SKornel Duleba } 130197ff4c3SKornel Duleba if (outlen < blocklen) { 131197ff4c3SKornel Duleba out = block; 132197ff4c3SKornel Duleba outlen = blocklen; 133197ff4c3SKornel Duleba } else { 134197ff4c3SKornel Duleba out = outseg; 135197ff4c3SKornel Duleba } 136197ff4c3SKornel Duleba 137197ff4c3SKornel Duleba /* Figure out how many blocks we can encrypt/decrypt at once. */ 138197ff4c3SKornel Duleba seglen = rounddown(MIN(plen, MIN(inlen, outlen)), blocklen); 139197ff4c3SKornel Duleba 140197ff4c3SKornel Duleba AES_CBC_ENCRYPT(in, out, seglen, &key, iv, encrypt); 141197ff4c3SKornel Duleba 142197ff4c3SKornel Duleba if (out == block) { 143197ff4c3SKornel Duleba crypto_cursor_copyback(&cc_out, blocklen, block); 144197ff4c3SKornel Duleba outseg = crypto_cursor_segment(&cc_out, &outlen); 145197ff4c3SKornel Duleba } else { 146197ff4c3SKornel Duleba crypto_cursor_advance(&cc_out, seglen); 147197ff4c3SKornel Duleba outseg += seglen; 148197ff4c3SKornel Duleba outlen -= seglen; 149197ff4c3SKornel Duleba } 150197ff4c3SKornel Duleba if (in == block) { 151197ff4c3SKornel Duleba inseg = crypto_cursor_segment(&cc_in, &inlen); 152197ff4c3SKornel Duleba } else { 153197ff4c3SKornel Duleba crypto_cursor_advance(&cc_in, seglen); 154197ff4c3SKornel Duleba inseg += seglen; 155197ff4c3SKornel Duleba inlen -= seglen; 156197ff4c3SKornel Duleba } 157197ff4c3SKornel Duleba plen -= seglen; 158197ff4c3SKornel Duleba } 159197ff4c3SKornel Duleba 160197ff4c3SKornel Duleba explicit_bzero(block, sizeof(block)); 161197ff4c3SKornel Duleba explicit_bzero(iv, sizeof(iv)); 162197ff4c3SKornel Duleba explicit_bzero(&key, sizeof(key)); 163197ff4c3SKornel Duleba return (0); 164197ff4c3SKornel Duleba } 1659a3444d9SMark Johnston 1669a3444d9SMark Johnston static int 1679a3444d9SMark Johnston ossl_aes_gcm(struct ossl_session_cipher *s, struct cryptop *crp, 1689a3444d9SMark Johnston const struct crypto_session_params *csp) 1699a3444d9SMark Johnston { 170*5c0dac0bSMark Johnston struct ossl_gcm_context ctx; 1719a3444d9SMark Johnston struct crypto_buffer_cursor cc_in, cc_out; 1729a3444d9SMark Johnston unsigned char iv[AES_BLOCK_LEN], tag[AES_BLOCK_LEN]; 1739a3444d9SMark Johnston const unsigned char *inseg; 1749a3444d9SMark Johnston unsigned char *outseg; 1759a3444d9SMark Johnston size_t inlen, outlen, seglen; 1769a3444d9SMark Johnston int error; 1779a3444d9SMark Johnston bool encrypt; 1789a3444d9SMark Johnston 1799a3444d9SMark Johnston encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op); 1809a3444d9SMark Johnston 1819a3444d9SMark Johnston if (crp->crp_cipher_key != NULL) { 1829a3444d9SMark Johnston if (encrypt) 1839a3444d9SMark Johnston error = s->cipher->set_encrypt_key(crp->crp_cipher_key, 184*5c0dac0bSMark Johnston 8 * csp->csp_cipher_klen, 185*5c0dac0bSMark Johnston (struct ossl_cipher_context *)&ctx); 1869a3444d9SMark Johnston else 1879a3444d9SMark Johnston error = s->cipher->set_decrypt_key(crp->crp_cipher_key, 188*5c0dac0bSMark Johnston 8 * csp->csp_cipher_klen, 189*5c0dac0bSMark Johnston (struct ossl_cipher_context *)&ctx); 1909a3444d9SMark Johnston if (error) 1919a3444d9SMark Johnston return (error); 1929a3444d9SMark Johnston } else if (encrypt) { 193*5c0dac0bSMark Johnston memcpy(&ctx, &s->enc_ctx, sizeof(struct ossl_gcm_context)); 1949a3444d9SMark Johnston } else { 195*5c0dac0bSMark Johnston memcpy(&ctx, &s->dec_ctx, sizeof(struct ossl_gcm_context)); 1969a3444d9SMark Johnston } 1979a3444d9SMark Johnston 1989a3444d9SMark Johnston crypto_read_iv(crp, iv); 199*5c0dac0bSMark Johnston ctx.ops->setiv(&ctx, iv, csp->csp_ivlen); 2009a3444d9SMark Johnston 20187826c87SMark Johnston if (crp->crp_aad != NULL) { 202*5c0dac0bSMark Johnston if (ctx.ops->aad(&ctx, crp->crp_aad, crp->crp_aad_length) != 0) 20387826c87SMark Johnston return (EINVAL); 20487826c87SMark Johnston } else { 2059a3444d9SMark Johnston crypto_cursor_init(&cc_in, &crp->crp_buf); 2069a3444d9SMark Johnston crypto_cursor_advance(&cc_in, crp->crp_aad_start); 20787826c87SMark Johnston for (size_t alen = crp->crp_aad_length; alen > 0; 20887826c87SMark Johnston alen -= seglen) { 2099a3444d9SMark Johnston inseg = crypto_cursor_segment(&cc_in, &inlen); 2109a3444d9SMark Johnston seglen = MIN(alen, inlen); 211*5c0dac0bSMark Johnston if (ctx.ops->aad(&ctx, inseg, seglen) != 0) 2129a3444d9SMark Johnston return (EINVAL); 2139a3444d9SMark Johnston crypto_cursor_advance(&cc_in, seglen); 2149a3444d9SMark Johnston } 21587826c87SMark Johnston } 2169a3444d9SMark Johnston 2179a3444d9SMark Johnston crypto_cursor_init(&cc_in, &crp->crp_buf); 2189a3444d9SMark Johnston crypto_cursor_advance(&cc_in, crp->crp_payload_start); 2199a3444d9SMark Johnston if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) { 2209a3444d9SMark Johnston crypto_cursor_init(&cc_out, &crp->crp_obuf); 2219a3444d9SMark Johnston crypto_cursor_advance(&cc_out, crp->crp_payload_output_start); 2229a3444d9SMark Johnston } else { 2239a3444d9SMark Johnston cc_out = cc_in; 2249a3444d9SMark Johnston } 2259a3444d9SMark Johnston 2269a3444d9SMark Johnston for (size_t plen = crp->crp_payload_length; plen > 0; plen -= seglen) { 2279a3444d9SMark Johnston inseg = crypto_cursor_segment(&cc_in, &inlen); 2289a3444d9SMark Johnston outseg = crypto_cursor_segment(&cc_out, &outlen); 2299a3444d9SMark Johnston seglen = MIN(plen, MIN(inlen, outlen)); 2309a3444d9SMark Johnston 2319a3444d9SMark Johnston if (encrypt) { 232*5c0dac0bSMark Johnston if (ctx.ops->encrypt(&ctx, inseg, outseg, seglen) != 0) 2339a3444d9SMark Johnston return (EINVAL); 2349a3444d9SMark Johnston } else { 235*5c0dac0bSMark Johnston if (ctx.ops->decrypt(&ctx, inseg, outseg, seglen) != 0) 2369a3444d9SMark Johnston return (EINVAL); 2379a3444d9SMark Johnston } 2389a3444d9SMark Johnston 2399a3444d9SMark Johnston crypto_cursor_advance(&cc_in, seglen); 2409a3444d9SMark Johnston crypto_cursor_advance(&cc_out, seglen); 2419a3444d9SMark Johnston } 2429a3444d9SMark Johnston 2439a3444d9SMark Johnston error = 0; 2449a3444d9SMark Johnston if (encrypt) { 245*5c0dac0bSMark Johnston ctx.ops->tag(&ctx, tag, GMAC_DIGEST_LEN); 2469a3444d9SMark Johnston crypto_copyback(crp, crp->crp_digest_start, GMAC_DIGEST_LEN, 2479a3444d9SMark Johnston tag); 2489a3444d9SMark Johnston } else { 2499a3444d9SMark Johnston crypto_copydata(crp, crp->crp_digest_start, GMAC_DIGEST_LEN, 2509a3444d9SMark Johnston tag); 251*5c0dac0bSMark Johnston if (ctx.ops->finish(&ctx, tag, GMAC_DIGEST_LEN) != 0) 2529a3444d9SMark Johnston error = EBADMSG; 2539a3444d9SMark Johnston } 2549a3444d9SMark Johnston 2559a3444d9SMark Johnston explicit_bzero(iv, sizeof(iv)); 2569a3444d9SMark Johnston explicit_bzero(tag, sizeof(tag)); 257*5c0dac0bSMark Johnston explicit_bzero(&ctx, sizeof(ctx)); 2589a3444d9SMark Johnston 2599a3444d9SMark Johnston return (error); 2609a3444d9SMark Johnston } 261