/*
 * 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;
}
Ejemplo n.º 2
0
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);
}