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, &params->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(&params->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