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) + 4 * 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
->q_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
->q_size
, sizeof(params
->q_size
));
57 ptr
= dh_pack_data(ptr
, end
, ¶ms
->g_size
, sizeof(params
->g_size
));
58 ptr
= dh_pack_data(ptr
, end
, params
->key
, params
->key_size
);
59 ptr
= dh_pack_data(ptr
, end
, params
->p
, params
->p_size
);
60 ptr
= dh_pack_data(ptr
, end
, params
->q
, params
->q_size
);
61 ptr
= dh_pack_data(ptr
, end
, params
->g
, params
->g_size
);
66 EXPORT_SYMBOL_GPL(crypto_dh_encode_key
);
68 int crypto_dh_decode_key(const char *buf
, unsigned int len
, struct dh
*params
)
71 struct kpp_secret secret
;
73 if (unlikely(!buf
|| len
< DH_KPP_SECRET_MIN_SIZE
))
76 ptr
= dh_unpack_data(&secret
, ptr
, sizeof(secret
));
77 if (secret
.type
!= CRYPTO_KPP_SECRET_TYPE_DH
)
80 ptr
= dh_unpack_data(¶ms
->key_size
, ptr
, sizeof(params
->key_size
));
81 ptr
= dh_unpack_data(¶ms
->p_size
, ptr
, sizeof(params
->p_size
));
82 ptr
= dh_unpack_data(¶ms
->q_size
, ptr
, sizeof(params
->q_size
));
83 ptr
= dh_unpack_data(¶ms
->g_size
, ptr
, sizeof(params
->g_size
));
84 if (secret
.len
!= crypto_dh_key_len(params
))
88 * Don't permit the buffer for 'key' or 'g' to be larger than 'p', since
89 * some drivers assume otherwise.
91 if (params
->key_size
> params
->p_size
||
92 params
->g_size
> params
->p_size
|| params
->q_size
> params
->p_size
)
95 /* Don't allocate memory. Set pointers to data within
98 params
->key
= (void *)ptr
;
99 params
->p
= (void *)(ptr
+ params
->key_size
);
100 params
->q
= (void *)(ptr
+ params
->key_size
+ params
->p_size
);
101 params
->g
= (void *)(ptr
+ params
->key_size
+ params
->p_size
+
105 * Don't permit 'p' to be 0. It's not a prime number, and it's subject
106 * to corner cases such as 'mod 0' being undefined or
107 * crypto_kpp_maxsize() returning 0.
109 if (memchr_inv(params
->p
, 0, params
->p_size
) == NULL
)
112 /* It is permissible to not provide Q. */
113 if (params
->q_size
== 0)
118 EXPORT_SYMBOL_GPL(crypto_dh_decode_key
);