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>
4244f8e1e8SMark Johnston #elif defined (__arm__)
4344f8e1e8SMark Johnston #include <crypto/openssl/ossl_arm.h>
44*3465f14dSShawn Anastasio #elif defined (__powerpc64__)
45*3465f14dSShawn Anastasio #include <crypto/openssl/ossl_ppc.h>
46*3465f14dSShawn Anastasio #else
47*3465f14dSShawn Anastasio #error "Unsupported architecture!"
48197ff4c3SKornel Duleba #endif
49197ff4c3SKornel Duleba
50197ff4c3SKornel Duleba static ossl_cipher_process_t ossl_aes_cbc;
519a3444d9SMark Johnston static ossl_cipher_process_t ossl_aes_gcm;
52197ff4c3SKornel Duleba
53197ff4c3SKornel Duleba struct ossl_cipher ossl_cipher_aes_cbc = {
54197ff4c3SKornel Duleba .type = CRYPTO_AES_CBC,
55197ff4c3SKornel Duleba .blocksize = AES_BLOCK_LEN,
56197ff4c3SKornel Duleba .ivsize = AES_BLOCK_LEN,
57197ff4c3SKornel Duleba
58197ff4c3SKornel Duleba /* Filled during initialization based on CPU caps. */
59197ff4c3SKornel Duleba .set_encrypt_key = NULL,
60197ff4c3SKornel Duleba .set_decrypt_key = NULL,
61197ff4c3SKornel Duleba .process = ossl_aes_cbc
62197ff4c3SKornel Duleba };
63197ff4c3SKornel Duleba
649a3444d9SMark Johnston struct ossl_cipher ossl_cipher_aes_gcm = {
659a3444d9SMark Johnston .type = CRYPTO_AES_NIST_GCM_16,
669a3444d9SMark Johnston .blocksize = 1,
679a3444d9SMark Johnston .ivsize = AES_GCM_IV_LEN,
689a3444d9SMark Johnston
699a3444d9SMark Johnston /* Filled during initialization based on CPU caps. */
709a3444d9SMark Johnston .set_encrypt_key = NULL,
719a3444d9SMark Johnston .set_decrypt_key = NULL,
729a3444d9SMark Johnston .process = ossl_aes_gcm,
739a3444d9SMark Johnston };
749a3444d9SMark Johnston
75197ff4c3SKornel Duleba static int
ossl_aes_cbc(struct ossl_session_cipher * s,struct cryptop * crp,const struct crypto_session_params * csp)76197ff4c3SKornel Duleba ossl_aes_cbc(struct ossl_session_cipher *s, struct cryptop *crp,
77197ff4c3SKornel Duleba const struct crypto_session_params *csp)
78197ff4c3SKornel Duleba {
79197ff4c3SKornel Duleba struct crypto_buffer_cursor cc_in, cc_out;
80197ff4c3SKornel Duleba unsigned char block[EALG_MAX_BLOCK_LEN];
81197ff4c3SKornel Duleba unsigned char iv[EALG_MAX_BLOCK_LEN];
82197ff4c3SKornel Duleba const unsigned char *in, *inseg;
83197ff4c3SKornel Duleba unsigned char *out, *outseg;
84197ff4c3SKornel Duleba size_t plen, seglen, inlen, outlen;
85197ff4c3SKornel Duleba struct ossl_cipher_context key;
86197ff4c3SKornel Duleba struct ossl_cipher *cipher;
87197ff4c3SKornel Duleba int blocklen, error;
88197ff4c3SKornel Duleba bool encrypt;
89197ff4c3SKornel Duleba
90197ff4c3SKornel Duleba cipher = s->cipher;
91197ff4c3SKornel Duleba encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op);
92197ff4c3SKornel Duleba plen = crp->crp_payload_length;
93197ff4c3SKornel Duleba blocklen = cipher->blocksize;
94197ff4c3SKornel Duleba
95197ff4c3SKornel Duleba if (plen % blocklen)
96197ff4c3SKornel Duleba return (EINVAL);
97197ff4c3SKornel Duleba
98197ff4c3SKornel Duleba if (crp->crp_cipher_key != NULL) {
99197ff4c3SKornel Duleba if (encrypt)
100197ff4c3SKornel Duleba error = cipher->set_encrypt_key(crp->crp_cipher_key,
101197ff4c3SKornel Duleba 8 * csp->csp_cipher_klen, &key);
102197ff4c3SKornel Duleba else
103197ff4c3SKornel Duleba error = cipher->set_decrypt_key(crp->crp_cipher_key,
104197ff4c3SKornel Duleba 8 * csp->csp_cipher_klen, &key);
105197ff4c3SKornel Duleba if (error)
106197ff4c3SKornel Duleba return (error);
107197ff4c3SKornel Duleba } else {
108197ff4c3SKornel Duleba if (encrypt)
109197ff4c3SKornel Duleba key = s->enc_ctx;
110197ff4c3SKornel Duleba else
111197ff4c3SKornel Duleba key = s->dec_ctx;
112197ff4c3SKornel Duleba }
113197ff4c3SKornel Duleba
114197ff4c3SKornel Duleba crypto_read_iv(crp, iv);
115197ff4c3SKornel Duleba
116197ff4c3SKornel Duleba /* Derived from ossl_chacha20.c */
117197ff4c3SKornel Duleba crypto_cursor_init(&cc_in, &crp->crp_buf);
118197ff4c3SKornel Duleba crypto_cursor_advance(&cc_in, crp->crp_payload_start);
119197ff4c3SKornel Duleba inseg = crypto_cursor_segment(&cc_in, &inlen);
120197ff4c3SKornel Duleba if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
121197ff4c3SKornel Duleba crypto_cursor_init(&cc_out, &crp->crp_obuf);
122197ff4c3SKornel Duleba crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
123197ff4c3SKornel Duleba } else {
124197ff4c3SKornel Duleba cc_out = cc_in;
125197ff4c3SKornel Duleba }
126197ff4c3SKornel Duleba outseg = crypto_cursor_segment(&cc_out, &outlen);
127197ff4c3SKornel Duleba
128197ff4c3SKornel Duleba while (plen >= blocklen) {
129197ff4c3SKornel Duleba if (inlen < blocklen) {
130197ff4c3SKornel Duleba crypto_cursor_copydata(&cc_in, blocklen, block);
131197ff4c3SKornel Duleba in = block;
132197ff4c3SKornel Duleba inlen = blocklen;
133197ff4c3SKornel Duleba } else {
134197ff4c3SKornel Duleba in = inseg;
135197ff4c3SKornel Duleba }
136197ff4c3SKornel Duleba if (outlen < blocklen) {
137197ff4c3SKornel Duleba out = block;
138197ff4c3SKornel Duleba outlen = blocklen;
139197ff4c3SKornel Duleba } else {
140197ff4c3SKornel Duleba out = outseg;
141197ff4c3SKornel Duleba }
142197ff4c3SKornel Duleba
143197ff4c3SKornel Duleba /* Figure out how many blocks we can encrypt/decrypt at once. */
144197ff4c3SKornel Duleba seglen = rounddown(MIN(plen, MIN(inlen, outlen)), blocklen);
145197ff4c3SKornel Duleba
146197ff4c3SKornel Duleba AES_CBC_ENCRYPT(in, out, seglen, &key, iv, encrypt);
147197ff4c3SKornel Duleba
148197ff4c3SKornel Duleba if (out == block) {
149197ff4c3SKornel Duleba crypto_cursor_copyback(&cc_out, blocklen, block);
150197ff4c3SKornel Duleba outseg = crypto_cursor_segment(&cc_out, &outlen);
151197ff4c3SKornel Duleba } else {
152197ff4c3SKornel Duleba crypto_cursor_advance(&cc_out, seglen);
153197ff4c3SKornel Duleba outseg += seglen;
154197ff4c3SKornel Duleba outlen -= seglen;
155197ff4c3SKornel Duleba }
156197ff4c3SKornel Duleba if (in == block) {
157197ff4c3SKornel Duleba inseg = crypto_cursor_segment(&cc_in, &inlen);
158197ff4c3SKornel Duleba } else {
159197ff4c3SKornel Duleba crypto_cursor_advance(&cc_in, seglen);
160197ff4c3SKornel Duleba inseg += seglen;
161197ff4c3SKornel Duleba inlen -= seglen;
162197ff4c3SKornel Duleba }
163197ff4c3SKornel Duleba plen -= seglen;
164197ff4c3SKornel Duleba }
165197ff4c3SKornel Duleba
166197ff4c3SKornel Duleba explicit_bzero(block, sizeof(block));
167197ff4c3SKornel Duleba explicit_bzero(iv, sizeof(iv));
168197ff4c3SKornel Duleba explicit_bzero(&key, sizeof(key));
169197ff4c3SKornel Duleba return (0);
170197ff4c3SKornel Duleba }
1719a3444d9SMark Johnston
1729a3444d9SMark Johnston static int
ossl_aes_gcm(struct ossl_session_cipher * s,struct cryptop * crp,const struct crypto_session_params * csp)1739a3444d9SMark Johnston ossl_aes_gcm(struct ossl_session_cipher *s, struct cryptop *crp,
1749a3444d9SMark Johnston const struct crypto_session_params *csp)
1759a3444d9SMark Johnston {
1765c0dac0bSMark Johnston struct ossl_gcm_context ctx;
1779a3444d9SMark Johnston struct crypto_buffer_cursor cc_in, cc_out;
1789a3444d9SMark Johnston unsigned char iv[AES_BLOCK_LEN], tag[AES_BLOCK_LEN];
1799a3444d9SMark Johnston const unsigned char *inseg;
1809a3444d9SMark Johnston unsigned char *outseg;
1819a3444d9SMark Johnston size_t inlen, outlen, seglen;
1829a3444d9SMark Johnston int error;
1839a3444d9SMark Johnston bool encrypt;
1849a3444d9SMark Johnston
1859a3444d9SMark Johnston encrypt = CRYPTO_OP_IS_ENCRYPT(crp->crp_op);
1869a3444d9SMark Johnston
1879a3444d9SMark Johnston if (crp->crp_cipher_key != NULL) {
1889a3444d9SMark Johnston if (encrypt)
1899a3444d9SMark Johnston error = s->cipher->set_encrypt_key(crp->crp_cipher_key,
1905c0dac0bSMark Johnston 8 * csp->csp_cipher_klen,
1915c0dac0bSMark Johnston (struct ossl_cipher_context *)&ctx);
1929a3444d9SMark Johnston else
1939a3444d9SMark Johnston error = s->cipher->set_decrypt_key(crp->crp_cipher_key,
1945c0dac0bSMark Johnston 8 * csp->csp_cipher_klen,
1955c0dac0bSMark Johnston (struct ossl_cipher_context *)&ctx);
1969a3444d9SMark Johnston if (error)
1979a3444d9SMark Johnston return (error);
1989a3444d9SMark Johnston } else if (encrypt) {
1995c0dac0bSMark Johnston memcpy(&ctx, &s->enc_ctx, sizeof(struct ossl_gcm_context));
2009a3444d9SMark Johnston } else {
2015c0dac0bSMark Johnston memcpy(&ctx, &s->dec_ctx, sizeof(struct ossl_gcm_context));
2029a3444d9SMark Johnston }
2039a3444d9SMark Johnston
2049a3444d9SMark Johnston crypto_read_iv(crp, iv);
2055c0dac0bSMark Johnston ctx.ops->setiv(&ctx, iv, csp->csp_ivlen);
2069a3444d9SMark Johnston
20787826c87SMark Johnston if (crp->crp_aad != NULL) {
2085c0dac0bSMark Johnston if (ctx.ops->aad(&ctx, crp->crp_aad, crp->crp_aad_length) != 0)
20987826c87SMark Johnston return (EINVAL);
21087826c87SMark Johnston } else {
2119a3444d9SMark Johnston crypto_cursor_init(&cc_in, &crp->crp_buf);
2129a3444d9SMark Johnston crypto_cursor_advance(&cc_in, crp->crp_aad_start);
21387826c87SMark Johnston for (size_t alen = crp->crp_aad_length; alen > 0;
21487826c87SMark Johnston alen -= seglen) {
2159a3444d9SMark Johnston inseg = crypto_cursor_segment(&cc_in, &inlen);
2169a3444d9SMark Johnston seglen = MIN(alen, inlen);
2175c0dac0bSMark Johnston if (ctx.ops->aad(&ctx, inseg, seglen) != 0)
2189a3444d9SMark Johnston return (EINVAL);
2199a3444d9SMark Johnston crypto_cursor_advance(&cc_in, seglen);
2209a3444d9SMark Johnston }
22187826c87SMark Johnston }
2229a3444d9SMark Johnston
2239a3444d9SMark Johnston crypto_cursor_init(&cc_in, &crp->crp_buf);
2249a3444d9SMark Johnston crypto_cursor_advance(&cc_in, crp->crp_payload_start);
2259a3444d9SMark Johnston if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
2269a3444d9SMark Johnston crypto_cursor_init(&cc_out, &crp->crp_obuf);
2279a3444d9SMark Johnston crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
2289a3444d9SMark Johnston } else {
2299a3444d9SMark Johnston cc_out = cc_in;
2309a3444d9SMark Johnston }
2319a3444d9SMark Johnston
2329a3444d9SMark Johnston for (size_t plen = crp->crp_payload_length; plen > 0; plen -= seglen) {
2339a3444d9SMark Johnston inseg = crypto_cursor_segment(&cc_in, &inlen);
2349a3444d9SMark Johnston outseg = crypto_cursor_segment(&cc_out, &outlen);
2359a3444d9SMark Johnston seglen = MIN(plen, MIN(inlen, outlen));
2369a3444d9SMark Johnston
2379a3444d9SMark Johnston if (encrypt) {
2385c0dac0bSMark Johnston if (ctx.ops->encrypt(&ctx, inseg, outseg, seglen) != 0)
2399a3444d9SMark Johnston return (EINVAL);
2409a3444d9SMark Johnston } else {
2415c0dac0bSMark Johnston if (ctx.ops->decrypt(&ctx, inseg, outseg, seglen) != 0)
2429a3444d9SMark Johnston return (EINVAL);
2439a3444d9SMark Johnston }
2449a3444d9SMark Johnston
2459a3444d9SMark Johnston crypto_cursor_advance(&cc_in, seglen);
2469a3444d9SMark Johnston crypto_cursor_advance(&cc_out, seglen);
2479a3444d9SMark Johnston }
2489a3444d9SMark Johnston
2499a3444d9SMark Johnston error = 0;
2509a3444d9SMark Johnston if (encrypt) {
2515c0dac0bSMark Johnston ctx.ops->tag(&ctx, tag, GMAC_DIGEST_LEN);
2529a3444d9SMark Johnston crypto_copyback(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
2539a3444d9SMark Johnston tag);
2549a3444d9SMark Johnston } else {
2559a3444d9SMark Johnston crypto_copydata(crp, crp->crp_digest_start, GMAC_DIGEST_LEN,
2569a3444d9SMark Johnston tag);
2575c0dac0bSMark Johnston if (ctx.ops->finish(&ctx, tag, GMAC_DIGEST_LEN) != 0)
2589a3444d9SMark Johnston error = EBADMSG;
2599a3444d9SMark Johnston }
2609a3444d9SMark Johnston
2619a3444d9SMark Johnston explicit_bzero(iv, sizeof(iv));
2629a3444d9SMark Johnston explicit_bzero(tag, sizeof(tag));
2635c0dac0bSMark Johnston explicit_bzero(&ctx, sizeof(ctx));
2649a3444d9SMark Johnston
2659a3444d9SMark Johnston return (error);
2669a3444d9SMark Johnston }
267