1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2016, Intel Corporation
4 * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
6 #include <linux/kernel.h>
7 #include <linux/export.h>
9 #include <linux/string.h>
10 #include <crypto/dh.h>
11 #include <crypto/kpp.h>
13 #define DH_KPP_SECRET_MIN_SIZE (sizeof(struct kpp_secret) + 3 * sizeof(int))
15 static inline u8
*dh_pack_data(u8
*dst
, u8
*end
, const void *src
, size_t size
)
17 if (!dst
|| size
> end
- dst
)
19 memcpy(dst
, src
, size
);
23 static inline const u8
*dh_unpack_data(void *dst
, const void *src
, size_t size
)
25 memcpy(dst
, src
, size
);
29 static inline unsigned int dh_data_size(const struct dh
*p
)
31 return p
->key_size
+ p
->p_size
+ p
->g_size
;
34 unsigned int crypto_dh_key_len(const struct dh
*p
)
36 return DH_KPP_SECRET_MIN_SIZE
+ dh_data_size(p
);
38 EXPORT_SYMBOL_GPL(crypto_dh_key_len
);
40 int crypto_dh_encode_key(char *buf
, unsigned int len
, const struct dh
*params
)
43 u8
* const end
= ptr
+ len
;
44 struct kpp_secret secret
= {
45 .type
= CRYPTO_KPP_SECRET_TYPE_DH
,
52 ptr
= dh_pack_data(ptr
, end
, &secret
, sizeof(secret
));
53 ptr
= dh_pack_data(ptr
, end
, ¶ms
->key_size
,
54 sizeof(params
->key_size
));
55 ptr
= dh_pack_data(ptr
, end
, ¶ms
->p_size
, sizeof(params
->p_size
));
56 ptr
= dh_pack_data(ptr
, end
, ¶ms
->g_size
, sizeof(params
->g_size
));
57 ptr
= dh_pack_data(ptr
, end
, params
->key
, params
->key_size
);
58 ptr
= dh_pack_data(ptr
, end
, params
->p
, params
->p_size
);
59 ptr
= dh_pack_data(ptr
, end
, params
->g
, params
->g_size
);
64 EXPORT_SYMBOL_GPL(crypto_dh_encode_key
);
66 int __crypto_dh_decode_key(const char *buf
, unsigned int len
, struct dh
*params
)
69 struct kpp_secret secret
;
71 if (unlikely(!buf
|| len
< DH_KPP_SECRET_MIN_SIZE
))
74 ptr
= dh_unpack_data(&secret
, ptr
, sizeof(secret
));
75 if (secret
.type
!= CRYPTO_KPP_SECRET_TYPE_DH
)
78 ptr
= dh_unpack_data(¶ms
->key_size
, ptr
, sizeof(params
->key_size
));
79 ptr
= dh_unpack_data(¶ms
->p_size
, ptr
, sizeof(params
->p_size
));
80 ptr
= dh_unpack_data(¶ms
->g_size
, ptr
, sizeof(params
->g_size
));
81 if (secret
.len
!= crypto_dh_key_len(params
))
84 /* Don't allocate memory. Set pointers to data within
87 params
->key
= (void *)ptr
;
88 params
->p
= (void *)(ptr
+ params
->key_size
);
89 params
->g
= (void *)(ptr
+ params
->key_size
+ params
->p_size
);
94 int crypto_dh_decode_key(const char *buf
, unsigned int len
, struct dh
*params
)
98 err
= __crypto_dh_decode_key(buf
, len
, params
);
103 * Don't permit the buffer for 'key' or 'g' to be larger than 'p', since
104 * some drivers assume otherwise.
106 if (params
->key_size
> params
->p_size
||
107 params
->g_size
> params
->p_size
)
111 * Don't permit 'p' to be 0. It's not a prime number, and it's subject
112 * to corner cases such as 'mod 0' being undefined or
113 * crypto_kpp_maxsize() returning 0.
115 if (memchr_inv(params
->p
, 0, params
->p_size
) == NULL
)
120 EXPORT_SYMBOL_GPL(crypto_dh_decode_key
);