Changeset View
Standalone View
sys/crypto/aesni/aesni.c
/*- | /*- | ||||
* Copyright (c) 2005-2008 Pawel Jakub Dawidek <pjd@FreeBSD.org> | * Copyright (c) 2005-2008 Pawel Jakub Dawidek <pjd@FreeBSD.org> | ||||
* Copyright (c) 2010 Konstantin Belousov <kib@FreeBSD.org> | * Copyright (c) 2010 Konstantin Belousov <kib@FreeBSD.org> | ||||
* Copyright (c) 2014 The FreeBSD Foundation | * Copyright (c) 2014 The FreeBSD Foundation | ||||
* Copyright (c) 2017 Conrad Meyer <cem@FreeBSD.org> | |||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Portions of this software were developed by John-Mark Gurney | * Portions of this software were developed by John-Mark Gurney | ||||
* under sponsorship of the FreeBSD Foundation and | * under sponsorship of the FreeBSD Foundation and | ||||
* Rubicon Communications, LLC (Netgate). | * Rubicon Communications, LLC (Netgate). | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
Show All 28 Lines | |||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/rwlock.h> | #include <sys/rwlock.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/uio.h> | #include <sys/uio.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <crypto/aesni/aesni.h> | #include <crypto/aesni/aesni.h> | ||||
#include <cryptodev_if.h> | #include <crypto/aesni/sha_sse.h> | ||||
#include <crypto/sha1.h> | |||||
#include <crypto/sha2/sha256.h> | |||||
#include <opencrypto/cryptodev.h> | |||||
#include <opencrypto/gmac.h> | #include <opencrypto/gmac.h> | ||||
#include <cryptodev_if.h> | |||||
#include <machine/md_var.h> | |||||
#include <machine/specialreg.h> | |||||
#if defined(__i386__) | |||||
#include <machine/npx.h> | |||||
#elif defined(__amd64__) | |||||
#include <machine/fpu.h> | |||||
#endif | |||||
static struct mtx_padalign *ctx_mtx; | static struct mtx_padalign *ctx_mtx; | ||||
static struct fpu_kern_ctx **ctx_fpu; | static struct fpu_kern_ctx **ctx_fpu; | ||||
struct aesni_softc { | struct aesni_softc { | ||||
int dieing; | int dieing; | ||||
int32_t cid; | int32_t cid; | ||||
uint32_t sid; | uint32_t sid; | ||||
bool has_aes; | |||||
bool has_sha; | |||||
TAILQ_HEAD(aesni_sessions_head, aesni_session) sessions; | TAILQ_HEAD(aesni_sessions_head, aesni_session) sessions; | ||||
struct rwlock lock; | struct rwlock lock; | ||||
}; | }; | ||||
#define ACQUIRE_CTX(i, ctx) \ | #define ACQUIRE_CTX(i, ctx) \ | ||||
do { \ | do { \ | ||||
(i) = PCPU_GET(cpuid); \ | (i) = PCPU_GET(cpuid); \ | ||||
mtx_lock(&ctx_mtx[(i)]); \ | mtx_lock(&ctx_mtx[(i)]); \ | ||||
(ctx) = ctx_fpu[(i)]; \ | (ctx) = ctx_fpu[(i)]; \ | ||||
} while (0) | } while (0) | ||||
#define RELEASE_CTX(i, ctx) \ | #define RELEASE_CTX(i, ctx) \ | ||||
do { \ | do { \ | ||||
mtx_unlock(&ctx_mtx[(i)]); \ | mtx_unlock(&ctx_mtx[(i)]); \ | ||||
(i) = -1; \ | (i) = -1; \ | ||||
(ctx) = NULL; \ | (ctx) = NULL; \ | ||||
} while (0) | } while (0) | ||||
static int aesni_newsession(device_t, uint32_t *sidp, struct cryptoini *cri); | static int aesni_newsession(device_t, uint32_t *sidp, struct cryptoini *cri); | ||||
static int aesni_freesession(device_t, uint64_t tid); | static int aesni_freesession(device_t, uint64_t tid); | ||||
static void aesni_freesession_locked(struct aesni_softc *sc, | static void aesni_freesession_locked(struct aesni_softc *sc, | ||||
struct aesni_session *ses); | struct aesni_session *ses); | ||||
static int aesni_cipher_setup(struct aesni_session *ses, | static int aesni_cipher_setup(struct aesni_session *ses, | ||||
struct cryptoini *encini); | struct cryptoini *encini, struct cryptoini *authini); | ||||
static int aesni_cipher_process(struct aesni_session *ses, | static int aesni_cipher_process(struct aesni_session *ses, | ||||
struct cryptodesc *enccrd, struct cryptodesc *authcrd, struct cryptop *crp); | struct cryptodesc *enccrd, struct cryptodesc *authcrd, struct cryptop *crp); | ||||
static int aesni_cipher_crypt(struct aesni_session *ses, | |||||
struct cryptodesc *enccrd, struct cryptodesc *authcrd, struct cryptop *crp); | |||||
static int aesni_cipher_mac(struct aesni_session *ses, struct cryptodesc *crd, | |||||
struct cryptop *crp); | |||||
MALLOC_DEFINE(M_AESNI, "aesni_data", "AESNI Data"); | MALLOC_DEFINE(M_AESNI, "aesni_data", "AESNI Data"); | ||||
static void | static void | ||||
aesni_identify(driver_t *drv, device_t parent) | aesni_identify(driver_t *drv, device_t parent) | ||||
{ | { | ||||
/* NB: order 10 is so we get attached after h/w devices */ | /* NB: order 10 is so we get attached after h/w devices */ | ||||
if (device_find_child(parent, "aesni", -1) == NULL && | if (device_find_child(parent, "aesni", -1) == NULL && | ||||
BUS_ADD_CHILD(parent, 10, "aesni", -1) == 0) | BUS_ADD_CHILD(parent, 10, "aesni", -1) == 0) | ||||
panic("aesni: could not attach"); | panic("aesni: could not attach"); | ||||
} | } | ||||
static int | static void | ||||
aesni_probe(device_t dev) | detect_cpu_features(bool *has_aes, bool *has_sha) | ||||
{ | { | ||||
if ((cpu_feature2 & CPUID2_AESNI) == 0) { | *has_aes = ((cpu_feature2 & CPUID2_AESNI) != 0 && | ||||
device_printf(dev, "No AESNI support.\n"); | (cpu_feature2 & CPUID2_SSE41) != 0); | ||||
return (EINVAL); | *has_sha = ((cpu_stdext_feature & CPUID_STDEXT_SHA) != 0 && | ||||
(cpu_feature2 & CPUID2_SSSE3) != 0); | |||||
} | } | ||||
if ((cpu_feature2 & CPUID2_SSE41) == 0) { | static int | ||||
device_printf(dev, "No SSE4.1 support.\n"); | aesni_probe(device_t dev) | ||||
return (EINVAL); | { | ||||
} | bool has_aes, has_sha; | ||||
detect_cpu_features(&has_aes, &has_sha); | |||||
if (!has_aes && !has_sha) { | |||||
device_printf(dev, "No AES or SHA support.\n"); | |||||
return (EINVAL); | |||||
} else if (has_aes && has_sha) | |||||
device_set_desc_copy(dev, | |||||
rlibby: It looks like this could be `device_set_desc` (no `_copy`) as these are string constants and it… | |||||
Not Done Inline ActionsTrue. Ideally there would be a device_set_descf() method that would take a format string and then some copy/paste here could be reduced. I'll remove _copy. cem: True. Ideally there would be a device_set_descf() method that would take a format string and… | |||||
"AES-CBC,AES-XTS,AES-GCM,AES-ICM,SHA1,SHA256"); | |||||
else if (has_aes) | |||||
device_set_desc_copy(dev, "AES-CBC,AES-XTS,AES-GCM,AES-ICM"); | device_set_desc_copy(dev, "AES-CBC,AES-XTS,AES-GCM,AES-ICM"); | ||||
else | |||||
device_set_desc_copy(dev, "SHA1,SHA256"); | |||||
Done Inline ActionsPerhaps s/SHA2/SHA256/? jhb: Perhaps s/SHA2/SHA256/? | |||||
Done Inline ActionsAh, good point. cem: Ah, good point. | |||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
aesni_cleanctx(void) | aesni_cleanctx(void) | ||||
{ | { | ||||
int i; | int i; | ||||
Show All 35 Lines | ctx_fpu = malloc(sizeof *ctx_fpu * (mp_maxid + 1), M_AESNI, | ||||
M_WAITOK|M_ZERO); | M_WAITOK|M_ZERO); | ||||
CPU_FOREACH(i) { | CPU_FOREACH(i) { | ||||
ctx_fpu[i] = fpu_kern_alloc_ctx(0); | ctx_fpu[i] = fpu_kern_alloc_ctx(0); | ||||
mtx_init(&ctx_mtx[i], "anifpumtx", NULL, MTX_DEF|MTX_NEW); | mtx_init(&ctx_mtx[i], "anifpumtx", NULL, MTX_DEF|MTX_NEW); | ||||
} | } | ||||
rw_init(&sc->lock, "aesni_lock"); | rw_init(&sc->lock, "aesni_lock"); | ||||
detect_cpu_features(&sc->has_aes, &sc->has_sha); | |||||
if (sc->has_aes) { | |||||
crypto_register(sc->cid, CRYPTO_AES_CBC, 0, 0); | crypto_register(sc->cid, CRYPTO_AES_CBC, 0, 0); | ||||
crypto_register(sc->cid, CRYPTO_AES_ICM, 0, 0); | crypto_register(sc->cid, CRYPTO_AES_ICM, 0, 0); | ||||
crypto_register(sc->cid, CRYPTO_AES_NIST_GCM_16, 0, 0); | crypto_register(sc->cid, CRYPTO_AES_NIST_GCM_16, 0, 0); | ||||
crypto_register(sc->cid, CRYPTO_AES_128_NIST_GMAC, 0, 0); | crypto_register(sc->cid, CRYPTO_AES_128_NIST_GMAC, 0, 0); | ||||
crypto_register(sc->cid, CRYPTO_AES_192_NIST_GMAC, 0, 0); | crypto_register(sc->cid, CRYPTO_AES_192_NIST_GMAC, 0, 0); | ||||
crypto_register(sc->cid, CRYPTO_AES_256_NIST_GMAC, 0, 0); | crypto_register(sc->cid, CRYPTO_AES_256_NIST_GMAC, 0, 0); | ||||
crypto_register(sc->cid, CRYPTO_AES_XTS, 0, 0); | crypto_register(sc->cid, CRYPTO_AES_XTS, 0, 0); | ||||
} | |||||
if (sc->has_sha) { | |||||
crypto_register(sc->cid, CRYPTO_SHA1, 0, 0); | |||||
crypto_register(sc->cid, CRYPTO_SHA1_HMAC, 0, 0); | |||||
crypto_register(sc->cid, CRYPTO_SHA2_256_HMAC, 0, 0); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
aesni_detach(device_t dev) | aesni_detach(device_t dev) | ||||
{ | { | ||||
struct aesni_softc *sc; | struct aesni_softc *sc; | ||||
struct aesni_session *ses; | struct aesni_session *ses; | ||||
Show All 24 Lines | aesni_detach(device_t dev) | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
aesni_newsession(device_t dev, uint32_t *sidp, struct cryptoini *cri) | aesni_newsession(device_t dev, uint32_t *sidp, struct cryptoini *cri) | ||||
{ | { | ||||
struct aesni_softc *sc; | struct aesni_softc *sc; | ||||
struct aesni_session *ses; | struct aesni_session *ses; | ||||
struct cryptoini *encini; | struct cryptoini *encini, *authini; | ||||
int error; | int error; | ||||
if (sidp == NULL || cri == NULL) { | if (sidp == NULL || cri == NULL) { | ||||
CRYPTDEB("no sidp or cri"); | CRYPTDEB("no sidp or cri"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
if (sc->dieing) | if (sc->dieing) | ||||
return (EINVAL); | return (EINVAL); | ||||
ses = NULL; | ses = NULL; | ||||
authini = NULL; | |||||
encini = NULL; | encini = NULL; | ||||
for (; cri != NULL; cri = cri->cri_next) { | for (; cri != NULL; cri = cri->cri_next) { | ||||
switch (cri->cri_alg) { | switch (cri->cri_alg) { | ||||
case CRYPTO_AES_CBC: | case CRYPTO_AES_CBC: | ||||
case CRYPTO_AES_ICM: | case CRYPTO_AES_ICM: | ||||
case CRYPTO_AES_XTS: | case CRYPTO_AES_XTS: | ||||
case CRYPTO_AES_NIST_GCM_16: | case CRYPTO_AES_NIST_GCM_16: | ||||
if (!sc->has_aes) | |||||
goto unhandled; | |||||
if (encini != NULL) { | if (encini != NULL) { | ||||
CRYPTDEB("encini already set"); | CRYPTDEB("encini already set"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
encini = cri; | encini = cri; | ||||
break; | break; | ||||
case CRYPTO_AES_128_NIST_GMAC: | case CRYPTO_AES_128_NIST_GMAC: | ||||
case CRYPTO_AES_192_NIST_GMAC: | case CRYPTO_AES_192_NIST_GMAC: | ||||
case CRYPTO_AES_256_NIST_GMAC: | case CRYPTO_AES_256_NIST_GMAC: | ||||
Done Inline ActionsShould probably do something to ensure that GMAC auth is only used with GCM cipher and vice versa. For ccr(4) I think I used a bool gcm_hash and then after walking the cri loop ensured that if gcm_hash was set, encinit was valid and was GCM, maybe something like: if (gcm_hash && (encini == NULL || encini->cipher != CRYPTO_AES_NIST_GCM_16)) return (EINVAL); if (encini != NULL && encini->cipher == CRYPTO_AES_NIST_GCM_16 && !gcm_hash) return (EINVAL); jhb: Should probably do something to ensure that GMAC auth is only used with GCM cipher and vice… | |||||
Not Done Inline ActionsWill do! cem: Will do! | |||||
/* | /* | ||||
* nothing to do here, maybe in the future cache some | * nothing to do here, maybe in the future cache some | ||||
* values for GHASH | * values for GHASH | ||||
*/ | */ | ||||
break; | break; | ||||
case CRYPTO_SHA1: | |||||
case CRYPTO_SHA1_HMAC: | |||||
case CRYPTO_SHA2_256_HMAC: | |||||
if (!sc->has_sha) | |||||
goto unhandled; | |||||
if (authini != NULL) { | |||||
CRYPTDEB("authini already set"); | |||||
return (EINVAL); | |||||
} | |||||
authini = cri; | |||||
break; | |||||
default: | default: | ||||
unhandled: | |||||
CRYPTDEB("unhandled algorithm"); | CRYPTDEB("unhandled algorithm"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
} | } | ||||
if (encini == NULL) { | if (encini == NULL && authini == NULL) { | ||||
CRYPTDEB("no cipher"); | CRYPTDEB("no cipher"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
rw_wlock(&sc->lock); | rw_wlock(&sc->lock); | ||||
if (sc->dieing) { | if (sc->dieing) { | ||||
rw_wunlock(&sc->lock); | rw_wunlock(&sc->lock); | ||||
return (EINVAL); | return (EINVAL); | ||||
Show All 11 Lines | if (ses == NULL || ses->used) { | ||||
} | } | ||||
ses->id = sc->sid++; | ses->id = sc->sid++; | ||||
} else { | } else { | ||||
TAILQ_REMOVE(&sc->sessions, ses, next); | TAILQ_REMOVE(&sc->sessions, ses, next); | ||||
} | } | ||||
ses->used = 1; | ses->used = 1; | ||||
TAILQ_INSERT_TAIL(&sc->sessions, ses, next); | TAILQ_INSERT_TAIL(&sc->sessions, ses, next); | ||||
rw_wunlock(&sc->lock); | rw_wunlock(&sc->lock); | ||||
if (encini != NULL) | |||||
ses->algo = encini->cri_alg; | ses->algo = encini->cri_alg; | ||||
if (authini != NULL) | |||||
ses->auth_algo = authini->cri_alg; | |||||
error = aesni_cipher_setup(ses, encini); | error = aesni_cipher_setup(ses, encini, authini); | ||||
if (error != 0) { | if (error != 0) { | ||||
CRYPTDEB("setup failed"); | CRYPTDEB("setup failed"); | ||||
rw_wlock(&sc->lock); | rw_wlock(&sc->lock); | ||||
aesni_freesession_locked(sc, ses); | aesni_freesession_locked(sc, ses); | ||||
rw_wunlock(&sc->lock); | rw_wunlock(&sc->lock); | ||||
return (error); | return (error); | ||||
} | } | ||||
*sidp = ses->id; | *sidp = ses->id; | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
aesni_freesession_locked(struct aesni_softc *sc, struct aesni_session *ses) | aesni_freesession_locked(struct aesni_softc *sc, struct aesni_session *ses) | ||||
{ | { | ||||
uint32_t sid; | uint32_t sid; | ||||
rw_assert(&sc->lock, RA_WLOCKED); | rw_assert(&sc->lock, RA_WLOCKED); | ||||
sid = ses->id; | sid = ses->id; | ||||
TAILQ_REMOVE(&sc->sessions, ses, next); | TAILQ_REMOVE(&sc->sessions, ses, next); | ||||
*ses = (struct aesni_session){}; | explicit_bzero(ses, sizeof(*ses)); | ||||
ses->id = sid; | ses->id = sid; | ||||
TAILQ_INSERT_HEAD(&sc->sessions, ses, next); | TAILQ_INSERT_HEAD(&sc->sessions, ses, next); | ||||
} | } | ||||
static int | static int | ||||
aesni_freesession(device_t dev, uint64_t tid) | aesni_freesession(device_t dev, uint64_t tid) | ||||
{ | { | ||||
struct aesni_softc *sc; | struct aesni_softc *sc; | ||||
Show All 35 Lines | aesni_process(device_t dev, struct cryptop *crp, int hint __unused) | ||||
if (crp->crp_callback == NULL || crp->crp_desc == NULL) { | if (crp->crp_callback == NULL || crp->crp_desc == NULL) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) { | for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) { | ||||
switch (crd->crd_alg) { | switch (crd->crd_alg) { | ||||
case CRYPTO_AES_NIST_GCM_16: | |||||
needauth = 1; | |||||
/* FALLTHROUGH */ | |||||
case CRYPTO_AES_CBC: | case CRYPTO_AES_CBC: | ||||
case CRYPTO_AES_ICM: | case CRYPTO_AES_ICM: | ||||
case CRYPTO_AES_XTS: | case CRYPTO_AES_XTS: | ||||
if (enccrd != NULL) { | if (enccrd != NULL) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
enccrd = crd; | enccrd = crd; | ||||
break; | break; | ||||
case CRYPTO_AES_NIST_GCM_16: | |||||
if (enccrd != NULL) { | |||||
error = EINVAL; | |||||
goto out; | |||||
} | |||||
enccrd = crd; | |||||
needauth = 1; | |||||
break; | |||||
case CRYPTO_AES_128_NIST_GMAC: | case CRYPTO_AES_128_NIST_GMAC: | ||||
case CRYPTO_AES_192_NIST_GMAC: | case CRYPTO_AES_192_NIST_GMAC: | ||||
case CRYPTO_AES_256_NIST_GMAC: | case CRYPTO_AES_256_NIST_GMAC: | ||||
case CRYPTO_SHA1: | |||||
case CRYPTO_SHA1_HMAC: | |||||
case CRYPTO_SHA2_256_HMAC: | |||||
if (authcrd != NULL) { | if (authcrd != NULL) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
authcrd = crd; | authcrd = crd; | ||||
needauth = 1; | |||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
} | } | ||||
if (enccrd == NULL || (needauth && authcrd == NULL)) { | if ((enccrd == NULL && authcrd == NULL) || | ||||
(needauth && authcrd == NULL)) { | |||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* CBC & XTS can only handle full blocks for now */ | /* CBC & XTS can only handle full blocks for now */ | ||||
if ((enccrd->crd_alg == CRYPTO_AES_CBC || enccrd->crd_alg == | if (enccrd != NULL && (enccrd->crd_alg == CRYPTO_AES_CBC || | ||||
CRYPTO_AES_XTS) && (enccrd->crd_len % AES_BLOCK_LEN) != 0) { | enccrd->crd_alg == CRYPTO_AES_XTS) && | ||||
(enccrd->crd_len % AES_BLOCK_LEN) != 0) { | |||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
rw_rlock(&sc->lock); | rw_rlock(&sc->lock); | ||||
TAILQ_FOREACH_REVERSE(ses, &sc->sessions, aesni_sessions_head, next) { | TAILQ_FOREACH_REVERSE(ses, &sc->sessions, aesni_sessions_head, next) { | ||||
if (ses->id == (crp->crp_sid & 0xffffffff)) | if (ses->id == (crp->crp_sid & 0xffffffff)) | ||||
break; | break; | ||||
Show All 9 Lines | if (error != 0) | ||||
goto out; | goto out; | ||||
out: | out: | ||||
crp->crp_etype = error; | crp->crp_etype = error; | ||||
crypto_done(crp); | crypto_done(crp); | ||||
return (error); | return (error); | ||||
} | } | ||||
uint8_t * | static uint8_t * | ||||
aesni_cipher_alloc(struct cryptodesc *enccrd, struct cryptop *crp, | aesni_cipher_alloc(struct cryptodesc *enccrd, struct cryptop *crp, | ||||
int *allocated) | bool *allocated) | ||||
{ | { | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct uio *uio; | struct uio *uio; | ||||
struct iovec *iov; | struct iovec *iov; | ||||
uint8_t *addr; | uint8_t *addr; | ||||
if (crp->crp_flags & CRYPTO_F_IMBUF) { | if (crp->crp_flags & CRYPTO_F_IMBUF) { | ||||
m = (struct mbuf *)crp->crp_buf; | m = (struct mbuf *)crp->crp_buf; | ||||
if (m->m_next != NULL) | if (m->m_next != NULL) | ||||
goto alloc; | goto alloc; | ||||
addr = mtod(m, uint8_t *); | addr = mtod(m, uint8_t *); | ||||
} else if (crp->crp_flags & CRYPTO_F_IOV) { | } else if (crp->crp_flags & CRYPTO_F_IOV) { | ||||
uio = (struct uio *)crp->crp_buf; | uio = (struct uio *)crp->crp_buf; | ||||
if (uio->uio_iovcnt != 1) | if (uio->uio_iovcnt != 1) | ||||
goto alloc; | goto alloc; | ||||
iov = uio->uio_iov; | iov = uio->uio_iov; | ||||
addr = (uint8_t *)iov->iov_base; | addr = (uint8_t *)iov->iov_base; | ||||
} else | } else | ||||
addr = (uint8_t *)crp->crp_buf; | addr = (uint8_t *)crp->crp_buf; | ||||
*allocated = 0; | *allocated = false; | ||||
addr += enccrd->crd_skip; | addr += enccrd->crd_skip; | ||||
return (addr); | return (addr); | ||||
alloc: | alloc: | ||||
addr = malloc(enccrd->crd_len, M_AESNI, M_NOWAIT); | addr = malloc(enccrd->crd_len, M_AESNI, M_NOWAIT); | ||||
if (addr != NULL) { | if (addr != NULL) { | ||||
*allocated = 1; | *allocated = true; | ||||
crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, | crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, | ||||
enccrd->crd_len, addr); | enccrd->crd_len, addr); | ||||
} else | } else | ||||
*allocated = 0; | *allocated = false; | ||||
return (addr); | return (addr); | ||||
} | } | ||||
static device_method_t aesni_methods[] = { | static device_method_t aesni_methods[] = { | ||||
DEVMETHOD(device_identify, aesni_identify), | DEVMETHOD(device_identify, aesni_identify), | ||||
DEVMETHOD(device_probe, aesni_probe), | DEVMETHOD(device_probe, aesni_probe), | ||||
DEVMETHOD(device_attach, aesni_attach), | DEVMETHOD(device_attach, aesni_attach), | ||||
DEVMETHOD(device_detach, aesni_detach), | DEVMETHOD(device_detach, aesni_detach), | ||||
Show All 12 Lines | |||||
}; | }; | ||||
static devclass_t aesni_devclass; | static devclass_t aesni_devclass; | ||||
DRIVER_MODULE(aesni, nexus, aesni_driver, aesni_devclass, 0, 0); | DRIVER_MODULE(aesni, nexus, aesni_driver, aesni_devclass, 0, 0); | ||||
MODULE_VERSION(aesni, 1); | MODULE_VERSION(aesni, 1); | ||||
MODULE_DEPEND(aesni, crypto, 1, 1, 1); | MODULE_DEPEND(aesni, crypto, 1, 1, 1); | ||||
static int | static int | ||||
aesni_cipher_setup(struct aesni_session *ses, struct cryptoini *encini) | aesni_cipher_setup(struct aesni_session *ses, struct cryptoini *encini, | ||||
struct cryptoini *authini) | |||||
{ | { | ||||
struct fpu_kern_ctx *ctx; | struct fpu_kern_ctx *ctx; | ||||
int error; | int kt, ctxidx, keylen, error; | ||||
int kt, ctxidx; | |||||
switch (ses->auth_algo) { | |||||
case CRYPTO_SHA1: | |||||
case CRYPTO_SHA1_HMAC: | |||||
case CRYPTO_SHA2_256_HMAC: | |||||
keylen = authini->cri_klen / 8; | |||||
rlibbyUnsubmitted Done Inline ActionsSpell 8 as CHAR_BIT and add if (authini->cri_klen % CHAR_BIT != 0) return (EINVAL), or too paranoid? rlibby: Spell `8` as `CHAR_BIT` and add `if (authini->cri_klen % CHAR_BIT != 0) return (EINVAL)`, or… | |||||
cemAuthorUnsubmitted Not Done Inline ActionsI'm not a fan of spelling 8 as CHAR_BIT, but we could add the modulus check. Some other drivers use roundup(). cem: I'm not a fan of spelling 8 as CHAR_BIT, but we could add the modulus check. Some other… | |||||
if (keylen > sizeof(ses->hmac_key)) | |||||
return (EINVAL); | |||||
if (ses->auth_algo == CRYPTO_SHA1 && keylen > 0) | |||||
return (EINVAL); | |||||
memcpy(ses->hmac_key, authini->cri_key, keylen); | |||||
ses->mlen = authini->cri_mlen; | |||||
} | |||||
kt = is_fpu_kern_thread(0); | kt = is_fpu_kern_thread(0); | ||||
if (!kt) { | if (!kt) { | ||||
ACQUIRE_CTX(ctxidx, ctx); | ACQUIRE_CTX(ctxidx, ctx); | ||||
error = fpu_kern_enter(curthread, ctx, | error = fpu_kern_enter(curthread, ctx, | ||||
FPU_KERN_NORMAL | FPU_KERN_KTHR); | FPU_KERN_NORMAL | FPU_KERN_KTHR); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
} | } | ||||
error = 0; | |||||
if (encini != NULL) | |||||
error = aesni_cipher_setup_common(ses, encini->cri_key, | error = aesni_cipher_setup_common(ses, encini->cri_key, | ||||
encini->cri_klen); | encini->cri_klen); | ||||
if (!kt) { | if (!kt) { | ||||
fpu_kern_leave(curthread, ctx); | fpu_kern_leave(curthread, ctx); | ||||
out: | out: | ||||
RELEASE_CTX(ctxidx, ctx); | RELEASE_CTX(ctxidx, ctx); | ||||
} | } | ||||
return (error); | return (error); | ||||
rlibbyUnsubmitted Done Inline ActionsSo as earlier, we don't need the fpu context for setup in the encini == NULL case. It may not be worth worrying about. rlibby: So as earlier, we don't need the fpu context for setup in the `encini == NULL` case. It may… | |||||
cemAuthorUnsubmitted Done Inline ActionsOh, true. Will fix. cem: Oh, true. Will fix. | |||||
} | } | ||||
static int | |||||
intel_sha1_update(void *vctx, const void *vdata, u_int datalen) | |||||
{ | |||||
struct sha1_ctxt *ctx = vctx; | |||||
const char *data = vdata; | |||||
size_t gaplen; | |||||
size_t gapstart; | |||||
size_t off; | |||||
size_t copysiz; | |||||
u_int blocks; | |||||
off = 0; | |||||
/* Do any aligned blocks without redundant copying. */ | |||||
if (datalen >= 64 && ctx->count % 64 == 0) { | |||||
blocks = datalen / 64; | |||||
ctx->c.b64[0] += blocks * 64 * 8; | |||||
intel_sha1_step(ctx->h.b32, data + off, blocks); | |||||
off += blocks * 64; | |||||
} | |||||
while (off < datalen) { | |||||
gapstart = ctx->count % 64; | |||||
gaplen = 64 - gapstart; | |||||
copysiz = (gaplen < datalen - off) ? gaplen : datalen - off; | |||||
bcopy(&data[off], &ctx->m.b8[gapstart], copysiz); | |||||
ctx->count += copysiz; | |||||
ctx->count %= 64; | |||||
ctx->c.b64[0] += copysiz * 8; | |||||
if (ctx->count % 64 == 0) | |||||
intel_sha1_step(ctx->h.b32, (void *)ctx->m.b8, 1); | |||||
off += copysiz; | |||||
} | |||||
return (0); | |||||
} | |||||
static void | |||||
SHA1_Finalize_fn(void *digest, void *ctx) | |||||
{ | |||||
sha1_result(ctx, digest); | |||||
} | |||||
static int | |||||
intel_sha256_update(void *vctx, const void *vdata, u_int len) | |||||
{ | |||||
SHA256_CTX *ctx = vctx; | |||||
uint64_t bitlen; | |||||
uint32_t r; | |||||
u_int blocks; | |||||
const unsigned char *src = vdata; | |||||
/* Number of bytes left in the buffer from previous updates */ | |||||
r = (ctx->count >> 3) & 0x3f; | |||||
/* Convert the length into a number of bits */ | |||||
bitlen = len << 3; | |||||
/* Update number of bits */ | |||||
ctx->count += bitlen; | |||||
/* Handle the case where we don't need to perform any transforms */ | |||||
if (len < 64 - r) { | |||||
memcpy(&ctx->buf[r], src, len); | |||||
return (0); | |||||
} | |||||
/* Finish the current block */ | |||||
memcpy(&ctx->buf[r], src, 64 - r); | |||||
intel_sha256_step(ctx->state, ctx->buf, 1); | |||||
src += 64 - r; | |||||
len -= 64 - r; | |||||
/* Perform complete blocks */ | |||||
if (len >= 64) { | |||||
blocks = len / 64; | |||||
intel_sha256_step(ctx->state, src, blocks); | |||||
src += blocks * 64; | |||||
len -= blocks * 64; | |||||
} | |||||
/* Copy left over data into buffer */ | |||||
memcpy(ctx->buf, src, len); | |||||
return (0); | |||||
} | |||||
static void | |||||
SHA256_Finalize_fn(void *digest, void *ctx) | |||||
{ | |||||
SHA256_Final(digest, ctx); | |||||
} | |||||
/* | /* | ||||
* authcrd contains the associated date. | * Compute the HASH( (key ^ xorbyte) || buf ) | ||||
*/ | */ | ||||
static void | |||||
hmac_internal(void *ctx, uint32_t *res, | |||||
int (*update)(void *, const void *, u_int), | |||||
void (*finalize)(void *, void *), uint8_t *key, uint8_t xorbyte, | |||||
const void *buf, size_t off, size_t buflen, int crpflags) | |||||
{ | |||||
size_t i; | |||||
for (i = 0; i < 64; i++) | |||||
key[i] ^= xorbyte; | |||||
update(ctx, key, 64); | |||||
for (i = 0; i < 64; i++) | |||||
key[i] ^= xorbyte; | |||||
crypto_apply(crpflags, __DECONST(void *, buf), off, buflen, | |||||
__DECONST(int (*)(void *, void *, u_int), update), ctx); | |||||
finalize(res, ctx); | |||||
} | |||||
static int | static int | ||||
aesni_cipher_process(struct aesni_session *ses, struct cryptodesc *enccrd, | aesni_cipher_process(struct aesni_session *ses, struct cryptodesc *enccrd, | ||||
struct cryptodesc *authcrd, struct cryptop *crp) | struct cryptodesc *authcrd, struct cryptop *crp) | ||||
{ | { | ||||
struct fpu_kern_ctx *ctx; | struct fpu_kern_ctx *ctx; | ||||
uint8_t iv[AES_BLOCK_LEN]; | int error, ctxidx; | ||||
uint8_t tag[GMAC_DIGEST_LEN]; | bool kt; | ||||
uint8_t *buf, *authbuf; | |||||
int error, allocated, authallocated; | |||||
int ivlen, encflag; | |||||
int kt, ctxidx; | |||||
encflag = (enccrd->crd_flags & CRD_F_ENCRYPT) == CRD_F_ENCRYPT; | if (enccrd != NULL) { | ||||
if ((enccrd->crd_alg == CRYPTO_AES_ICM || | if ((enccrd->crd_alg == CRYPTO_AES_ICM || | ||||
enccrd->crd_alg == CRYPTO_AES_NIST_GCM_16) && | enccrd->crd_alg == CRYPTO_AES_NIST_GCM_16) && | ||||
(enccrd->crd_flags & CRD_F_IV_EXPLICIT) == 0) | (enccrd->crd_flags & CRD_F_IV_EXPLICIT) == 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
buf = aesni_cipher_alloc(enccrd, crp, &allocated); | |||||
if (buf == NULL) | |||||
return (ENOMEM); | |||||
error = 0; | |||||
authbuf = NULL; | |||||
authallocated = 0; | |||||
if (authcrd != NULL) { | |||||
authbuf = aesni_cipher_alloc(authcrd, crp, &authallocated); | |||||
if (authbuf == NULL) { | |||||
error = ENOMEM; | |||||
goto out1; | |||||
} | } | ||||
} | |||||
error = 0; | |||||
kt = is_fpu_kern_thread(0); | kt = is_fpu_kern_thread(0); | ||||
if (!kt) { | if (!kt) { | ||||
ACQUIRE_CTX(ctxidx, ctx); | ACQUIRE_CTX(ctxidx, ctx); | ||||
error = fpu_kern_enter(curthread, ctx, | error = fpu_kern_enter(curthread, ctx, | ||||
FPU_KERN_NORMAL|FPU_KERN_KTHR); | FPU_KERN_NORMAL | FPU_KERN_KTHR); | ||||
if (error != 0) | if (error != 0) | ||||
goto out2; | goto out2; | ||||
} | } | ||||
/* Do work */ | |||||
if (enccrd != NULL && authcrd != NULL) { | |||||
/* Perform the first operation */ | |||||
if (crp->crp_desc == enccrd) | |||||
error = aesni_cipher_crypt(ses, enccrd, authcrd, crp); | |||||
else | |||||
error = aesni_cipher_mac(ses, authcrd, crp); | |||||
if (error != 0) | |||||
goto out; | |||||
/* Perform the second operation */ | |||||
if (crp->crp_desc == enccrd) | |||||
error = aesni_cipher_mac(ses, authcrd, crp); | |||||
else | |||||
error = aesni_cipher_crypt(ses, enccrd, authcrd, crp); | |||||
} else if (enccrd != NULL) | |||||
error = aesni_cipher_crypt(ses, enccrd, authcrd, crp); | |||||
else | |||||
error = aesni_cipher_mac(ses, authcrd, crp); | |||||
if (error != 0) | |||||
goto out; | |||||
out: | |||||
if (!kt) { | |||||
fpu_kern_leave(curthread, ctx); | |||||
out2: | |||||
RELEASE_CTX(ctxidx, ctx); | |||||
} | |||||
return (error); | |||||
} | |||||
static int | |||||
aesni_cipher_crypt(struct aesni_session *ses, struct cryptodesc *enccrd, | |||||
struct cryptodesc *authcrd, struct cryptop *crp) | |||||
{ | |||||
uint8_t iv[AES_BLOCK_LEN], tag[GMAC_DIGEST_LEN], *buf, *authbuf; | |||||
int error, ivlen; | |||||
bool encflag, allocated, authallocated; | |||||
buf = aesni_cipher_alloc(enccrd, crp, &allocated); | |||||
if (buf == NULL) | |||||
return (ENOMEM); | |||||
authallocated = false; | |||||
if (ses->algo == CRYPTO_AES_NIST_GCM_16 && authcrd != NULL) { | |||||
authbuf = aesni_cipher_alloc(authcrd, crp, &authallocated); | |||||
if (authbuf == NULL) { | |||||
error = ENOMEM; | |||||
goto out; | |||||
} | |||||
} | |||||
error = 0; | |||||
encflag = (enccrd->crd_flags & CRD_F_ENCRYPT) == CRD_F_ENCRYPT; | |||||
if ((enccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) { | if ((enccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) { | ||||
error = aesni_cipher_setup_common(ses, enccrd->crd_key, | error = aesni_cipher_setup_common(ses, enccrd->crd_key, | ||||
enccrd->crd_klen); | enccrd->crd_klen); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
} | } | ||||
/* XXX - validate that enccrd and authcrd have/use same key? */ | |||||
switch (enccrd->crd_alg) { | switch (enccrd->crd_alg) { | ||||
case CRYPTO_AES_CBC: | case CRYPTO_AES_CBC: | ||||
case CRYPTO_AES_ICM: | case CRYPTO_AES_ICM: | ||||
ivlen = AES_BLOCK_LEN; | ivlen = AES_BLOCK_LEN; | ||||
break; | break; | ||||
case CRYPTO_AES_XTS: | case CRYPTO_AES_XTS: | ||||
ivlen = 8; | ivlen = 8; | ||||
break; | break; | ||||
Show All 15 Lines | aesni_cipher_crypt(struct aesni_session *ses, struct cryptodesc *enccrd, | ||||
} else { | } else { | ||||
if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) | if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) | ||||
bcopy(enccrd->crd_iv, iv, ivlen); | bcopy(enccrd->crd_iv, iv, ivlen); | ||||
else | else | ||||
crypto_copydata(crp->crp_flags, crp->crp_buf, | crypto_copydata(crp->crp_flags, crp->crp_buf, | ||||
enccrd->crd_inject, ivlen, iv); | enccrd->crd_inject, ivlen, iv); | ||||
} | } | ||||
if (authcrd != NULL && !encflag) | if (authcrd != NULL && !encflag) | ||||
Done Inline ActionsThis block probably needs to be GCM-only jhb: This block probably needs to be GCM-only | |||||
crypto_copydata(crp->crp_flags, crp->crp_buf, | crypto_copydata(crp->crp_flags, crp->crp_buf, | ||||
authcrd->crd_inject, GMAC_DIGEST_LEN, tag); | authcrd->crd_inject, GMAC_DIGEST_LEN, tag); | ||||
else | else | ||||
bzero(tag, sizeof tag); | bzero(tag, sizeof tag); | ||||
/* Do work */ | |||||
switch (ses->algo) { | switch (ses->algo) { | ||||
case CRYPTO_AES_CBC: | case CRYPTO_AES_CBC: | ||||
if (encflag) | if (encflag) | ||||
aesni_encrypt_cbc(ses->rounds, ses->enc_schedule, | aesni_encrypt_cbc(ses->rounds, ses->enc_schedule, | ||||
enccrd->crd_len, buf, buf, iv); | enccrd->crd_len, buf, buf, iv); | ||||
else | else | ||||
aesni_decrypt_cbc(ses->rounds, ses->dec_schedule, | aesni_decrypt_cbc(ses->rounds, ses->dec_schedule, | ||||
enccrd->crd_len, buf, iv); | enccrd->crd_len, buf, iv); | ||||
break; | break; | ||||
case CRYPTO_AES_ICM: | case CRYPTO_AES_ICM: | ||||
/* encryption & decryption are the same */ | /* encryption & decryption are the same */ | ||||
aesni_encrypt_icm(ses->rounds, ses->enc_schedule, | aesni_encrypt_icm(ses->rounds, ses->enc_schedule, | ||||
enccrd->crd_len, buf, buf, iv); | enccrd->crd_len, buf, buf, iv); | ||||
break; | break; | ||||
case CRYPTO_AES_XTS: | case CRYPTO_AES_XTS: | ||||
if (encflag) | if (encflag) | ||||
aesni_encrypt_xts(ses->rounds, ses->enc_schedule, | aesni_encrypt_xts(ses->rounds, ses->enc_schedule, | ||||
ses->xts_schedule, enccrd->crd_len, buf, buf, | ses->xts_schedule, enccrd->crd_len, buf, buf, | ||||
iv); | iv); | ||||
else | else | ||||
aesni_decrypt_xts(ses->rounds, ses->dec_schedule, | aesni_decrypt_xts(ses->rounds, ses->dec_schedule, | ||||
ses->xts_schedule, enccrd->crd_len, buf, buf, | ses->xts_schedule, enccrd->crd_len, buf, buf, | ||||
iv); | iv); | ||||
break; | break; | ||||
case CRYPTO_AES_NIST_GCM_16: | case CRYPTO_AES_NIST_GCM_16: | ||||
Done Inline ActionsYou could move it into the 'case' here. jhb: You could move it into the 'case' here. | |||||
if (encflag) | if (encflag) { | ||||
AES_GCM_encrypt(buf, buf, authbuf, iv, tag, | AES_GCM_encrypt(buf, buf, authbuf, iv, tag, | ||||
enccrd->crd_len, authcrd->crd_len, ivlen, | enccrd->crd_len, authcrd->crd_len, ivlen, | ||||
ses->enc_schedule, ses->rounds); | ses->enc_schedule, ses->rounds); | ||||
else { | |||||
if (authcrd != NULL) | |||||
crypto_copyback(crp->crp_flags, crp->crp_buf, | |||||
authcrd->crd_inject, GMAC_DIGEST_LEN, tag); | |||||
} else { | |||||
if (!AES_GCM_decrypt(buf, buf, authbuf, iv, tag, | if (!AES_GCM_decrypt(buf, buf, authbuf, iv, tag, | ||||
enccrd->crd_len, authcrd->crd_len, ivlen, | enccrd->crd_len, authcrd->crd_len, ivlen, | ||||
ses->enc_schedule, ses->rounds)) | ses->enc_schedule, ses->rounds)) | ||||
error = EBADMSG; | error = EBADMSG; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
if (allocated) | |||||
crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, | |||||
enccrd->crd_len, buf); | |||||
if (!error && authcrd != NULL) { | |||||
crypto_copyback(crp->crp_flags, crp->crp_buf, | |||||
authcrd->crd_inject, GMAC_DIGEST_LEN, tag); | |||||
} | |||||
out: | out: | ||||
if (!kt) { | |||||
fpu_kern_leave(curthread, ctx); | |||||
out2: | |||||
RELEASE_CTX(ctxidx, ctx); | |||||
} | |||||
out1: | |||||
if (allocated) { | if (allocated) { | ||||
bzero(buf, enccrd->crd_len); | explicit_bzero(buf, enccrd->crd_len); | ||||
free(buf, M_AESNI); | free(buf, M_AESNI); | ||||
} | } | ||||
if (authallocated) | if (authallocated) { | ||||
explicit_bzero(authbuf, authcrd->crd_len); | |||||
free(authbuf, M_AESNI); | free(authbuf, M_AESNI); | ||||
} | |||||
return (error); | return (error); | ||||
} | |||||
static int | |||||
aesni_cipher_mac(struct aesni_session *ses, struct cryptodesc *crd, | |||||
struct cryptop *crp) | |||||
{ | |||||
union { | |||||
struct SHA256Context sha2 __aligned(16); | |||||
struct sha1_ctxt sha1 __aligned(16); | |||||
} sctx; | |||||
uint32_t res[SHA2_256_HASH_LEN / sizeof(uint32_t)]; | |||||
rlibbyUnsubmitted Not Done Inline ActionsMaybe better spelled howmany(MAX(SHA1_HASH_LEN, SHA2_256_HASH_LEN), sizeof(uint32_t)). rlibby: Maybe better spelled `howmany(MAX(SHA1_HASH_LEN, SHA2_256_HASH_LEN), sizeof(uint32_t))`. | |||||
cemAuthorUnsubmitted Not Done Inline ActionsI mean, these numbers are written in stone. I am not worried about either HASH_LEN changing or becoming not an even multiple of 4 bytes. I chose this way of writing it just because it is slightly less magical than "8." cem: I mean, these numbers are written in stone. I am not worried about either HASH_LEN changing or… | |||||
int hashlen; | |||||
if (crd->crd_flags != 0) | |||||
return (EINVAL); | |||||
switch (ses->auth_algo) { | |||||
case CRYPTO_SHA1_HMAC: | |||||
hashlen = SHA1_HASH_LEN; | |||||
/* Inner hash: (K ^ IPAD) || data */ | |||||
sha1_init(&sctx.sha1); | |||||
hmac_internal(&sctx.sha1, res, intel_sha1_update, | |||||
SHA1_Finalize_fn, ses->hmac_key, 0x36, crp->crp_buf, | |||||
crd->crd_skip, crd->crd_len, crp->crp_flags); | |||||
/* Outer hash: (K ^ OPAD) || inner hash */ | |||||
sha1_init(&sctx.sha1); | |||||
hmac_internal(&sctx.sha1, res, intel_sha1_update, | |||||
SHA1_Finalize_fn, ses->hmac_key, 0x5C, res, 0, hashlen, 0); | |||||
break; | |||||
case CRYPTO_SHA1: | |||||
hashlen = SHA1_HASH_LEN; | |||||
sha1_init(&sctx.sha1); | |||||
crypto_apply(crp->crp_flags, crp->crp_buf, crd->crd_skip, | |||||
crd->crd_len, __DECONST(int (*)(void *, void *, u_int), | |||||
intel_sha1_update), &sctx.sha1); | |||||
sha1_result(&sctx.sha1, (void *)res); | |||||
break; | |||||
case CRYPTO_SHA2_256_HMAC: | |||||
hashlen = SHA2_256_HASH_LEN; | |||||
/* Inner hash: (K ^ IPAD) || data */ | |||||
SHA256_Init(&sctx.sha2); | |||||
hmac_internal(&sctx.sha2, res, intel_sha256_update, | |||||
SHA256_Finalize_fn, ses->hmac_key, 0x36, crp->crp_buf, | |||||
crd->crd_skip, crd->crd_len, crp->crp_flags); | |||||
/* Outer hash: (K ^ OPAD) || inner hash */ | |||||
SHA256_Init(&sctx.sha2); | |||||
hmac_internal(&sctx.sha2, res, intel_sha256_update, | |||||
SHA256_Finalize_fn, ses->hmac_key, 0x5C, res, 0, hashlen, | |||||
0); | |||||
break; | |||||
default: | |||||
/* | |||||
* AES-GMAC authentication is verified while processing the | |||||
* enccrd | |||||
*/ | |||||
return (0); | |||||
} | |||||
if (ses->mlen != 0 && ses->mlen < hashlen) | |||||
hashlen = ses->mlen; | |||||
crypto_copyback(crp->crp_flags, crp->crp_buf, crd->crd_inject, hashlen, | |||||
(void *)res); | |||||
return (0); | |||||
} | } |
It looks like this could be device_set_desc (no _copy) as these are string constants and it doesn't look like they are ever mutated. Not new though.