2 * Copyright (c) 2016, Intel Corporation
3 * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
10 #include <linux/kernel.h>
11 #include <linux/export.h>
12 #include <linux/err.h>
13 #include <linux/string.h>
14 #include <crypto/dh.h>
15 #include <crypto/kpp.h>
17 #define DH_KPP_SECRET_MIN_SIZE (sizeof(struct kpp_secret) + 4 * sizeof(int))
19 static inline u8
*dh_pack_data(u8
*dst
, u8
*end
, const void *src
, size_t size
)
21 if (!dst
|| size
> end
- dst
)
23 memcpy(dst
, src
, size
);
27 static inline const u8
*dh_unpack_data(void *dst
, const void *src
, size_t size
)
29 memcpy(dst
, src
, size
);
33 static inline unsigned int dh_data_size(const struct dh
*p
)
35 return p
->key_size
+ p
->p_size
+ p
->q_size
+ p
->g_size
;
38 unsigned int crypto_dh_key_len(const struct dh
*p
)
40 return DH_KPP_SECRET_MIN_SIZE
+ dh_data_size(p
);
42 EXPORT_SYMBOL_GPL(crypto_dh_key_len
);
44 int crypto_dh_encode_key(char *buf
, unsigned int len
, const struct dh
*params
)
47 u8
* const end
= ptr
+ len
;
48 struct kpp_secret secret
= {
49 .type
= CRYPTO_KPP_SECRET_TYPE_DH
,
56 ptr
= dh_pack_data(ptr
, end
, &secret
, sizeof(secret
));
57 ptr
= dh_pack_data(ptr
, end
, ¶ms
->key_size
,
58 sizeof(params
->key_size
));
59 ptr
= dh_pack_data(ptr
, end
, ¶ms
->p_size
, sizeof(params
->p_size
));
60 ptr
= dh_pack_data(ptr
, end
, ¶ms
->q_size
, sizeof(params
->q_size
));
61 ptr
= dh_pack_data(ptr
, end
, ¶ms
->g_size
, sizeof(params
->g_size
));
62 ptr
= dh_pack_data(ptr
, end
, params
->key
, params
->key_size
);
63 ptr
= dh_pack_data(ptr
, end
, params
->p
, params
->p_size
);
64 ptr
= dh_pack_data(ptr
, end
, params
->q
, params
->q_size
);
65 ptr
= dh_pack_data(ptr
, end
, params
->g
, params
->g_size
);
70 EXPORT_SYMBOL_GPL(crypto_dh_encode_key
);
72 int crypto_dh_decode_key(const char *buf
, unsigned int len
, struct dh
*params
)
75 struct kpp_secret secret
;
77 if (unlikely(!buf
|| len
< DH_KPP_SECRET_MIN_SIZE
))
80 ptr
= dh_unpack_data(&secret
, ptr
, sizeof(secret
));
81 if (secret
.type
!= CRYPTO_KPP_SECRET_TYPE_DH
)
84 ptr
= dh_unpack_data(¶ms
->key_size
, ptr
, sizeof(params
->key_size
));
85 ptr
= dh_unpack_data(¶ms
->p_size
, ptr
, sizeof(params
->p_size
));
86 ptr
= dh_unpack_data(¶ms
->q_size
, ptr
, sizeof(params
->q_size
));
87 ptr
= dh_unpack_data(¶ms
->g_size
, ptr
, sizeof(params
->g_size
));
88 if (secret
.len
!= crypto_dh_key_len(params
))
92 * Don't permit the buffer for 'key' or 'g' to be larger than 'p', since
93 * some drivers assume otherwise.
95 if (params
->key_size
> params
->p_size
||
96 params
->g_size
> params
->p_size
|| params
->q_size
> params
->p_size
)
99 /* Don't allocate memory. Set pointers to data within
102 params
->key
= (void *)ptr
;
103 params
->p
= (void *)(ptr
+ params
->key_size
);
104 params
->q
= (void *)(ptr
+ params
->key_size
+ params
->p_size
);
105 params
->g
= (void *)(ptr
+ params
->key_size
+ params
->p_size
+
109 * Don't permit 'p' to be 0. It's not a prime number, and it's subject
110 * to corner cases such as 'mod 0' being undefined or
111 * crypto_kpp_maxsize() returning 0.
113 if (memchr_inv(params
->p
, 0, params
->p_size
) == NULL
)
116 /* It is permissible to not provide Q. */
117 if (params
->q_size
== 0)
122 EXPORT_SYMBOL_GPL(crypto_dh_decode_key
);