1c58794deSPawel Jakub Dawidek /*- 23728855aSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 33728855aSPedro F. Giffuni * 49839c97bSPawel Jakub Dawidek * Copyright (c) 2005-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> 5c58794deSPawel Jakub Dawidek * All rights reserved. 6c58794deSPawel Jakub Dawidek * 7c58794deSPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 8c58794deSPawel Jakub Dawidek * modification, are permitted provided that the following conditions 9c58794deSPawel Jakub Dawidek * are met: 10c58794deSPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 11c58794deSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 12c58794deSPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 13c58794deSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 14c58794deSPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 15c58794deSPawel Jakub Dawidek * 16c58794deSPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17c58794deSPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18c58794deSPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19c58794deSPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20c58794deSPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21c58794deSPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22c58794deSPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23c58794deSPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24c58794deSPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25c58794deSPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26c58794deSPawel Jakub Dawidek * SUCH DAMAGE. 27c58794deSPawel Jakub Dawidek */ 28c58794deSPawel Jakub Dawidek 29c58794deSPawel Jakub Dawidek #include <sys/cdefs.h> 30c58794deSPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 31c58794deSPawel Jakub Dawidek 32c58794deSPawel Jakub Dawidek #include <sys/param.h> 33c58794deSPawel Jakub Dawidek #ifdef _KERNEL 34c58794deSPawel Jakub Dawidek #include <sys/systm.h> 35c58794deSPawel Jakub Dawidek #include <sys/kernel.h> 36c58794deSPawel Jakub Dawidek #include <sys/malloc.h> 37c58794deSPawel Jakub Dawidek #else 38c58794deSPawel Jakub Dawidek #include <stdint.h> 39c58794deSPawel Jakub Dawidek #include <string.h> 40c58794deSPawel Jakub Dawidek #include <strings.h> 41c58794deSPawel Jakub Dawidek #include <errno.h> 42c58794deSPawel Jakub Dawidek #include <assert.h> 43c58794deSPawel Jakub Dawidek #include <openssl/evp.h> 44c58794deSPawel Jakub Dawidek #define _OpenSSL_ 45c58794deSPawel Jakub Dawidek #endif 46c58794deSPawel Jakub Dawidek #include <geom/eli/g_eli.h> 47c58794deSPawel Jakub Dawidek 48c58794deSPawel Jakub Dawidek #ifdef _KERNEL 49c58794deSPawel Jakub Dawidek MALLOC_DECLARE(M_ELI); 50c58794deSPawel Jakub Dawidek 51c58794deSPawel Jakub Dawidek static int 52c58794deSPawel Jakub Dawidek g_eli_crypto_done(struct cryptop *crp) 53c58794deSPawel Jakub Dawidek { 54c58794deSPawel Jakub Dawidek 55c58794deSPawel Jakub Dawidek crp->crp_opaque = (void *)crp; 56c58794deSPawel Jakub Dawidek wakeup(crp); 57c58794deSPawel Jakub Dawidek return (0); 58c58794deSPawel Jakub Dawidek } 59c58794deSPawel Jakub Dawidek 60c58794deSPawel Jakub Dawidek static int 61c58794deSPawel Jakub Dawidek g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, 62c58794deSPawel Jakub Dawidek const u_char *key, size_t keysize) 63c58794deSPawel Jakub Dawidek { 64c58794deSPawel Jakub Dawidek struct cryptoini cri; 65c58794deSPawel Jakub Dawidek struct cryptop *crp; 66c58794deSPawel Jakub Dawidek struct cryptodesc *crd; 67*1df7f415SConrad Meyer crypto_session_t sid; 68c58794deSPawel Jakub Dawidek u_char *p; 69c58794deSPawel Jakub Dawidek int error; 70c58794deSPawel Jakub Dawidek 719a5a1d1eSPawel Jakub Dawidek KASSERT(algo != CRYPTO_AES_XTS, 729a5a1d1eSPawel Jakub Dawidek ("%s: CRYPTO_AES_XTS unexpected here", __func__)); 739a5a1d1eSPawel Jakub Dawidek 74c58794deSPawel Jakub Dawidek bzero(&cri, sizeof(cri)); 75c58794deSPawel Jakub Dawidek cri.cri_alg = algo; 76c58794deSPawel Jakub Dawidek cri.cri_key = __DECONST(void *, key); 77c58794deSPawel Jakub Dawidek cri.cri_klen = keysize; 786810ad6fSSam Leffler error = crypto_newsession(&sid, &cri, CRYPTOCAP_F_SOFTWARE); 79c58794deSPawel Jakub Dawidek if (error != 0) 80c58794deSPawel Jakub Dawidek return (error); 8189fac384SJohn-Mark Gurney p = malloc(sizeof(*crp) + sizeof(*crd), M_ELI, M_NOWAIT | M_ZERO); 82c58794deSPawel Jakub Dawidek if (p == NULL) { 83c58794deSPawel Jakub Dawidek crypto_freesession(sid); 84c58794deSPawel Jakub Dawidek return (ENOMEM); 85c58794deSPawel Jakub Dawidek } 86c58794deSPawel Jakub Dawidek crp = (struct cryptop *)p; p += sizeof(*crp); 87c58794deSPawel Jakub Dawidek crd = (struct cryptodesc *)p; p += sizeof(*crd); 88c58794deSPawel Jakub Dawidek 89c58794deSPawel Jakub Dawidek crd->crd_skip = 0; 90c58794deSPawel Jakub Dawidek crd->crd_len = datasize; 915af2ae28SPawel Jakub Dawidek crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; 92c58794deSPawel Jakub Dawidek if (enc) 93c58794deSPawel Jakub Dawidek crd->crd_flags |= CRD_F_ENCRYPT; 94c58794deSPawel Jakub Dawidek crd->crd_alg = algo; 95c58794deSPawel Jakub Dawidek crd->crd_key = __DECONST(void *, key); 96c58794deSPawel Jakub Dawidek crd->crd_klen = keysize; 97c58794deSPawel Jakub Dawidek bzero(crd->crd_iv, sizeof(crd->crd_iv)); 98c58794deSPawel Jakub Dawidek crd->crd_next = NULL; 99c58794deSPawel Jakub Dawidek 100c58794deSPawel Jakub Dawidek crp->crp_sid = sid; 101c58794deSPawel Jakub Dawidek crp->crp_ilen = datasize; 102c58794deSPawel Jakub Dawidek crp->crp_olen = datasize; 103c58794deSPawel Jakub Dawidek crp->crp_opaque = NULL; 104c58794deSPawel Jakub Dawidek crp->crp_callback = g_eli_crypto_done; 10589fac384SJohn-Mark Gurney crp->crp_buf = (void *)data; 10608fca7a5SJohn-Mark Gurney crp->crp_flags = CRYPTO_F_CBIFSYNC; 107c58794deSPawel Jakub Dawidek crp->crp_desc = crd; 108c58794deSPawel Jakub Dawidek 109c58794deSPawel Jakub Dawidek error = crypto_dispatch(crp); 110c58794deSPawel Jakub Dawidek if (error == 0) { 111c58794deSPawel Jakub Dawidek while (crp->crp_opaque == NULL) 112c58794deSPawel Jakub Dawidek tsleep(crp, PRIBIO, "geli", hz / 5); 113c58794deSPawel Jakub Dawidek error = crp->crp_etype; 114c58794deSPawel Jakub Dawidek } 115c58794deSPawel Jakub Dawidek 116c58794deSPawel Jakub Dawidek free(crp, M_ELI); 117c58794deSPawel Jakub Dawidek crypto_freesession(sid); 118c58794deSPawel Jakub Dawidek return (error); 119c58794deSPawel Jakub Dawidek } 120c58794deSPawel Jakub Dawidek #else /* !_KERNEL */ 121c58794deSPawel Jakub Dawidek static int 122c58794deSPawel Jakub Dawidek g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, 123c58794deSPawel Jakub Dawidek const u_char *key, size_t keysize) 124c58794deSPawel Jakub Dawidek { 125c58794deSPawel Jakub Dawidek EVP_CIPHER_CTX ctx; 126c58794deSPawel Jakub Dawidek const EVP_CIPHER *type; 127c58794deSPawel Jakub Dawidek u_char iv[keysize]; 128c58794deSPawel Jakub Dawidek int outsize; 129c58794deSPawel Jakub Dawidek 1309a5a1d1eSPawel Jakub Dawidek assert(algo != CRYPTO_AES_XTS); 1319a5a1d1eSPawel Jakub Dawidek 132c58794deSPawel Jakub Dawidek switch (algo) { 133c58794deSPawel Jakub Dawidek case CRYPTO_NULL_CBC: 134c58794deSPawel Jakub Dawidek type = EVP_enc_null(); 135c58794deSPawel Jakub Dawidek break; 136c58794deSPawel Jakub Dawidek case CRYPTO_AES_CBC: 137c58794deSPawel Jakub Dawidek switch (keysize) { 138c58794deSPawel Jakub Dawidek case 128: 139c58794deSPawel Jakub Dawidek type = EVP_aes_128_cbc(); 140c58794deSPawel Jakub Dawidek break; 141c58794deSPawel Jakub Dawidek case 192: 142c58794deSPawel Jakub Dawidek type = EVP_aes_192_cbc(); 143c58794deSPawel Jakub Dawidek break; 144c58794deSPawel Jakub Dawidek case 256: 145c58794deSPawel Jakub Dawidek type = EVP_aes_256_cbc(); 146c58794deSPawel Jakub Dawidek break; 147c58794deSPawel Jakub Dawidek default: 148c58794deSPawel Jakub Dawidek return (EINVAL); 149c58794deSPawel Jakub Dawidek } 150c58794deSPawel Jakub Dawidek break; 151c58794deSPawel Jakub Dawidek case CRYPTO_BLF_CBC: 152c58794deSPawel Jakub Dawidek type = EVP_bf_cbc(); 153c58794deSPawel Jakub Dawidek break; 15418b0b6d1SJohn Birrell #ifndef OPENSSL_NO_CAMELLIA 155864cba96SPawel Jakub Dawidek case CRYPTO_CAMELLIA_CBC: 156864cba96SPawel Jakub Dawidek switch (keysize) { 157864cba96SPawel Jakub Dawidek case 128: 158864cba96SPawel Jakub Dawidek type = EVP_camellia_128_cbc(); 159864cba96SPawel Jakub Dawidek break; 160864cba96SPawel Jakub Dawidek case 192: 161864cba96SPawel Jakub Dawidek type = EVP_camellia_192_cbc(); 162864cba96SPawel Jakub Dawidek break; 163864cba96SPawel Jakub Dawidek case 256: 164864cba96SPawel Jakub Dawidek type = EVP_camellia_256_cbc(); 165864cba96SPawel Jakub Dawidek break; 166864cba96SPawel Jakub Dawidek default: 167864cba96SPawel Jakub Dawidek return (EINVAL); 168864cba96SPawel Jakub Dawidek } 169864cba96SPawel Jakub Dawidek break; 17018b0b6d1SJohn Birrell #endif 171c58794deSPawel Jakub Dawidek case CRYPTO_3DES_CBC: 172c58794deSPawel Jakub Dawidek type = EVP_des_ede3_cbc(); 173c58794deSPawel Jakub Dawidek break; 174c58794deSPawel Jakub Dawidek default: 175c58794deSPawel Jakub Dawidek return (EINVAL); 176c58794deSPawel Jakub Dawidek } 177c58794deSPawel Jakub Dawidek 178c58794deSPawel Jakub Dawidek EVP_CIPHER_CTX_init(&ctx); 179c58794deSPawel Jakub Dawidek 180c58794deSPawel Jakub Dawidek EVP_CipherInit_ex(&ctx, type, NULL, NULL, NULL, enc); 181c58794deSPawel Jakub Dawidek EVP_CIPHER_CTX_set_key_length(&ctx, keysize / 8); 182c58794deSPawel Jakub Dawidek EVP_CIPHER_CTX_set_padding(&ctx, 0); 183c58794deSPawel Jakub Dawidek bzero(iv, sizeof(iv)); 184c58794deSPawel Jakub Dawidek EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, enc); 185c58794deSPawel Jakub Dawidek 186c58794deSPawel Jakub Dawidek if (EVP_CipherUpdate(&ctx, data, &outsize, data, datasize) == 0) { 187c58794deSPawel Jakub Dawidek EVP_CIPHER_CTX_cleanup(&ctx); 188c58794deSPawel Jakub Dawidek return (EINVAL); 189c58794deSPawel Jakub Dawidek } 190c58794deSPawel Jakub Dawidek assert(outsize == (int)datasize); 191c58794deSPawel Jakub Dawidek 192c58794deSPawel Jakub Dawidek if (EVP_CipherFinal_ex(&ctx, data + outsize, &outsize) == 0) { 193c58794deSPawel Jakub Dawidek EVP_CIPHER_CTX_cleanup(&ctx); 194c58794deSPawel Jakub Dawidek return (EINVAL); 195c58794deSPawel Jakub Dawidek } 196c58794deSPawel Jakub Dawidek assert(outsize == 0); 197c58794deSPawel Jakub Dawidek 198c58794deSPawel Jakub Dawidek EVP_CIPHER_CTX_cleanup(&ctx); 199c58794deSPawel Jakub Dawidek return (0); 200c58794deSPawel Jakub Dawidek } 201c58794deSPawel Jakub Dawidek #endif /* !_KERNEL */ 202c58794deSPawel Jakub Dawidek 203c58794deSPawel Jakub Dawidek int 204c58794deSPawel Jakub Dawidek g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize, 205c58794deSPawel Jakub Dawidek const u_char *key, size_t keysize) 206c58794deSPawel Jakub Dawidek { 207c58794deSPawel Jakub Dawidek 2089a5a1d1eSPawel Jakub Dawidek /* We prefer AES-CBC for metadata protection. */ 2099a5a1d1eSPawel Jakub Dawidek if (algo == CRYPTO_AES_XTS) 2109a5a1d1eSPawel Jakub Dawidek algo = CRYPTO_AES_CBC; 2119a5a1d1eSPawel Jakub Dawidek 212c58794deSPawel Jakub Dawidek return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize)); 213c58794deSPawel Jakub Dawidek } 214c58794deSPawel Jakub Dawidek 215c58794deSPawel Jakub Dawidek int 216c58794deSPawel Jakub Dawidek g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize, 217c58794deSPawel Jakub Dawidek const u_char *key, size_t keysize) 218c58794deSPawel Jakub Dawidek { 219c58794deSPawel Jakub Dawidek 2209a5a1d1eSPawel Jakub Dawidek /* We prefer AES-CBC for metadata protection. */ 2219a5a1d1eSPawel Jakub Dawidek if (algo == CRYPTO_AES_XTS) 2229a5a1d1eSPawel Jakub Dawidek algo = CRYPTO_AES_CBC; 2239a5a1d1eSPawel Jakub Dawidek 224c58794deSPawel Jakub Dawidek return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize)); 225c58794deSPawel Jakub Dawidek } 226