Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (c) 2016, Intel Corporation
0004  * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
0005  */
0006 #include <linux/kernel.h>
0007 #include <linux/export.h>
0008 #include <linux/err.h>
0009 #include <linux/string.h>
0010 #include <crypto/dh.h>
0011 #include <crypto/kpp.h>
0012 
0013 #define DH_KPP_SECRET_MIN_SIZE (sizeof(struct kpp_secret) + 3 * sizeof(int))
0014 
0015 static inline u8 *dh_pack_data(u8 *dst, u8 *end, const void *src, size_t size)
0016 {
0017     if (!dst || size > end - dst)
0018         return NULL;
0019     memcpy(dst, src, size);
0020     return dst + size;
0021 }
0022 
0023 static inline const u8 *dh_unpack_data(void *dst, const void *src, size_t size)
0024 {
0025     memcpy(dst, src, size);
0026     return src + size;
0027 }
0028 
0029 static inline unsigned int dh_data_size(const struct dh *p)
0030 {
0031     return p->key_size + p->p_size + p->g_size;
0032 }
0033 
0034 unsigned int crypto_dh_key_len(const struct dh *p)
0035 {
0036     return DH_KPP_SECRET_MIN_SIZE + dh_data_size(p);
0037 }
0038 EXPORT_SYMBOL_GPL(crypto_dh_key_len);
0039 
0040 int crypto_dh_encode_key(char *buf, unsigned int len, const struct dh *params)
0041 {
0042     u8 *ptr = buf;
0043     u8 * const end = ptr + len;
0044     struct kpp_secret secret = {
0045         .type = CRYPTO_KPP_SECRET_TYPE_DH,
0046         .len = len
0047     };
0048 
0049     if (unlikely(!len))
0050         return -EINVAL;
0051 
0052     ptr = dh_pack_data(ptr, end, &secret, sizeof(secret));
0053     ptr = dh_pack_data(ptr, end, &params->key_size,
0054                sizeof(params->key_size));
0055     ptr = dh_pack_data(ptr, end, &params->p_size, sizeof(params->p_size));
0056     ptr = dh_pack_data(ptr, end, &params->g_size, sizeof(params->g_size));
0057     ptr = dh_pack_data(ptr, end, params->key, params->key_size);
0058     ptr = dh_pack_data(ptr, end, params->p, params->p_size);
0059     ptr = dh_pack_data(ptr, end, params->g, params->g_size);
0060     if (ptr != end)
0061         return -EINVAL;
0062     return 0;
0063 }
0064 EXPORT_SYMBOL_GPL(crypto_dh_encode_key);
0065 
0066 int __crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params)
0067 {
0068     const u8 *ptr = buf;
0069     struct kpp_secret secret;
0070 
0071     if (unlikely(!buf || len < DH_KPP_SECRET_MIN_SIZE))
0072         return -EINVAL;
0073 
0074     ptr = dh_unpack_data(&secret, ptr, sizeof(secret));
0075     if (secret.type != CRYPTO_KPP_SECRET_TYPE_DH)
0076         return -EINVAL;
0077 
0078     ptr = dh_unpack_data(&params->key_size, ptr, sizeof(params->key_size));
0079     ptr = dh_unpack_data(&params->p_size, ptr, sizeof(params->p_size));
0080     ptr = dh_unpack_data(&params->g_size, ptr, sizeof(params->g_size));
0081     if (secret.len != crypto_dh_key_len(params))
0082         return -EINVAL;
0083 
0084     /* Don't allocate memory. Set pointers to data within
0085      * the given buffer
0086      */
0087     params->key = (void *)ptr;
0088     params->p = (void *)(ptr + params->key_size);
0089     params->g = (void *)(ptr + params->key_size + params->p_size);
0090 
0091     return 0;
0092 }
0093 
0094 int crypto_dh_decode_key(const char *buf, unsigned int len, struct dh *params)
0095 {
0096     int err;
0097 
0098     err = __crypto_dh_decode_key(buf, len, params);
0099     if (err)
0100         return err;
0101 
0102     /*
0103      * Don't permit the buffer for 'key' or 'g' to be larger than 'p', since
0104      * some drivers assume otherwise.
0105      */
0106     if (params->key_size > params->p_size ||
0107         params->g_size > params->p_size)
0108         return -EINVAL;
0109 
0110     /*
0111      * Don't permit 'p' to be 0.  It's not a prime number, and it's subject
0112      * to corner cases such as 'mod 0' being undefined or
0113      * crypto_kpp_maxsize() returning 0.
0114      */
0115     if (memchr_inv(params->p, 0, params->p_size) == NULL)
0116         return -EINVAL;
0117 
0118     return 0;
0119 }
0120 EXPORT_SYMBOL_GPL(crypto_dh_decode_key);