162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016, Intel Corporation 462306a36Sopenharmony_ci * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/export.h> 862306a36Sopenharmony_ci#include <linux/err.h> 962306a36Sopenharmony_ci#include <linux/string.h> 1062306a36Sopenharmony_ci#include <crypto/ecdh.h> 1162306a36Sopenharmony_ci#include <crypto/kpp.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define ECDH_KPP_SECRET_MIN_SIZE (sizeof(struct kpp_secret) + sizeof(short)) 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic inline u8 *ecdh_pack_data(void *dst, const void *src, size_t sz) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci memcpy(dst, src, sz); 1862306a36Sopenharmony_ci return dst + sz; 1962306a36Sopenharmony_ci} 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic inline const u8 *ecdh_unpack_data(void *dst, const void *src, size_t sz) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci memcpy(dst, src, sz); 2462306a36Sopenharmony_ci return src + sz; 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ciunsigned int crypto_ecdh_key_len(const struct ecdh *params) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci return ECDH_KPP_SECRET_MIN_SIZE + params->key_size; 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_ecdh_key_len); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciint crypto_ecdh_encode_key(char *buf, unsigned int len, 3462306a36Sopenharmony_ci const struct ecdh *params) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci u8 *ptr = buf; 3762306a36Sopenharmony_ci struct kpp_secret secret = { 3862306a36Sopenharmony_ci .type = CRYPTO_KPP_SECRET_TYPE_ECDH, 3962306a36Sopenharmony_ci .len = len 4062306a36Sopenharmony_ci }; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (unlikely(!buf)) 4362306a36Sopenharmony_ci return -EINVAL; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (len != crypto_ecdh_key_len(params)) 4662306a36Sopenharmony_ci return -EINVAL; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci ptr = ecdh_pack_data(ptr, &secret, sizeof(secret)); 4962306a36Sopenharmony_ci ptr = ecdh_pack_data(ptr, ¶ms->key_size, sizeof(params->key_size)); 5062306a36Sopenharmony_ci ecdh_pack_data(ptr, params->key, params->key_size); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci return 0; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_ecdh_encode_key); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciint crypto_ecdh_decode_key(const char *buf, unsigned int len, 5762306a36Sopenharmony_ci struct ecdh *params) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci const u8 *ptr = buf; 6062306a36Sopenharmony_ci struct kpp_secret secret; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (unlikely(!buf || len < ECDH_KPP_SECRET_MIN_SIZE)) 6362306a36Sopenharmony_ci return -EINVAL; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci ptr = ecdh_unpack_data(&secret, ptr, sizeof(secret)); 6662306a36Sopenharmony_ci if (secret.type != CRYPTO_KPP_SECRET_TYPE_ECDH) 6762306a36Sopenharmony_ci return -EINVAL; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (unlikely(len < secret.len)) 7062306a36Sopenharmony_ci return -EINVAL; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci ptr = ecdh_unpack_data(¶ms->key_size, ptr, sizeof(params->key_size)); 7362306a36Sopenharmony_ci if (secret.len != crypto_ecdh_key_len(params)) 7462306a36Sopenharmony_ci return -EINVAL; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* Don't allocate memory. Set pointer to data 7762306a36Sopenharmony_ci * within the given buffer 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci params->key = (void *)ptr; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_ecdh_decode_key); 84