/* * Fill the buffer with as much entropy as we can. Return true if it * has full entropy and false if not. */ static bool rndpool_extract(void *buffer, size_t bytes) { const size_t extracted = rnd_extract_data(buffer, bytes, RND_EXTRACT_GOOD); if (extracted < bytes) { (void)rnd_extract_data((uint8_t *)buffer + extracted, bytes - extracted, RND_EXTRACT_ANY); mutex_spin_enter(&rndpool_mtx); rnd_getmore(bytes - extracted); mutex_spin_exit(&rndpool_mtx); return false; } return true; }
int via_padlock_crypto_newsession(void *arg, uint32_t *sidp, struct cryptoini *cri) { struct cryptoini *c; struct via_padlock_softc *sc = arg; struct via_padlock_session *ses = NULL; const struct swcr_auth_hash *axf; struct swcr_data *swd; int sesn, i, cw0; KASSERT(sc != NULL /*, ("via_padlock_crypto_freesession: null softc")*/); if (sc == NULL || sidp == NULL || cri == NULL) return (EINVAL); if (sc->sc_sessions == NULL) { ses = sc->sc_sessions = malloc(sizeof(*ses), M_DEVBUF, M_NOWAIT); if (ses == NULL) return (ENOMEM); sesn = 0; sc->sc_nsessions = 1; } else { for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { if (sc->sc_sessions[sesn].ses_used == 0) { ses = &sc->sc_sessions[sesn]; break; } } if (ses == NULL) { sesn = sc->sc_nsessions; ses = malloc((sesn + 1) * sizeof(*ses), M_DEVBUF, M_NOWAIT); if (ses == NULL) return (ENOMEM); memcpy(ses, sc->sc_sessions, sesn * sizeof(*ses)); memset(sc->sc_sessions, 0, sesn * sizeof(*ses)); free(sc->sc_sessions, M_DEVBUF); sc->sc_sessions = ses; ses = &sc->sc_sessions[sesn]; sc->sc_nsessions++; } } memset(ses, 0, sizeof(*ses)); ses->ses_used = 1; for (c = cri; c != NULL; c = c->cri_next) { switch (c->cri_alg) { case CRYPTO_AES_CBC: switch (c->cri_klen) { case 128: cw0 = C3_CRYPT_CWLO_KEY128; break; case 192: cw0 = C3_CRYPT_CWLO_KEY192; break; case 256: cw0 = C3_CRYPT_CWLO_KEY256; break; default: return (EINVAL); } cw0 |= C3_CRYPT_CWLO_ALG_AES | C3_CRYPT_CWLO_KEYGEN_SW | C3_CRYPT_CWLO_NORMAL; #ifdef __NetBSD__ rnd_extract_data(ses->ses_iv, sizeof(ses->ses_iv), RND_EXTRACT_ANY); #else get_random_bytes(ses->ses_iv, sizeof(ses->ses_iv)); #endif ses->ses_klen = c->cri_klen; ses->ses_cw0 = cw0; /* Build expanded keys for both directions */ rijndaelKeySetupEnc(ses->ses_ekey, c->cri_key, c->cri_klen); rijndaelKeySetupDec(ses->ses_dkey, c->cri_key, c->cri_klen); for (i = 0; i < 4 * (RIJNDAEL_MAXNR + 1); i++) { ses->ses_ekey[i] = ntohl(ses->ses_ekey[i]); ses->ses_dkey[i] = ntohl(ses->ses_dkey[i]); } break; /* Use hashing implementations from the cryptosoft code. */ case CRYPTO_MD5_HMAC: axf = &swcr_auth_hash_hmac_md5; goto authcommon; case CRYPTO_MD5_HMAC_96: axf = &swcr_auth_hash_hmac_md5_96; goto authcommon; case CRYPTO_SHA1_HMAC: axf = &swcr_auth_hash_hmac_sha1; goto authcommon; case CRYPTO_SHA1_HMAC_96: axf = &swcr_auth_hash_hmac_sha1_96; goto authcommon; case CRYPTO_RIPEMD160_HMAC: axf = &swcr_auth_hash_hmac_ripemd_160; goto authcommon; case CRYPTO_RIPEMD160_HMAC_96: axf = &swcr_auth_hash_hmac_ripemd_160_96; goto authcommon; case CRYPTO_SHA2_HMAC: if (cri->cri_klen == 256) axf = &swcr_auth_hash_hmac_sha2_256; else if (cri->cri_klen == 384) axf = &swcr_auth_hash_hmac_sha2_384; else if (cri->cri_klen == 512) axf = &swcr_auth_hash_hmac_sha2_512; else { return EINVAL; } authcommon: MALLOC(swd, struct swcr_data *, sizeof(struct swcr_data), M_CRYPTO_DATA, M_NOWAIT); if (swd == NULL) { via_padlock_crypto_freesession(sc, sesn); return (ENOMEM); } memset(swd, 0, sizeof(struct swcr_data)); ses->swd = swd; swd->sw_ictx = malloc(axf->auth_hash->ctxsize, M_CRYPTO_DATA, M_NOWAIT); if (swd->sw_ictx == NULL) { via_padlock_crypto_freesession(sc, sesn); return (ENOMEM); } swd->sw_octx = malloc(axf->auth_hash->ctxsize, M_CRYPTO_DATA, M_NOWAIT); if (swd->sw_octx == NULL) { via_padlock_crypto_freesession(sc, sesn); return (ENOMEM); } for (i = 0; i < c->cri_klen / 8; i++) c->cri_key[i] ^= HMAC_IPAD_VAL; axf->Init(swd->sw_ictx); axf->Update(swd->sw_ictx, c->cri_key, c->cri_klen / 8); axf->Update(swd->sw_ictx, hmac_ipad_buffer, HMAC_BLOCK_LEN - (c->cri_klen / 8)); for (i = 0; i < c->cri_klen / 8; i++) c->cri_key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL); axf->Init(swd->sw_octx); axf->Update(swd->sw_octx, c->cri_key, c->cri_klen / 8); axf->Update(swd->sw_octx, hmac_opad_buffer, HMAC_BLOCK_LEN - (c->cri_klen / 8)); for (i = 0; i < c->cri_klen / 8; i++) c->cri_key[i] ^= HMAC_OPAD_VAL; swd->sw_axf = axf; swd->sw_alg = c->cri_alg; break; default: return (EINVAL); } } *sidp = VIAC3_SID(0, sesn); return (0); }