g_eli_crypto.c revision 172031
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 11193323Sed * 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 15193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18226633Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19195340Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21206083Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22224145Sdim * 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 24193323Sed * SUCH DAMAGE. 25193323Sed */ 26193323Sed 27193323Sed#include <sys/cdefs.h> 28193323Sed__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_crypto.c 172031 2007-09-01 06:33:02Z 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 37224145Sdim#include <stdint.h> 38193323Sed#include <string.h> 39198892Srdivacky#include <strings.h> 40198892Srdivacky#include <errno.h> 41198892Srdivacky#include <assert.h> 42198892Srdivacky#include <openssl/evp.h> 43198892Srdivacky#define _OpenSSL_ 44198892Srdivacky#endif 45198892Srdivacky#include <geom/eli/g_eli.h> 46198892Srdivacky 47198892Srdivacky#ifdef _KERNEL 48198892SrdivackyMALLOC_DECLARE(M_ELI); 49198892Srdivacky 50198892Srdivackystatic int 51198892Srdivackyg_eli_crypto_done(struct cryptop *crp) 52201360Srdivacky{ 53224145Sdim 54224145Sdim crp->crp_opaque = (void *)crp; 55224145Sdim wakeup(crp); 56198892Srdivacky return (0); 57198892Srdivacky} 58198892Srdivacky 59198892Srdivackystatic int 60198892Srdivackyg_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, 61198892Srdivacky const u_char *key, size_t keysize) 62198892Srdivacky{ 63198892Srdivacky struct cryptoini cri; 64201360Srdivacky struct cryptop *crp; 65201360Srdivacky struct cryptodesc *crd; 66224145Sdim struct uio *uio; 67198892Srdivacky struct iovec *iov; 68224145Sdim uint64_t sid; 69224145Sdim u_char *p; 70224145Sdim int error; 71224145Sdim 72224145Sdim bzero(&cri, sizeof(cri)); 73224145Sdim cri.cri_alg = algo; 74198892Srdivacky cri.cri_key = __DECONST(void *, key); 75198892Srdivacky cri.cri_klen = keysize; 76198892Srdivacky error = crypto_newsession(&sid, &cri, CRYPTOCAP_F_SOFTWARE); 77224145Sdim if (error != 0) 78224145Sdim return (error); 79198892Srdivacky p = malloc(sizeof(*crp) + sizeof(*crd) + sizeof(*uio) + sizeof(*iov), 80198892Srdivacky M_ELI, M_NOWAIT | M_ZERO); 81198892Srdivacky if (p == NULL) { 82198892Srdivacky crypto_freesession(sid); 83198892Srdivacky return (ENOMEM); 84193323Sed } 85193323Sed crp = (struct cryptop *)p; p += sizeof(*crp); 86193323Sed crd = (struct cryptodesc *)p; p += sizeof(*crd); 87193323Sed uio = (struct uio *)p; p += sizeof(*uio); 88207618Srdivacky iov = (struct iovec *)p; p += sizeof(*iov); 89193323Sed 90193323Sed iov->iov_len = datasize; 91206083Srdivacky iov->iov_base = data; 92206083Srdivacky 93206083Srdivacky uio->uio_iov = iov; 94212904Sdim uio->uio_iovcnt = 1; 95212904Sdim uio->uio_segflg = UIO_SYSSPACE; 96212904Sdim uio->uio_resid = datasize; 97212904Sdim 98212904Sdim crd->crd_skip = 0; 99212904Sdim crd->crd_len = datasize; 100212904Sdim crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; 101212904Sdim if (enc) 102206083Srdivacky crd->crd_flags |= CRD_F_ENCRYPT; 103206083Srdivacky crd->crd_alg = algo; 104206083Srdivacky crd->crd_key = __DECONST(void *, key); 105206083Srdivacky crd->crd_klen = keysize; 106206083Srdivacky bzero(crd->crd_iv, sizeof(crd->crd_iv)); 107193323Sed crd->crd_next = NULL; 108224145Sdim 109224145Sdim crp->crp_sid = sid; 110224145Sdim crp->crp_ilen = datasize; 111224145Sdim crp->crp_olen = datasize; 112224145Sdim crp->crp_opaque = NULL; 113201360Srdivacky crp->crp_callback = g_eli_crypto_done; 114201360Srdivacky crp->crp_buf = (void *)uio; 115193323Sed crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIFSYNC | CRYPTO_F_REL; 116193323Sed crp->crp_desc = crd; 117193323Sed 118193323Sed error = crypto_dispatch(crp); 119193323Sed if (error == 0) { 120198892Srdivacky while (crp->crp_opaque == NULL) 121198892Srdivacky tsleep(crp, PRIBIO, "geli", hz / 5); 122198892Srdivacky error = crp->crp_etype; 123198892Srdivacky } 124198892Srdivacky 125198892Srdivacky free(crp, M_ELI); 126193323Sed crypto_freesession(sid); 127195340Sed return (error); 128198396Srdivacky} 129224145Sdim#else /* !_KERNEL */ 130193323Sedstatic int 131193323Sedg_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, 132224145Sdim const u_char *key, size_t keysize) 133195340Sed{ 134193323Sed EVP_CIPHER_CTX ctx; 135193323Sed const EVP_CIPHER *type; 136218893Sdim u_char iv[keysize]; 137193323Sed int outsize; 138193323Sed 139218893Sdim switch (algo) { 140193323Sed case CRYPTO_NULL_CBC: 141193323Sed type = EVP_enc_null(); 142193323Sed break; 143193323Sed case CRYPTO_AES_CBC: 144193323Sed switch (keysize) { 145193323Sed case 128: 146226633Sdim type = EVP_aes_128_cbc(); 147226633Sdim break; 148193323Sed case 192: 149193323Sed type = EVP_aes_192_cbc(); 150193323Sed break; 151193323Sed case 256: 152193323Sed type = EVP_aes_256_cbc(); 153193323Sed break; 154193323Sed default: 155193323Sed return (EINVAL); 156218893Sdim } 157193323Sed break; 158193323Sed case CRYPTO_BLF_CBC: 159193323Sed type = EVP_bf_cbc(); 160218893Sdim break; 161218893Sdim case CRYPTO_CAMELLIA_CBC: 162193323Sed switch (keysize) { 163193323Sed case 128: 164193323Sed type = EVP_camellia_128_cbc(); 165193323Sed break; 166193323Sed case 192: 167193323Sed type = EVP_camellia_192_cbc(); 168193323Sed break; 169193323Sed case 256: 170193323Sed type = EVP_camellia_256_cbc(); 171193323Sed break; 172193323Sed default: 173193323Sed return (EINVAL); 174193323Sed } 175193323Sed break; 176193323Sed case CRYPTO_3DES_CBC: 177193323Sed type = EVP_des_ede3_cbc(); 178193323Sed break; 179193323Sed default: 180198090Srdivacky return (EINVAL); 181193323Sed } 182226633Sdim 183226633Sdim EVP_CIPHER_CTX_init(&ctx); 184203954Srdivacky 185201360Srdivacky EVP_CipherInit_ex(&ctx, type, NULL, NULL, NULL, enc); 186201360Srdivacky EVP_CIPHER_CTX_set_key_length(&ctx, keysize / 8); 187201360Srdivacky EVP_CIPHER_CTX_set_padding(&ctx, 0); 188201360Srdivacky bzero(iv, sizeof(iv)); 189201360Srdivacky EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, enc); 190201360Srdivacky 191201360Srdivacky if (EVP_CipherUpdate(&ctx, data, &outsize, data, datasize) == 0) { 192201360Srdivacky EVP_CIPHER_CTX_cleanup(&ctx); 193201360Srdivacky return (EINVAL); 194193323Sed } 195193323Sed assert(outsize == (int)datasize); 196193323Sed 197193323Sed if (EVP_CipherFinal_ex(&ctx, data + outsize, &outsize) == 0) { 198193323Sed EVP_CIPHER_CTX_cleanup(&ctx); 199193323Sed return (EINVAL); 200193323Sed } 201193323Sed assert(outsize == 0); 202193323Sed 203193323Sed EVP_CIPHER_CTX_cleanup(&ctx); 204193323Sed return (0); 205193323Sed} 206193323Sed#endif /* !_KERNEL */ 207198090Srdivacky 208193323Sedint 209193323Sedg_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize, 210193323Sed const u_char *key, size_t keysize) 211193323Sed{ 212195340Sed 213198090Srdivacky return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize)); 214201360Srdivacky} 215201360Srdivacky 216206083Srdivackyint 217193323Sedg_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize, 218193323Sed const u_char *key, size_t keysize) 219224145Sdim{ 220224145Sdim 221193323Sed return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize)); 222193323Sed} 223193323Sed 224224145Sdimvoid 225224145Sdimg_eli_crypto_hmac_init(struct hmac_ctx *ctx, const uint8_t *hkey, 226224145Sdim size_t hkeylen) 227224145Sdim{ 228224145Sdim u_char k_ipad[128], key[128]; 229193323Sed SHA512_CTX lctx; 230224145Sdim u_int i; 231224145Sdim 232224145Sdim bzero(key, sizeof(key)); 233193323Sed if (hkeylen == 0) 234193323Sed ; /* do nothing */ 235193323Sed else if (hkeylen <= 128) 236193323Sed bcopy(hkey, key, hkeylen); 237193323Sed else { 238193323Sed /* If key is longer than 128 bytes reset it to key = SHA512(key). */ 239193323Sed SHA512_Init(&lctx); 240198892Srdivacky SHA512_Update(&lctx, hkey, hkeylen); 241198892Srdivacky SHA512_Final(key, &lctx); 242198892Srdivacky } 243198892Srdivacky 244193323Sed /* XOR key with ipad and opad values. */ 245198892Srdivacky for (i = 0; i < sizeof(key); i++) { 246193323Sed k_ipad[i] = key[i] ^ 0x36; 247193323Sed ctx->k_opad[i] = key[i] ^ 0x5c; 248193323Sed } 249193323Sed bzero(key, sizeof(key)); 250198892Srdivacky /* Perform inner SHA512. */ 251193323Sed SHA512_Init(&ctx->shactx); 252193323Sed SHA512_Update(&ctx->shactx, k_ipad, sizeof(k_ipad)); 253193323Sed} 254193323Sed 255226633Sdimvoid 256226633Sdimg_eli_crypto_hmac_update(struct hmac_ctx *ctx, const uint8_t *data, 257193323Sed size_t datasize) 258193323Sed{ 259193323Sed 260193323Sed SHA512_Update(&ctx->shactx, data, datasize); 261193323Sed} 262193323Sed 263193323Sedvoid 264193323Sedg_eli_crypto_hmac_final(struct hmac_ctx *ctx, uint8_t *md, size_t mdsize) 265193323Sed{ 266193323Sed u_char digest[SHA512_MDLEN]; 267193323Sed SHA512_CTX lctx; 268193323Sed 269193323Sed SHA512_Final(digest, &ctx->shactx); 270193323Sed /* Perform outer SHA512. */ 271193323Sed SHA512_Init(&lctx); 272193323Sed SHA512_Update(&lctx, ctx->k_opad, sizeof(ctx->k_opad)); 273193323Sed bzero(ctx, sizeof(*ctx)); 274193323Sed SHA512_Update(&lctx, digest, sizeof(digest)); 275226633Sdim SHA512_Final(digest, &lctx); 276202375Srdivacky /* mdsize == 0 means "Give me the whole hash!" */ 277193323Sed if (mdsize == 0) 278226633Sdim mdsize = SHA512_MDLEN; 279226633Sdim bcopy(digest, md, mdsize); 280224145Sdim} 281224145Sdim 282226633Sdimvoid 283193323Sedg_eli_crypto_hmac(const uint8_t *hkey, size_t hkeysize, const uint8_t *data, 284193323Sed size_t datasize, uint8_t *md, size_t mdsize) 285224145Sdim{ 286193323Sed struct hmac_ctx ctx; 287193323Sed 288224145Sdim g_eli_crypto_hmac_init(&ctx, hkey, hkeysize); 289224145Sdim g_eli_crypto_hmac_update(&ctx, data, datasize); 290224145Sdim g_eli_crypto_hmac_final(&ctx, md, mdsize); 291224145Sdim} 292193323Sed