Exemplo n.º 1
0
/*
 * zcrypt_key_lookup
 *
 * This function looks up the key we need based on the bookmark.
 * It returns a reference to the key that the caller should NOT free.
 * The caller should use zcrypt_key_hold/release()
 * On failure it returns NULL;
 */
zcrypt_key_t *
zcrypt_key_lookup(spa_t *spa, uint64_t objset, uint64_t txg)
{
	zcrypt_keystore_node_t *skn;
	zcrypt_keychain_node_t *dkn;
	crypto_mechanism_t mech = { 0 };
	zcrypt_key_t *key;

#if _KERNEL
    printk("zcrypt_key_lookup enter\n");
#endif

	skn = zcrypt_keystore_find_node(spa, objset, B_FALSE);
	if (skn == NULL)
		return (NULL);

	/* ZIL writes use txg 0 but we want the latest key */
	if (txg == 0)
		txg = -1UL;
	mutex_enter(&skn->skn_lock);
	dkn = zcrypt_keychain_find(skn->skn_keychain, txg);
	if (dkn == NULL) {
		mutex_exit(&skn->skn_lock);
		return (NULL);
	}
	key = dkn->dkn_key;
	if (key != NULL && !key->zk_ctx_tmpl_valid) {
		mech.cm_type = crypto_mech2id(
		    zio_crypt_table[key->zk_crypt].ci_mechname);
		if (crypto_create_ctx_template(&mech, &key->zk_key,
		    &key->zk_ctx_tmpl, KM_SLEEP) == CRYPTO_SUCCESS)
			key->zk_ctx_tmpl_valid = B_TRUE;
	}
	if (key != NULL && !key->zk_mac_ctx_tmpl_valid) {
		mech.cm_type = crypto_mech2id(SUN_CKM_SHA256_HMAC_GENERAL);
		if (crypto_create_ctx_template(&mech, &key->zk_mackey,
		    &key->zk_mac_ctx_tmpl, KM_SLEEP) == CRYPTO_SUCCESS)
			key->zk_mac_ctx_tmpl_valid = B_TRUE;
	}
	mutex_exit(&skn->skn_lock);

#if _KERNEL
    printk("zcrypt_key_lookup exit: key %p\n", key);
#endif
	return (key);
}
Exemplo n.º 2
0
int
smb_md5_getmech(smb_sign_mech_t *mech)
{
	crypto_mech_type_t t;

	t = crypto_mech2id(SUN_CKM_MD5);
	if (t == CRYPTO_MECH_INVALID)
		return (-1);
	mech->cm_type = t;
	return (0);
}
Exemplo n.º 3
0
int
smb2_hmac_getmech(smb_sign_mech_t *mech)
{
	crypto_mech_type_t t;

	t = crypto_mech2id(SUN_CKM_SHA256_HMAC);
	if (t == CRYPTO_MECH_INVALID)
		return (-1);
	mech->cm_type = t;
	return (0);
}
Exemplo n.º 4
0
boolean_t
zcrypt_mech_available(enum zio_crypt crypt)
{
	crypto_mech_type_t mech;

	if (crypt == ZIO_CRYPT_INHERIT || crypt == ZIO_CRYPT_OFF)
		return (TRUE);

	mech = crypto_mech2id(zio_crypt_table[crypt].ci_mechname);

	if (mech == CRYPTO_MECH_INVALID) {
		return (FALSE);
	}
	return (TRUE);
}
Exemplo n.º 5
0
/*
 * This is called via the system taskq, so that we can do further
 * initializations that have to wait until the kcf module itself is
 * done loading.  (After kcf:_init returns.)
 */
static void
rnd_init2(void *unused)
{

	_NOTE(ARGUNUSED(unused));

	/*
	 * This will load a randomness provider; typically "swrand",
	 * but could be another provider if so configured.
	 */
	rngmech_type = crypto_mech2id(SUN_RANDOM);

	/* Update rng_prov_found etc. */
	(void) kcf_rngprov_check();

	/* FIPS 140-2 init. */
	rnd_fips_discard_initial();

	/* Start rnd_handler calls. */
	rnd_schedule_timeout();
}
Exemplo n.º 6
0
static int
hkdf_sha512_extract(uint8_t *salt, uint_t salt_len, uint8_t *key_material,
    uint_t km_len, uint8_t *out_buf)
{
	int ret;
	crypto_mechanism_t mech;
	crypto_key_t key;
	crypto_data_t input_cd, output_cd;

	/* initialize HMAC mechanism */
	mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
	mech.cm_param = NULL;
	mech.cm_param_len = 0;

	/* initialize the salt as a crypto key */
	key.ck_format = CRYPTO_KEY_RAW;
	key.ck_length = CRYPTO_BYTES2BITS(salt_len);
	key.ck_data = salt;

	/* initialize crypto data for the input and output data */
	input_cd.cd_format = CRYPTO_DATA_RAW;
	input_cd.cd_offset = 0;
	input_cd.cd_length = km_len;
	input_cd.cd_raw.iov_base = (char *)key_material;
	input_cd.cd_raw.iov_len = input_cd.cd_length;

	output_cd.cd_format = CRYPTO_DATA_RAW;
	output_cd.cd_offset = 0;
	output_cd.cd_length = SHA512_DIGEST_LENGTH;
	output_cd.cd_raw.iov_base = (char *)out_buf;
	output_cd.cd_raw.iov_len = output_cd.cd_length;

	ret = crypto_mac(&mech, &input_cd, &key, NULL, &output_cd, NULL);
	if (ret != CRYPTO_SUCCESS)
		return (SET_ERROR(EIO));

	return (0);
}
Exemplo n.º 7
0
static int
pbkdf2(uint8_t *passphrase, size_t passphraselen, uint8_t *salt,
    size_t saltlen, uint64_t iterations, uint8_t *output,
    size_t outputlen)
{
	int ret;
	uint64_t iter;
	uint32_t blockptr, i;
	uint16_t hmac_key_len;
	uint8_t *hmac_key;
	uint8_t block[SHA1_DIGEST_LEN * 2];
	uint8_t *hmacresult = block + SHA1_DIGEST_LEN;
	crypto_mechanism_t mech;
	crypto_key_t key;
	crypto_data_t in_data, out_data;
	crypto_ctx_template_t tmpl = NULL;

	/* initialize output */
	memset(output, 0, outputlen);

	/* initialize icp for use */
	thread_init();
	icp_init();

	/* HMAC key size is max(sizeof(uint32_t) + salt len, sha 256 len) */
	if (saltlen > SHA1_DIGEST_LEN) {
		hmac_key_len = saltlen + sizeof (uint32_t);
	} else {
		hmac_key_len = SHA1_DIGEST_LEN;
	}

	hmac_key = calloc(hmac_key_len, 1);
	if (!hmac_key) {
		ret = ENOMEM;
		goto error;
	}

	/* initialize sha 256 hmac mechanism */
	mech.cm_type = crypto_mech2id(SUN_CKM_SHA1_HMAC);
	mech.cm_param = NULL;
	mech.cm_param_len = 0;

	/* initialize passphrase as a crypto key */
	key.ck_format = CRYPTO_KEY_RAW;
	key.ck_length = CRYPTO_BYTES2BITS(passphraselen);
	key.ck_data = passphrase;

	/*
	 * initialize crypto data for the input data. length will change
	 * after the first iteration, so we will initialize it in the loop.
	 */
	in_data.cd_format = CRYPTO_DATA_RAW;
	in_data.cd_offset = 0;
	in_data.cd_raw.iov_base = (char *)hmac_key;

	/* initialize crypto data for the output data */
	out_data.cd_format = CRYPTO_DATA_RAW;
	out_data.cd_offset = 0;
	out_data.cd_length = SHA1_DIGEST_LEN;
	out_data.cd_raw.iov_base = (char *)hmacresult;
	out_data.cd_raw.iov_len = out_data.cd_length;

	/* initialize the context template */
	ret = crypto_create_ctx_template(&mech, &key, &tmpl, KM_SLEEP);
	if (ret != CRYPTO_SUCCESS) {
		ret = EIO;
		goto error;
	}

	/* main loop */
	for (blockptr = 0; blockptr < outputlen; blockptr += SHA1_DIGEST_LEN) {

		/*
		 * for the first iteration, the HMAC key is the user-provided
		 * salt concatenated with the block index (1-indexed)
		 */
		i = htobe32(1 + (blockptr / SHA1_DIGEST_LEN));
		memmove(hmac_key, salt, saltlen);
		memmove(hmac_key + saltlen, (uint8_t *)(&i), sizeof (uint32_t));

		/* block initializes to zeroes (no XOR) */
		memset(block, 0, SHA1_DIGEST_LEN);

		for (iter = 0; iter < iterations; iter++) {
			if (iter > 0) {
				in_data.cd_length = SHA1_DIGEST_LEN;
				in_data.cd_raw.iov_len = in_data.cd_length;
			} else {
				in_data.cd_length = saltlen + sizeof (uint32_t);
				in_data.cd_raw.iov_len = in_data.cd_length;
			}

			ret = crypto_mac(&mech, &in_data, &key, tmpl,
			    &out_data, NULL);
			if (ret != CRYPTO_SUCCESS) {
				ret = EIO;
				goto error;
			}

			/* HMAC key now becomes the output of this iteration */
			memmove(hmac_key, hmacresult, SHA1_DIGEST_LEN);

			/* XOR this iteration's result with the current block */
			for (i = 0; i < SHA1_DIGEST_LEN; i++) {
				block[i] ^= hmacresult[i];
			}
		}

		/*
		 * compute length of this block, make sure we don't write
		 * beyond the end of the output, truncating if necessary
		 */
		if (blockptr + SHA1_DIGEST_LEN > outputlen) {
			memmove(output + blockptr, block, outputlen - blockptr);
		} else {
			memmove(output + blockptr, block, SHA1_DIGEST_LEN);
		}
	}

	crypto_destroy_ctx_template(tmpl);
	free(hmac_key);
	icp_fini();
	thread_fini();

	return (0);

error:
	crypto_destroy_ctx_template(tmpl);
	if (hmac_key != NULL)
		free(hmac_key);
	icp_fini();
	thread_fini();

	return (ret);
}
Exemplo n.º 8
0
/*
 * zcrypt_unwrap_key
 *
 * Using the provided wrapping key unwrap the key into a zcrypt_key_t.
 *
 * Allocates a zcrypt_key_t using kmem_alloc(), caller should free
 * using zcrypt_key_free().
 *
 * returns 0 on success
 */
int
zcrypt_unwrap_key(zcrypt_key_t *wk, uint64_t crypt,
    caddr_t wkeybuf, size_t wkeylen, zcrypt_key_t **zck)
{
	crypto_mechanism_t wmech;
	crypto_data_t wkey_cdt, ptkey_cdt;
	zcrypt_key_t *tmpzck;
	caddr_t uwrapkey, uwrapmac;
	size_t uwrapkeylen, uwrapmaclen;
	size_t keylen;
	int ret;
	zcrypt_key_phys_t *wkeyphys = (zcrypt_key_phys_t *)wkeybuf;
	uint64_t wcrypt;

	ASSERT(wkeybuf != NULL);
	ASSERT(wkeylen != 0);

	/*
	 * We maybe unwrapping a key of a smaller length than the wrapping
	 * key so unwrapbuflen and keylen need to take that into account.
	 *
	 * The incoming wkey also has the iv stored at the start.
	 */
	wcrypt = wkeyphys->zkp_crypt;
	ASSERT3U(wcrypt, <, ZIO_CRYPT_WRAP_FUNCTIONS);

	wmech.cm_type = crypto_mech2id(
	    zio_crypt_wrap_table[wcrypt].cwi_mechname);
	if (wmech.cm_type == CRYPTO_MECH_INVALID) {
		return (EINVAL);
	}
	keylen = zio_crypt_table[crypt].ci_keylen;

	if (wcrypt == ZIO_CRYPT_WRAP_AES_CCM) {
		CK_AES_CCM_PARAMS *ccmp;
		ccmp = kmem_zalloc(sizeof (CK_AES_CCM_PARAMS), KM_SLEEP);
		ccmp->ulNonceSize = zio_crypt_wrap_table[wcrypt].cwi_ivlen;
		ccmp->nonce = (uchar_t *)wkeyphys->zkp_kiv;
		ccmp->ulMACSize = zio_crypt_wrap_table[wcrypt].cwi_maclen;
		ccmp->ulDataSize = keylen + ccmp->ulMACSize;
		wmech.cm_param = (char *)ccmp;
		wmech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
	} else if (wcrypt == ZIO_CRYPT_WRAP_AES_GCM) {
		CK_AES_GCM_PARAMS *gcmp;
		gcmp = kmem_zalloc(sizeof (CK_AES_GCM_PARAMS), KM_SLEEP);
		gcmp->ulIvLen = zio_crypt_wrap_table[wcrypt].cwi_ivlen;
		gcmp->pIv = (uchar_t *)wkeyphys->zkp_kiv;
		gcmp->ulTagBits = zio_crypt_wrap_table[wcrypt].cwi_maclen * 8;
		wmech.cm_param = (char *)gcmp;
		wmech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
	} else {
		ASSERT(0);
	}

	uwrapkeylen = keylen + zio_crypt_wrap_table[wcrypt].cwi_maclen;
	uwrapkey = kmem_zalloc(uwrapkeylen, KM_SLEEP);

	SET_CRYPTO_DATA(ptkey_cdt, uwrapkey, uwrapkeylen);
	SET_CRYPTO_DATA(wkey_cdt, (char *)wkeyphys->zkp_key,
	    keylen + zio_crypt_wrap_table[wcrypt].cwi_maclen);

	ret = crypto_decrypt(&wmech, &wkey_cdt, &wk->zk_key,
	    NULL, &ptkey_cdt, NULL);
	kmem_free(wmech.cm_param, wmech.cm_param_len);
	if (ret != CRYPTO_SUCCESS) {
		kmem_free(uwrapkey, uwrapkeylen);
		zck = NULL;
		return (ret);
	}

	tmpzck = zcrypt_key_allocate();
	tmpzck->zk_key.ck_format = CRYPTO_KEY_RAW;
	tmpzck->zk_key.ck_data = kmem_alloc(keylen, KM_SLEEP);
	tmpzck->zk_key.ck_length = keylen * 8;
	tmpzck->zk_crypt = crypt;
	bcopy(uwrapkey, tmpzck->zk_key.ck_data, keylen);
	kmem_free(uwrapkey, uwrapkeylen);

	/* Now the HMAC-SHA256 key which we know is 32 bytes */
	keylen = 32;
	if (wcrypt == ZIO_CRYPT_WRAP_AES_CCM) {
		CK_AES_CCM_PARAMS *ccmp;
		ccmp = kmem_zalloc(sizeof (CK_AES_CCM_PARAMS), KM_SLEEP);
		ccmp->ulNonceSize = zio_crypt_wrap_table[wcrypt].cwi_ivlen;
		ccmp->nonce = (uchar_t *)wkeyphys->zkp_miv;
		ccmp->ulMACSize = zio_crypt_wrap_table[wcrypt].cwi_maclen;
		ccmp->ulDataSize = keylen + ccmp->ulMACSize;
		wmech.cm_param = (char *)ccmp;
		wmech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
	} else if (wcrypt == ZIO_CRYPT_WRAP_AES_GCM) {
		CK_AES_GCM_PARAMS *gcmp;
		gcmp = kmem_zalloc(sizeof (CK_AES_GCM_PARAMS), KM_SLEEP);
		gcmp->ulIvLen = zio_crypt_wrap_table[wcrypt].cwi_ivlen;
		gcmp->pIv = (uchar_t *)wkeyphys->zkp_miv;
		gcmp->ulTagBits = zio_crypt_wrap_table[wcrypt].cwi_maclen * 8;
		wmech.cm_param = (char *)gcmp;
		wmech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
	} else {
		ASSERT(0);
	}

	uwrapmaclen = keylen + zio_crypt_wrap_table[wcrypt].cwi_maclen;
	uwrapmac = kmem_zalloc(uwrapmaclen, KM_SLEEP);

	SET_CRYPTO_DATA(ptkey_cdt, uwrapmac, uwrapmaclen);
	SET_CRYPTO_DATA(wkey_cdt, (char *)wkeyphys->zkp_mackey,
	    keylen + zio_crypt_wrap_table[wcrypt].cwi_maclen);

	ret = crypto_decrypt(&wmech, &wkey_cdt, &wk->zk_key,
	    NULL, &ptkey_cdt, NULL);
	kmem_free(wmech.cm_param, wmech.cm_param_len);
	if (ret != CRYPTO_SUCCESS) {
		zcrypt_key_free(tmpzck);
		kmem_free(uwrapmac, uwrapmaclen);
		zck = NULL;
		return (ret);
	}

	tmpzck->zk_mackey.ck_format = CRYPTO_KEY_RAW;
	tmpzck->zk_mackey.ck_data = kmem_alloc(keylen, KM_SLEEP);
	tmpzck->zk_mackey.ck_length = keylen * 8;
	bcopy(uwrapmac, tmpzck->zk_mackey.ck_data, keylen);
	kmem_free(uwrapmac, uwrapmaclen);

	*zck = tmpzck;
	return (0);
}
Exemplo n.º 9
0
/*
 * zcrypt_wrap_key
 *
 * Using the provided wrapping key wrap the in memory representation of the
 * key into a form suitable for storage in a zap object.
 *
 * Uses kmem_alloc to create space for the wrapped key, the caller
 * should free with kmem_free when it is finished with the wrapped key.
 *
 * returns 0 on success
 */
int
zcrypt_wrap_key(zcrypt_key_t *wrappingkey, zcrypt_key_t *ptkey,
	caddr_t *wkeybuf, size_t *wkeylen, uint64_t wcrypt)
{
	crypto_mechanism_t wmech;
	crypto_data_t wkey_cdt, ptkey_cdt;
	size_t ptkeylen;
	size_t ivlen;
	int ret;
	zcrypt_key_phys_t *wkeyphys;

	/*
	 * Currently we only support wrapping keys of CRYPTO_KEY_RAW
	 */
	ASSERT(ptkey->zk_key.ck_format == CRYPTO_KEY_RAW);
	ASSERT(wcrypt < ZIO_CRYPT_WRAP_FUNCTIONS);

	wmech.cm_type = crypto_mech2id(
	    zio_crypt_wrap_table[wcrypt].cwi_mechname);
	if (wmech.cm_type == CRYPTO_MECH_INVALID)
		return (EINVAL);
	wkeyphys = kmem_zalloc(sizeof (zcrypt_key_phys_t), KM_PUSHPAGE); //Sleep
	wkeyphys->zkp_crypt = wcrypt;

	/*
	 * The data encryption and MAC keys are wrapped separately
	 * since in the future we may support one or both of them
	 * being in a FIPS 140-2 token as sensitive objects and we
	 * won't be able to treat them as "data" and wrap them together
	 * in one operation.
	 */

	/* Data encryption key is first */
	ptkeylen = CRYPTO_BITS2BYTES(ptkey->zk_key.ck_length);
	ivlen = zio_crypt_wrap_table[wcrypt].cwi_ivlen;
	VERIFY(random_get_bytes((uchar_t *)wkeyphys->zkp_kiv, ivlen) == 0);
	if (wcrypt == ZIO_CRYPT_WRAP_AES_CCM) {
		CK_AES_CCM_PARAMS *ccmp;
		ccmp = kmem_zalloc(sizeof (CK_AES_CCM_PARAMS), KM_PUSHPAGE); //Sleep
		ccmp->ulNonceSize = ivlen;
		ccmp->nonce = (uchar_t *)wkeyphys->zkp_kiv;
		ccmp->ulDataSize = ptkeylen;
		ccmp->ulMACSize = zio_crypt_wrap_table[wcrypt].cwi_maclen;
		wmech.cm_param = (char *)ccmp;
		wmech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
	} else if (wcrypt == ZIO_CRYPT_WRAP_AES_GCM) {
		CK_AES_GCM_PARAMS *gcmp;
		gcmp = kmem_zalloc(sizeof (CK_AES_GCM_PARAMS), KM_PUSHPAGE); //Sleep
		gcmp->ulIvLen = ivlen;
		gcmp->pIv = (uchar_t *)wkeyphys->zkp_kiv;
		gcmp->ulTagBits = zio_crypt_wrap_table[wcrypt].cwi_maclen * 8;
		wmech.cm_param = (char *)gcmp;
		wmech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
	} else {
		ASSERT(0);
	}

	SET_CRYPTO_DATA(wkey_cdt, (char *)wkeyphys->zkp_key,
	    ptkeylen + zio_crypt_wrap_table[wcrypt].cwi_maclen);
	SET_CRYPTO_DATA(ptkey_cdt, ptkey->zk_key.ck_data, ptkeylen);

#if _KERNEL
    printk("zcrypt 1\n");
#endif
	ret = crypto_encrypt(&wmech, &ptkey_cdt, &wrappingkey->zk_key,
	    NULL, &wkey_cdt, NULL);
	bzero(wmech.cm_param, wmech.cm_param_len);
	kmem_free(wmech.cm_param, wmech.cm_param_len);

	if (ret != CRYPTO_SUCCESS)
		goto out;

	/* Now the HMAC-SHA256 key for use with dedup IV generation */
	ptkeylen = CRYPTO_BITS2BYTES(ptkey->zk_mackey.ck_length);
	VERIFY(random_get_bytes((uchar_t *)wkeyphys->zkp_miv, ivlen) == 0);
	if (wcrypt == ZIO_CRYPT_WRAP_AES_CCM) {
		CK_AES_CCM_PARAMS *ccmp;
		ccmp = kmem_zalloc(sizeof (CK_AES_CCM_PARAMS), KM_PUSHPAGE); //Sleep
		ccmp->ulNonceSize = ivlen;
		ccmp->nonce = (uchar_t *)wkeyphys->zkp_miv;
		ccmp->ulDataSize = ptkeylen;
		ccmp->ulMACSize = zio_crypt_wrap_table[wcrypt].cwi_maclen;
		wmech.cm_param = (char *)ccmp;
		wmech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
	} else if (wcrypt == ZIO_CRYPT_WRAP_AES_GCM) {
		CK_AES_GCM_PARAMS *gcmp;
		gcmp = kmem_zalloc(sizeof (CK_AES_GCM_PARAMS), KM_PUSHPAGE); //Sleep
		gcmp->ulIvLen = ivlen;
		gcmp->pIv = (uchar_t *)wkeyphys->zkp_miv;
		gcmp->ulTagBits = zio_crypt_wrap_table[wcrypt].cwi_maclen * 8;
		wmech.cm_param = (char *)gcmp;
		wmech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
	} else {
		ASSERT(0);
	}

	SET_CRYPTO_DATA(wkey_cdt, (char *)wkeyphys->zkp_mackey,
	    ptkeylen + zio_crypt_wrap_table[wcrypt].cwi_maclen);
	SET_CRYPTO_DATA(ptkey_cdt, ptkey->zk_mackey.ck_data, ptkeylen);

#if _KERNEL
    printk("zcrypt 2\n");
#endif
	ret = crypto_encrypt(&wmech, &ptkey_cdt, &wrappingkey->zk_key,
	    NULL, &wkey_cdt, NULL);

	bzero(wmech.cm_param, wmech.cm_param_len);
	kmem_free(wmech.cm_param, wmech.cm_param_len);
out:
	if (ret != CRYPTO_SUCCESS) {
		kmem_free(wkeyphys, sizeof (zcrypt_key_phys_t));
		*wkeylen = 0;
		return (ret);
	}

	*wkeylen = sizeof (zcrypt_key_phys_t);
	*wkeybuf = (caddr_t)wkeyphys;

	return (0);
}
Exemplo n.º 10
0
static int
hkdf_sha512_expand(uint8_t *extract_key, uint8_t *info, uint_t info_len,
    uint8_t *out_buf, uint_t out_len)
{
	int ret;
	crypto_mechanism_t mech;
	crypto_context_t ctx;
	crypto_key_t key;
	crypto_data_t T_cd, info_cd, c_cd;
	uint_t i, T_len = 0, pos = 0;
	uint8_t c;
	uint_t N = (out_len + SHA512_DIGEST_LENGTH) / SHA512_DIGEST_LENGTH;
	uint8_t T[SHA512_DIGEST_LENGTH];

	if (N > 255)
		return (SET_ERROR(EINVAL));

	/* initialize HMAC mechanism */
	mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
	mech.cm_param = NULL;
	mech.cm_param_len = 0;

	/* initialize the salt as a crypto key */
	key.ck_format = CRYPTO_KEY_RAW;
	key.ck_length = CRYPTO_BYTES2BITS(SHA512_DIGEST_LENGTH);
	key.ck_data = extract_key;

	/* initialize crypto data for the input and output data */
	T_cd.cd_format = CRYPTO_DATA_RAW;
	T_cd.cd_offset = 0;
	T_cd.cd_raw.iov_base = (char *)T;

	c_cd.cd_format = CRYPTO_DATA_RAW;
	c_cd.cd_offset = 0;
	c_cd.cd_length = 1;
	c_cd.cd_raw.iov_base = (char *)&c;
	c_cd.cd_raw.iov_len = c_cd.cd_length;

	info_cd.cd_format = CRYPTO_DATA_RAW;
	info_cd.cd_offset = 0;
	info_cd.cd_length = info_len;
	info_cd.cd_raw.iov_base = (char *)info;
	info_cd.cd_raw.iov_len = info_cd.cd_length;

	for (i = 1; i <= N; i++) {
		c = i;

		T_cd.cd_length = T_len;
		T_cd.cd_raw.iov_len = T_cd.cd_length;

		ret = crypto_mac_init(&mech, &key, NULL, &ctx, NULL);
		if (ret != CRYPTO_SUCCESS)
			return (SET_ERROR(EIO));

		ret = crypto_mac_update(ctx, &T_cd, NULL);
		if (ret != CRYPTO_SUCCESS)
			return (SET_ERROR(EIO));

		ret = crypto_mac_update(ctx, &info_cd, NULL);
		if (ret != CRYPTO_SUCCESS)
			return (SET_ERROR(EIO));

		ret = crypto_mac_update(ctx, &c_cd, NULL);
		if (ret != CRYPTO_SUCCESS)
			return (SET_ERROR(EIO));

		T_len = SHA512_DIGEST_LENGTH;
		T_cd.cd_length = T_len;
		T_cd.cd_raw.iov_len = T_cd.cd_length;

		ret = crypto_mac_final(ctx, &T_cd, NULL);
		if (ret != CRYPTO_SUCCESS)
			return (SET_ERROR(EIO));

		bcopy(T, out_buf + pos,
		    (i != N) ? SHA512_DIGEST_LENGTH : (out_len - pos));
		pos += SHA512_DIGEST_LENGTH;
	}

	return (0);
}