Changeset View
Changeset View
Standalone View
Standalone View
sys/geom/eli/g_eli_hmac.c
- This file was copied from sys/geom/eli/g_eli_crypto.c.
Show All 37 Lines | |||||
#include <strings.h> | #include <strings.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <assert.h> | #include <assert.h> | ||||
#include <openssl/evp.h> | #include <openssl/evp.h> | ||||
#define _OpenSSL_ | #define _OpenSSL_ | ||||
#endif | #endif | ||||
#include <geom/eli/g_eli.h> | #include <geom/eli/g_eli.h> | ||||
#ifdef _KERNEL | |||||
MALLOC_DECLARE(M_ELI); | |||||
static int | |||||
g_eli_crypto_done(struct cryptop *crp) | |||||
{ | |||||
crp->crp_opaque = (void *)crp; | |||||
wakeup(crp); | |||||
return (0); | |||||
} | |||||
static int | |||||
g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, | |||||
const u_char *key, size_t keysize) | |||||
{ | |||||
struct cryptoini cri; | |||||
struct cryptop *crp; | |||||
struct cryptodesc *crd; | |||||
uint64_t sid; | |||||
u_char *p; | |||||
int error; | |||||
KASSERT(algo != CRYPTO_AES_XTS, | |||||
("%s: CRYPTO_AES_XTS unexpected here", __func__)); | |||||
bzero(&cri, sizeof(cri)); | |||||
cri.cri_alg = algo; | |||||
cri.cri_key = __DECONST(void *, key); | |||||
cri.cri_klen = keysize; | |||||
error = crypto_newsession(&sid, &cri, CRYPTOCAP_F_SOFTWARE); | |||||
if (error != 0) | |||||
return (error); | |||||
p = malloc(sizeof(*crp) + sizeof(*crd), M_ELI, M_NOWAIT | M_ZERO); | |||||
if (p == NULL) { | |||||
crypto_freesession(sid); | |||||
return (ENOMEM); | |||||
} | |||||
crp = (struct cryptop *)p; p += sizeof(*crp); | |||||
crd = (struct cryptodesc *)p; p += sizeof(*crd); | |||||
crd->crd_skip = 0; | |||||
crd->crd_len = datasize; | |||||
crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; | |||||
if (enc) | |||||
crd->crd_flags |= CRD_F_ENCRYPT; | |||||
crd->crd_alg = algo; | |||||
crd->crd_key = __DECONST(void *, key); | |||||
crd->crd_klen = keysize; | |||||
bzero(crd->crd_iv, sizeof(crd->crd_iv)); | |||||
crd->crd_next = NULL; | |||||
crp->crp_sid = sid; | |||||
crp->crp_ilen = datasize; | |||||
crp->crp_olen = datasize; | |||||
crp->crp_opaque = NULL; | |||||
crp->crp_callback = g_eli_crypto_done; | |||||
crp->crp_buf = (void *)data; | |||||
crp->crp_flags = CRYPTO_F_CBIFSYNC; | |||||
crp->crp_desc = crd; | |||||
error = crypto_dispatch(crp); | |||||
if (error == 0) { | |||||
while (crp->crp_opaque == NULL) | |||||
tsleep(crp, PRIBIO, "geli", hz / 5); | |||||
error = crp->crp_etype; | |||||
} | |||||
free(crp, M_ELI); | |||||
crypto_freesession(sid); | |||||
return (error); | |||||
} | |||||
#else /* !_KERNEL */ | |||||
static int | |||||
g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, | |||||
const u_char *key, size_t keysize) | |||||
{ | |||||
EVP_CIPHER_CTX ctx; | |||||
const EVP_CIPHER *type; | |||||
u_char iv[keysize]; | |||||
int outsize; | |||||
assert(algo != CRYPTO_AES_XTS); | |||||
switch (algo) { | |||||
case CRYPTO_NULL_CBC: | |||||
type = EVP_enc_null(); | |||||
break; | |||||
case CRYPTO_AES_CBC: | |||||
switch (keysize) { | |||||
case 128: | |||||
type = EVP_aes_128_cbc(); | |||||
break; | |||||
case 192: | |||||
type = EVP_aes_192_cbc(); | |||||
break; | |||||
case 256: | |||||
type = EVP_aes_256_cbc(); | |||||
break; | |||||
default: | |||||
return (EINVAL); | |||||
} | |||||
break; | |||||
case CRYPTO_BLF_CBC: | |||||
type = EVP_bf_cbc(); | |||||
break; | |||||
#ifndef OPENSSL_NO_CAMELLIA | |||||
case CRYPTO_CAMELLIA_CBC: | |||||
switch (keysize) { | |||||
case 128: | |||||
type = EVP_camellia_128_cbc(); | |||||
break; | |||||
case 192: | |||||
type = EVP_camellia_192_cbc(); | |||||
break; | |||||
case 256: | |||||
type = EVP_camellia_256_cbc(); | |||||
break; | |||||
default: | |||||
return (EINVAL); | |||||
} | |||||
break; | |||||
#endif | |||||
case CRYPTO_3DES_CBC: | |||||
type = EVP_des_ede3_cbc(); | |||||
break; | |||||
default: | |||||
return (EINVAL); | |||||
} | |||||
EVP_CIPHER_CTX_init(&ctx); | |||||
EVP_CipherInit_ex(&ctx, type, NULL, NULL, NULL, enc); | |||||
EVP_CIPHER_CTX_set_key_length(&ctx, keysize / 8); | |||||
EVP_CIPHER_CTX_set_padding(&ctx, 0); | |||||
bzero(iv, sizeof(iv)); | |||||
EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, enc); | |||||
if (EVP_CipherUpdate(&ctx, data, &outsize, data, datasize) == 0) { | |||||
EVP_CIPHER_CTX_cleanup(&ctx); | |||||
return (EINVAL); | |||||
} | |||||
assert(outsize == (int)datasize); | |||||
if (EVP_CipherFinal_ex(&ctx, data + outsize, &outsize) == 0) { | |||||
EVP_CIPHER_CTX_cleanup(&ctx); | |||||
return (EINVAL); | |||||
} | |||||
assert(outsize == 0); | |||||
EVP_CIPHER_CTX_cleanup(&ctx); | |||||
return (0); | |||||
} | |||||
#endif /* !_KERNEL */ | |||||
int | |||||
g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize, | |||||
const u_char *key, size_t keysize) | |||||
{ | |||||
/* We prefer AES-CBC for metadata protection. */ | |||||
if (algo == CRYPTO_AES_XTS) | |||||
algo = CRYPTO_AES_CBC; | |||||
return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize)); | |||||
} | |||||
int | |||||
g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize, | |||||
const u_char *key, size_t keysize) | |||||
{ | |||||
/* We prefer AES-CBC for metadata protection. */ | |||||
if (algo == CRYPTO_AES_XTS) | |||||
algo = CRYPTO_AES_CBC; | |||||
return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize)); | |||||
} | |||||
void | void | ||||
g_eli_crypto_hmac_init(struct hmac_ctx *ctx, const uint8_t *hkey, | g_eli_crypto_hmac_init(struct hmac_ctx *ctx, const uint8_t *hkey, | ||||
size_t hkeylen) | size_t hkeylen) | ||||
{ | { | ||||
u_char k_ipad[128], key[128]; | u_char k_ipad[128], key[128]; | ||||
SHA512_CTX lctx; | SHA512_CTX lctx; | ||||
u_int i; | u_int i; | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
g_eli_crypto_hmac(const uint8_t *hkey, size_t hkeysize, const uint8_t *data, | g_eli_crypto_hmac(const uint8_t *hkey, size_t hkeysize, const uint8_t *data, | ||||
size_t datasize, uint8_t *md, size_t mdsize) | size_t datasize, uint8_t *md, size_t mdsize) | ||||
{ | { | ||||
struct hmac_ctx ctx; | struct hmac_ctx ctx; | ||||
g_eli_crypto_hmac_init(&ctx, hkey, hkeysize); | g_eli_crypto_hmac_init(&ctx, hkey, hkeysize); | ||||
g_eli_crypto_hmac_update(&ctx, data, datasize); | g_eli_crypto_hmac_update(&ctx, data, datasize); | ||||
g_eli_crypto_hmac_final(&ctx, md, mdsize); | g_eli_crypto_hmac_final(&ctx, md, mdsize); | ||||
} | |||||
/* | |||||
* Here we generate IV. It is unique for every sector. | |||||
*/ | |||||
void | |||||
g_eli_crypto_ivgen(struct g_eli_softc *sc, off_t offset, u_char *iv, | |||||
size_t size) | |||||
{ | |||||
uint8_t off[8]; | |||||
if ((sc->sc_flags & G_ELI_FLAG_NATIVE_BYTE_ORDER) != 0) | |||||
bcopy(&offset, off, sizeof(off)); | |||||
else | |||||
le64enc(off, (uint64_t)offset); | |||||
switch (sc->sc_ealgo) { | |||||
case CRYPTO_AES_XTS: | |||||
bcopy(off, iv, sizeof(off)); | |||||
bzero(iv + sizeof(off), size - sizeof(off)); | |||||
break; | |||||
default: | |||||
{ | |||||
u_char hash[SHA256_DIGEST_LENGTH]; | |||||
SHA256_CTX ctx; | |||||
/* Copy precalculated SHA256 context for IV-Key. */ | |||||
bcopy(&sc->sc_ivctx, &ctx, sizeof(ctx)); | |||||
SHA256_Update(&ctx, off, sizeof(off)); | |||||
SHA256_Final(hash, &ctx); | |||||
bcopy(hash, iv, MIN(sizeof(hash), size)); | |||||
break; | |||||
} | |||||
} | |||||
} | } |