g_eli_crypto.c revision 157900
1193323Sed/*- 2193323Sed * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3193323Sed * All rights reserved. 4193323Sed * 5193323Sed * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that the following conditions 7193323Sed * are met: 8193323Sed * 1. Redistributions of source code must retain the above copyright 9193323Sed * notice, this list of conditions and the following disclaimer. 10193323Sed * 2. Redistributions in binary form must reproduce the above copyright 11249423Sdim * notice, this list of conditions and the following disclaimer in the 12193323Sed * documentation and/or other materials provided with the distribution. 13193323Sed * 14193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15263508Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16202878Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18249423Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19198090Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20202878Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21202878Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22206083Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23201360Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24198090Srdivacky * SUCH DAMAGE. 25198090Srdivacky */ 26202878Srdivacky 27263508Sdim#include <sys/cdefs.h> 28193323Sed__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_crypto.c 157900 2006-04-20 06:33:46Z pjd $"); 29193323Sed 30193323Sed#include <sys/param.h> 31193323Sed#ifdef _KERNEL 32193323Sed#include <sys/systm.h> 33193323Sed#include <sys/kernel.h> 34193323Sed#include <sys/malloc.h> 35193323Sed#include <sys/uio.h> 36193323Sed#else 37263508Sdim#include <stdint.h> 38263508Sdim#include <string.h> 39263508Sdim#include <strings.h> 40263508Sdim#include <errno.h> 41193323Sed#include <assert.h> 42193323Sed#include <openssl/evp.h> 43193323Sed#define _OpenSSL_ 44193323Sed#endif 45193323Sed#include <geom/eli/g_eli.h> 46193323Sed 47193323Sed#ifdef _KERNEL 48193323SedMALLOC_DECLARE(M_ELI); 49193323Sed 50263508Sdimstatic int 51193323Sedg_eli_crypto_done(struct cryptop *crp) 52193323Sed{ 53193323Sed 54193323Sed crp->crp_opaque = (void *)crp; 55193323Sed wakeup(crp); 56193323Sed return (0); 57193323Sed} 58193323Sed 59193323Sedstatic int 60206274Srdivackyg_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, 61193323Sed const u_char *key, size_t keysize) 62206274Srdivacky{ 63193323Sed struct cryptoini cri; 64193323Sed struct cryptop *crp; 65206274Srdivacky struct cryptodesc *crd; 66193323Sed struct uio *uio; 67193323Sed struct iovec *iov; 68193323Sed uint64_t sid; 69193323Sed u_char *p; 70193323Sed int error; 71193323Sed 72206274Srdivacky bzero(&cri, sizeof(cri)); 73226633Sdim cri.cri_alg = algo; 74193323Sed cri.cri_key = __DECONST(void *, key); 75193323Sed cri.cri_klen = keysize; 76206274Srdivacky error = crypto_newsession(&sid, &cri, 0); 77202878Srdivacky if (error != 0) 78193323Sed return (error); 79193323Sed p = malloc(sizeof(*crp) + sizeof(*crd) + sizeof(*uio) + sizeof(*iov), 80193323Sed M_ELI, M_NOWAIT | M_ZERO); 81206274Srdivacky if (p == NULL) { 82206274Srdivacky crypto_freesession(sid); 83193323Sed return (ENOMEM); 84193323Sed } 85193323Sed crp = (struct cryptop *)p; p += sizeof(*crp); 86198090Srdivacky crd = (struct cryptodesc *)p; p += sizeof(*crd); 87193323Sed uio = (struct uio *)p; p += sizeof(*uio); 88198090Srdivacky iov = (struct iovec *)p; p += sizeof(*iov); 89193323Sed 90193323Sed iov->iov_len = datasize; 91193323Sed iov->iov_base = data; 92193323Sed 93198090Srdivacky uio->uio_iov = iov; 94193323Sed uio->uio_iovcnt = 1; 95193323Sed uio->uio_segflg = UIO_SYSSPACE; 96193323Sed uio->uio_resid = datasize; 97193323Sed 98193323Sed crd->crd_skip = 0; 99193323Sed crd->crd_len = datasize; 100198090Srdivacky crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; 101193323Sed if (enc) 102193323Sed crd->crd_flags |= CRD_F_ENCRYPT; 103201360Srdivacky crd->crd_alg = algo; 104193323Sed crd->crd_key = __DECONST(void *, key); 105193323Sed crd->crd_klen = keysize; 106193323Sed bzero(crd->crd_iv, sizeof(crd->crd_iv)); 107193323Sed crd->crd_next = NULL; 108193323Sed 109193323Sed crp->crp_sid = sid; 110193323Sed crp->crp_ilen = datasize; 111193323Sed crp->crp_olen = datasize; 112193323Sed crp->crp_opaque = NULL; 113193323Sed crp->crp_callback = g_eli_crypto_done; 114193323Sed crp->crp_buf = (void *)uio; 115251662Sdim crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIFSYNC | CRYPTO_F_REL; 116251662Sdim crp->crp_desc = crd; 117263508Sdim 118263508Sdim error = crypto_dispatch(crp); 119263508Sdim if (error == 0) { 120263508Sdim while (crp->crp_opaque == NULL) 121263508Sdim tsleep(crp, PRIBIO, "geli", hz / 5); 122263508Sdim error = crp->crp_etype; 123263508Sdim } 124263508Sdim 125263508Sdim free(crp, M_ELI); 126263508Sdim crypto_freesession(sid); 127249423Sdim return (error); 128249423Sdim} 129249423Sdim#else /* !_KERNEL */ 130249423Sdimstatic int 131249423Sdimg_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, 132263508Sdim const u_char *key, size_t keysize) 133249423Sdim{ 134249423Sdim EVP_CIPHER_CTX ctx; 135263508Sdim const EVP_CIPHER *type; 136263508Sdim u_char iv[keysize]; 137263508Sdim int outsize; 138263508Sdim 139263508Sdim switch (algo) { 140263508Sdim case CRYPTO_NULL_CBC: 141263508Sdim type = EVP_enc_null(); 142263508Sdim break; 143263508Sdim case CRYPTO_AES_CBC: 144263508Sdim switch (keysize) { 145263508Sdim case 128: 146263508Sdim type = EVP_aes_128_cbc(); 147193323Sed break; 148251662Sdim case 192: 149193323Sed type = EVP_aes_192_cbc(); 150193323Sed break; 151193323Sed case 256: 152193323Sed type = EVP_aes_256_cbc(); 153193323Sed break; 154193323Sed default: 155198090Srdivacky return (EINVAL); 156193323Sed } 157204961Srdivacky break; 158193323Sed case CRYPTO_BLF_CBC: 159193323Sed type = EVP_bf_cbc(); 160193323Sed break; 161193323Sed case CRYPTO_3DES_CBC: 162204961Srdivacky type = EVP_des_ede3_cbc(); 163193323Sed break; 164204961Srdivacky default: 165193323Sed return (EINVAL); 166193323Sed } 167249423Sdim 168193323Sed EVP_CIPHER_CTX_init(&ctx); 169193323Sed 170193323Sed EVP_CipherInit_ex(&ctx, type, NULL, NULL, NULL, enc); 171193323Sed EVP_CIPHER_CTX_set_key_length(&ctx, keysize / 8); 172193323Sed EVP_CIPHER_CTX_set_padding(&ctx, 0); 173193323Sed bzero(iv, sizeof(iv)); 174193323Sed EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, enc); 175193323Sed 176193323Sed if (EVP_CipherUpdate(&ctx, data, &outsize, data, datasize) == 0) { 177193323Sed EVP_CIPHER_CTX_cleanup(&ctx); 178193323Sed return (EINVAL); 179193323Sed } 180193323Sed assert(outsize == (int)datasize); 181193323Sed 182193323Sed if (EVP_CipherFinal_ex(&ctx, data + outsize, &outsize) == 0) { 183193323Sed EVP_CIPHER_CTX_cleanup(&ctx); 184193323Sed return (EINVAL); 185193323Sed } 186193323Sed assert(outsize == 0); 187251662Sdim 188193323Sed EVP_CIPHER_CTX_cleanup(&ctx); 189193323Sed return (0); 190193323Sed} 191193323Sed#endif /* !_KERNEL */ 192193323Sed 193193323Sedint 194201360Srdivackyg_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize, 195193323Sed const u_char *key, size_t keysize) 196193323Sed{ 197193323Sed 198234353Sdim return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize)); 199193323Sed} 200193323Sed 201263508Sdimint 202201360Srdivackyg_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize, 203193323Sed const u_char *key, size_t keysize) 204193323Sed{ 205193323Sed 206193323Sed return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize)); 207193323Sed} 208193323Sed 209193323Sedvoid 210193323Sedg_eli_crypto_hmac_init(struct hmac_ctx *ctx, const uint8_t *hkey, 211193323Sed size_t hkeylen) 212263508Sdim{ 213202878Srdivacky u_char k_ipad[128], key[128]; 214193323Sed SHA512_CTX lctx; 215243830Sdim u_int i; 216243830Sdim 217243830Sdim bzero(key, sizeof(key)); 218243830Sdim if (hkeylen == 0) 219263508Sdim ; /* do nothing */ 220243830Sdim else if (hkeylen <= 128) 221193323Sed bcopy(hkey, key, hkeylen); 222193323Sed else { 223202878Srdivacky /* If key is longer than 128 bytes reset it to key = SHA512(key). */ 224193323Sed SHA512_Init(&lctx); 225202878Srdivacky SHA512_Update(&lctx, hkey, hkeylen); 226249423Sdim SHA512_Final(key, &lctx); 227193323Sed } 228202878Srdivacky 229193323Sed /* XOR key with ipad and opad values. */ 230202878Srdivacky for (i = 0; i < sizeof(key); i++) { 231249423Sdim k_ipad[i] = key[i] ^ 0x36; 232249423Sdim ctx->k_opad[i] = key[i] ^ 0x5c; 233206274Srdivacky } 234206274Srdivacky bzero(key, sizeof(key)); 235243830Sdim /* Perform inner SHA512. */ 236243830Sdim SHA512_Init(&ctx->shactx); 237198090Srdivacky SHA512_Update(&ctx->shactx, k_ipad, sizeof(k_ipad)); 238193323Sed} 239249423Sdim 240193323Sedvoid 241193323Sedg_eli_crypto_hmac_update(struct hmac_ctx *ctx, const uint8_t *data, 242193323Sed size_t datasize) 243193323Sed{ 244263508Sdim 245193323Sed SHA512_Update(&ctx->shactx, data, datasize); 246243830Sdim} 247193323Sed 248193323Sedvoid 249193323Sedg_eli_crypto_hmac_final(struct hmac_ctx *ctx, uint8_t *md, size_t mdsize) 250193323Sed{ 251193323Sed u_char digest[SHA512_MDLEN]; 252249423Sdim SHA512_CTX lctx; 253193323Sed 254193323Sed SHA512_Final(digest, &ctx->shactx); 255193323Sed /* Perform outer SHA512. */ 256193323Sed SHA512_Init(&lctx); 257249423Sdim SHA512_Update(&lctx, ctx->k_opad, sizeof(ctx->k_opad)); 258249423Sdim bzero(ctx, sizeof(*ctx)); 259198090Srdivacky SHA512_Update(&lctx, digest, sizeof(digest)); 260198090Srdivacky SHA512_Final(digest, &lctx); 261243830Sdim /* mdsize == 0 means "Give me the whole hash!" */ 262234353Sdim if (mdsize == 0) 263193323Sed mdsize = SHA512_MDLEN; 264193323Sed bcopy(digest, md, mdsize); 265193323Sed} 266193323Sed 267263508Sdimvoid 268234353Sdimg_eli_crypto_hmac(const uint8_t *hkey, size_t hkeysize, const uint8_t *data, 269234353Sdim size_t datasize, uint8_t *md, size_t mdsize) 270193323Sed{ 271193323Sed struct hmac_ctx ctx; 272193323Sed 273193323Sed g_eli_crypto_hmac_init(&ctx, hkey, hkeysize); 274263508Sdim g_eli_crypto_hmac_update(&ctx, data, datasize); 275263508Sdim g_eli_crypto_hmac_final(&ctx, md, mdsize); 276263508Sdim} 277263508Sdim