#include <sys/ctype.h>
#include <sys/zcp.h>
#include <sys/zcp_change_key.h>
static uint8_t
hexval(char c)
{
if (c >= '0' && c <= '9')
return (c - '0');
else if (c >= 'a' && c <= 'f')
return (c - 'a' + 10);
else if (c >= 'A' && c <= 'F')
return (c - 'A' + 10);
panic("invalid hex value");
}
static int
hex_to_raw(const char *key, uint8_t *buf, size_t buflen)
{
uint8_t *p;
size_t srclen = strlen(key);
size_t i;
if (buflen * 2 != srclen)
return (SET_ERROR(EINVAL));
for (i = 0, p = buf; i < srclen; i += 2, p++) {
if (!isxdigit(key[i]) || !isxdigit(key[i + 1]))
return (SET_ERROR(EINVAL));
*p = hexval(key[i]) << 4 | hexval(key[i + 1]);
}
return (0);
}
int
zcp_synctask_change_key_create_params(const char *key, size_t keylen,
zfs_keyformat_t keyformat, dsl_crypto_params_t **dcpp)
{
nvlist_t *args = fnvlist_alloc();
nvlist_t *hidden_args = fnvlist_alloc();
uint8_t rawkey[WRAPPING_KEY_LEN];
uint_t rawlen = 0;
int err = 0;
switch (keyformat) {
case ZFS_KEYFORMAT_RAW:
if (keylen != WRAPPING_KEY_LEN) {
err = SET_ERROR(EINVAL);
goto done;
}
bcopy(key, rawkey, keylen);
rawlen = keylen;
break;
case ZFS_KEYFORMAT_HEX:
err = hex_to_raw(key, rawkey, sizeof (rawkey));
if (err != 0)
goto done;
rawlen = sizeof (rawkey);
break;
default:
err = SET_ERROR(EINVAL);
goto done;
}
fnvlist_add_uint64(args, zfs_prop_to_name(ZFS_PROP_KEYFORMAT),
(uint64_t)keyformat);
fnvlist_add_uint8_array(hidden_args, "wkeydata", rawkey, rawlen);
err = dsl_crypto_params_create_nvlist(DCP_CMD_NEW_KEY, args,
hidden_args, dcpp);
done:
fnvlist_free(args);
fnvlist_free(hidden_args);
bzero(rawkey, sizeof (rawkey));
return (err);
}
void
zcp_synctask_change_key_cleanup(void *arg)
{
spa_keystore_change_key_args_t *skcka = arg;
dsl_crypto_params_free(skcka->skcka_cp, B_TRUE);
}
int
zcp_synctask_change_key_check(void *arg, dmu_tx_t *tx)
{
return (spa_keystore_change_key_check(arg, tx));
}
void
zcp_synctask_change_key_sync(void *arg, dmu_tx_t *tx)
{
spa_keystore_change_key_sync(arg, tx);
}