/* * 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); }
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); }
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); }
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); }
/* * 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(); }
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); }
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); }
/* * 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); }
/* * 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); }
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); }