#include <sys/types.h>
#include <sys/crypto/api.h>
#include <netsmb/nsmb_kcrypt.h>
#include <sys/cmn_err.h>
#include <sys/strsun.h>
#include <sys/sunddi.h>
static int
find_mech(smb_crypto_mech_t *mech, const char *name)
{
crypto_mech_type_t t;
t = crypto_mech2id(name);
if (t == CRYPTO_MECH_INVALID) {
cmn_err(CE_NOTE, "nsmb: no kcf mech: %s", name);
return (-1);
}
mech->cm_type = t;
return (0);
}
int
nsmb_aes_ccm_getmech(smb_crypto_mech_t *mech)
{
return (find_mech(mech, SUN_CKM_AES_CCM));
}
int
nsmb_aes_gcm_getmech(smb_crypto_mech_t *mech)
{
return (find_mech(mech, SUN_CKM_AES_GCM));
}
void
nsmb_crypto_init_ccm_param(smb_enc_ctx_t *ctx,
uint8_t *nonce, size_t noncesize,
uint8_t *auth, size_t authsize,
size_t datasize)
{
ASSERT3U(noncesize, >=, SMB3_AES_CCM_NONCE_SIZE);
ctx->param.ccm.ulMACSize = SMB2_SIG_SIZE;
ctx->param.ccm.ulNonceSize = SMB3_AES_CCM_NONCE_SIZE;
ctx->param.ccm.nonce = nonce;
ctx->param.ccm.ulDataSize = datasize;
ctx->param.ccm.ulAuthDataSize = authsize;
ctx->param.ccm.authData = auth;
ctx->mech.cm_param = (caddr_t)&ctx->param.ccm;
ctx->mech.cm_param_len = sizeof (ctx->param.ccm);
}
void
nsmb_crypto_init_gcm_param(smb_enc_ctx_t *ctx,
uint8_t *nonce, size_t noncesize,
uint8_t *auth, size_t authsize)
{
ASSERT3U(noncesize, >=, SMB3_AES_GCM_NONCE_SIZE);
ctx->param.gcm.pIv = nonce;
ctx->param.gcm.ulIvLen = SMB3_AES_GCM_NONCE_SIZE;
ctx->param.gcm.ulTagBits = SMB2_SIG_SIZE << 3;
ctx->param.gcm.pAAD = auth;
ctx->param.gcm.ulAADLen = authsize;
ctx->mech.cm_param = (caddr_t)&ctx->param.gcm;
ctx->mech.cm_param_len = sizeof (ctx->param.gcm);
}
int
nsmb_encrypt_init(smb_enc_ctx_t *ctxp,
uint8_t *key, size_t keylen)
{
bzero(&ctxp->ckey, sizeof (ctxp->ckey));
ctxp->ckey.ck_format = CRYPTO_KEY_RAW;
ctxp->ckey.ck_data = key;
ctxp->ckey.ck_length = keylen * 8;
return (0);
}
int
nsmb_decrypt_init(smb_enc_ctx_t *ctxp,
uint8_t *key, size_t keylen)
{
bzero(&ctxp->ckey, sizeof (ctxp->ckey));
ctxp->ckey.ck_format = CRYPTO_KEY_RAW;
ctxp->ckey.ck_data = key;
ctxp->ckey.ck_length = keylen * 8;
return (0);
}
void
nsmb_enc_ctx_done(smb_enc_ctx_t *ctxp)
{
}
int
nsmb_encrypt_mblks(smb_enc_ctx_t *ctxp, mblk_t *mp, size_t clearlen)
{
crypto_data_t in_cd, out_cd;
size_t inlen, outlen;
int rv;
inlen = clearlen;
outlen = clearlen + SMB2_SIG_SIZE;
ASSERT(msgsize(mp) >= outlen);
bzero(&in_cd, sizeof (crypto_data_t));
in_cd.cd_format = CRYPTO_DATA_MBLK;
in_cd.cd_length = inlen;
in_cd.cd_mp = mp;
bzero(&out_cd, sizeof (crypto_data_t));
out_cd.cd_format = CRYPTO_DATA_MBLK;
out_cd.cd_length = outlen;
out_cd.cd_mp = mp;
rv = crypto_encrypt(&ctxp->mech, &in_cd,
&ctxp->ckey, NULL, &out_cd, NULL);
if (rv != CRYPTO_SUCCESS) {
cmn_err(CE_WARN, "nsmb: crypto_encrypt failed: 0x%x", rv);
return (-1);
}
return (0);
}
int
nsmb_decrypt_mblks(smb_enc_ctx_t *ctxp, mblk_t *mp, size_t cipherlen)
{
crypto_data_t in_cd, out_cd;
size_t inlen, outlen;
int rv;
if (cipherlen <= SMB2_SIG_SIZE)
return (-1);
inlen = cipherlen;
outlen = cipherlen - SMB2_SIG_SIZE;
ASSERT(msgsize(mp) >= inlen);
bzero(&in_cd, sizeof (crypto_data_t));
in_cd.cd_format = CRYPTO_DATA_MBLK;
in_cd.cd_length = inlen;
in_cd.cd_mp = mp;
bzero(&out_cd, sizeof (crypto_data_t));
out_cd.cd_format = CRYPTO_DATA_MBLK;
out_cd.cd_length = outlen;
out_cd.cd_mp = mp;
rv = crypto_decrypt(&ctxp->mech, &in_cd,
&ctxp->ckey, NULL, &out_cd, NULL);
if (rv != CRYPTO_SUCCESS) {
cmn_err(CE_WARN, "nsmb: crypto_decrypt failed: 0x%x", rv);
return (-1);
}
return (0);
}