0001
0002
0003
0004
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, ¶ms->key_size,
0054 sizeof(params->key_size));
0055 ptr = dh_pack_data(ptr, end, ¶ms->p_size, sizeof(params->p_size));
0056 ptr = dh_pack_data(ptr, end, ¶ms->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(¶ms->key_size, ptr, sizeof(params->key_size));
0079 ptr = dh_unpack_data(¶ms->p_size, ptr, sizeof(params->p_size));
0080 ptr = dh_unpack_data(¶ms->g_size, ptr, sizeof(params->g_size));
0081 if (secret.len != crypto_dh_key_len(params))
0082 return -EINVAL;
0083
0084
0085
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
0104
0105
0106 if (params->key_size > params->p_size ||
0107 params->g_size > params->p_size)
0108 return -EINVAL;
0109
0110
0111
0112
0113
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);