xref: /openbsd/sbin/iked/dh.c (revision bc77414b)
1*bc77414bStobhe /*	$OpenBSD: dh.c,v 1.23 2020/04/28 15:18:52 tobhe Exp $	*/
245ae9d61Sreyk 
345ae9d61Sreyk /*
4547eb84dSreyk  * Copyright (c) 2010-2014 Reyk Floeter <reyk@openbsd.org>
545ae9d61Sreyk  *
645ae9d61Sreyk  * Permission to use, copy, modify, and distribute this software for any
745ae9d61Sreyk  * purpose with or without fee is hereby granted, provided that the above
845ae9d61Sreyk  * copyright notice and this permission notice appear in all copies.
945ae9d61Sreyk  *
1045ae9d61Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1145ae9d61Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1245ae9d61Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1345ae9d61Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1445ae9d61Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1545ae9d61Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1645ae9d61Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1745ae9d61Sreyk  */
1845ae9d61Sreyk 
19b9fc9a72Sderaadt #include <sys/param.h>	/* roundup */
2045ae9d61Sreyk #include <string.h>
2145ae9d61Sreyk 
2245ae9d61Sreyk #include <openssl/obj_mac.h>
2345ae9d61Sreyk #include <openssl/dh.h>
2445ae9d61Sreyk #include <openssl/ec.h>
2545ae9d61Sreyk #include <openssl/ecdh.h>
26a4194998Sjsg #include <openssl/bn.h>
2745ae9d61Sreyk 
2845ae9d61Sreyk #include "dh.h"
290d5bf58dSreyk 
300d5bf58dSreyk int	dh_init(struct group *);
3145ae9d61Sreyk 
3245135ebcSreyk /* MODP */
3345ae9d61Sreyk int	modp_init(struct group *);
3445ae9d61Sreyk int	modp_getlen(struct group *);
35d09d3a7dSreyk int	modp_create_exchange(struct group *, uint8_t *);
36d09d3a7dSreyk int	modp_create_shared(struct group *, uint8_t *, uint8_t *);
3745ae9d61Sreyk 
38*bc77414bStobhe /* ECP */
3945ae9d61Sreyk int	ec_init(struct group *);
4045ae9d61Sreyk int	ec_getlen(struct group *);
41a6321d0fSpatrick int	ec_secretlen(struct group *);
42d09d3a7dSreyk int	ec_create_exchange(struct group *, uint8_t *);
43d09d3a7dSreyk int	ec_create_shared(struct group *, uint8_t *, uint8_t *);
4445ae9d61Sreyk 
45a6321d0fSpatrick #define EC_POINT2RAW_FULL	0
46a6321d0fSpatrick #define EC_POINT2RAW_XONLY	1
47a6321d0fSpatrick int	ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t, int);
4845ae9d61Sreyk EC_POINT *
49d09d3a7dSreyk 	ec_raw2point(struct group *, uint8_t *, size_t);
5045ae9d61Sreyk 
5145135ebcSreyk /* curve25519 */
5245135ebcSreyk int	ec25519_init(struct group *);
5345135ebcSreyk int	ec25519_getlen(struct group *);
54d09d3a7dSreyk int	ec25519_create_exchange(struct group *, uint8_t *);
55d09d3a7dSreyk int	ec25519_create_shared(struct group *, uint8_t *, uint8_t *);
5645135ebcSreyk 
5745135ebcSreyk #define CURVE25519_SIZE 32	/* 256 bits */
5845135ebcSreyk struct curve25519_key {
59d09d3a7dSreyk 	uint8_t		 secret[CURVE25519_SIZE];
60d09d3a7dSreyk 	uint8_t		 public[CURVE25519_SIZE];
6145135ebcSreyk };
62d09d3a7dSreyk extern int crypto_scalarmult_curve25519(unsigned char a[CURVE25519_SIZE],
63d09d3a7dSreyk     const unsigned char b[CURVE25519_SIZE],
64d09d3a7dSreyk     const unsigned char c[CURVE25519_SIZE])
6545135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
6645135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)))
6745135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE)));
6845135ebcSreyk 
69e254d6eaSmikeb const struct group_id ike_groups[] = {
7045ae9d61Sreyk 	{ GROUP_MODP, 1, 768,
7145ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
7245ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
7345ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
7445ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
7545ae9d61Sreyk 	    "02"
7645ae9d61Sreyk 	},
7745ae9d61Sreyk 	{ GROUP_MODP, 2, 1024,
7845ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
7945ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
8045ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
8145ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
8245ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
8345ae9d61Sreyk 	    "FFFFFFFFFFFFFFFF",
8445ae9d61Sreyk 	    "02"
8545ae9d61Sreyk 	},
8645ae9d61Sreyk 	{ GROUP_MODP, 5, 1536,
8745ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
8845ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
8945ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
9045ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
9145ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
9245ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
9345ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
9445ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
9545ae9d61Sreyk 	    "02"
9645ae9d61Sreyk 	},
9745ae9d61Sreyk 	{ GROUP_MODP, 14, 2048,
9845ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
9945ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
10045ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
10145ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
10245ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
10345ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
10445ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
10545ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
10645ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
10745ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
10845ae9d61Sreyk 	    "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
10945ae9d61Sreyk 	    "02"
11045ae9d61Sreyk 	},
11145ae9d61Sreyk 	{ GROUP_MODP, 15, 3072,
11245ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
11345ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
11445ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
11545ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
11645ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
11745ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
11845ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
11945ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
12045ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
12145ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
12245ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
12345ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
12445ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
12545ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
12645ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
12745ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF",
12845ae9d61Sreyk 	    "02"
12945ae9d61Sreyk 	},
13045ae9d61Sreyk 	{ GROUP_MODP, 16, 4096,
13145ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
13245ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
13345ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
13445ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
13545ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
13645ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
13745ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
13845ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
13945ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
14045ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
14145ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
14245ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
14345ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
14445ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
14545ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
14645ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
14745ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
14845ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
14945ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
15045ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
15145ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
15245ae9d61Sreyk 	    "FFFFFFFFFFFFFFFF",
15345ae9d61Sreyk 	    "02"
15445ae9d61Sreyk 	},
15545ae9d61Sreyk 	{ GROUP_MODP, 17, 6144,
15645ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
15745ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
15845ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
15945ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
16045ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
16145ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
16245ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
16345ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
16445ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
16545ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
16645ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
16745ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
16845ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
16945ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
17045ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
17145ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
17245ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
17345ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
17445ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
17545ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
17645ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
17745ae9d61Sreyk 	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
17845ae9d61Sreyk 	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
17945ae9d61Sreyk 	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
18045ae9d61Sreyk 	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
18145ae9d61Sreyk 	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
18245ae9d61Sreyk 	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
18345ae9d61Sreyk 	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
18445ae9d61Sreyk 	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
18545ae9d61Sreyk 	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
18645ae9d61Sreyk 	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
18745ae9d61Sreyk 	    "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF",
18845ae9d61Sreyk 	    "02"
18945ae9d61Sreyk 	},
19045ae9d61Sreyk 	{ GROUP_MODP, 18, 8192,
19145ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
19245ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
19345ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
19445ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
19545ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
19645ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
19745ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
19845ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
19945ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
20045ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
20145ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
20245ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
20345ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
20445ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
20545ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
20645ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
20745ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
20845ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
20945ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
21045ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
21145ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
21245ae9d61Sreyk 	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
21345ae9d61Sreyk 	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
21445ae9d61Sreyk 	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
21545ae9d61Sreyk 	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
21645ae9d61Sreyk 	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
21745ae9d61Sreyk 	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
21845ae9d61Sreyk 	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
21945ae9d61Sreyk 	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
22045ae9d61Sreyk 	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
22145ae9d61Sreyk 	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
22245ae9d61Sreyk 	    "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
22345ae9d61Sreyk 	    "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
22445ae9d61Sreyk 	    "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
22545ae9d61Sreyk 	    "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
22645ae9d61Sreyk 	    "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
22745ae9d61Sreyk 	    "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
22845ae9d61Sreyk 	    "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
22945ae9d61Sreyk 	    "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
23045ae9d61Sreyk 	    "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
23145ae9d61Sreyk 	    "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
23245ae9d61Sreyk 	    "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
23345ae9d61Sreyk 	    "60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
23445ae9d61Sreyk 	    "02"
23545ae9d61Sreyk 	},
236369beec1Sreyk 	{ GROUP_ECP, 19, 256, NULL, NULL, NID_X9_62_prime256v1 },
237369beec1Sreyk 	{ GROUP_ECP, 20, 384, NULL, NULL, NID_secp384r1 },
238369beec1Sreyk 	{ GROUP_ECP, 21, 521, NULL, NULL, NID_secp521r1 },
239369beec1Sreyk 	{ GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 },
240547eb84dSreyk 	{ GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 },
241547eb84dSreyk 	{ GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 },
242547eb84dSreyk 	{ GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 },
243547eb84dSreyk 	{ GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 },
24445135ebcSreyk 	{ GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 },
245337280ecSsthen 	{ GROUP_CURVE25519, 31, CURVE25519_SIZE * 8 }
24645ae9d61Sreyk };
24745ae9d61Sreyk 
24845ae9d61Sreyk void
24945ae9d61Sreyk group_init(void)
25045ae9d61Sreyk {
2510d5bf58dSreyk 	/* currently not used */
25245ae9d61Sreyk 	return;
25345ae9d61Sreyk }
25445ae9d61Sreyk 
25545ae9d61Sreyk void
25645ae9d61Sreyk group_free(struct group *group)
25745ae9d61Sreyk {
25845ae9d61Sreyk 	if (group == NULL)
25945ae9d61Sreyk 		return;
26045ae9d61Sreyk 	if (group->dh != NULL)
26145ae9d61Sreyk 		DH_free(group->dh);
26245ae9d61Sreyk 	if (group->ec != NULL)
26345ae9d61Sreyk 		EC_KEY_free(group->ec);
26429b4e2eaSderaadt 	freezero(group->curve25519, sizeof(struct curve25519_key));
26545ae9d61Sreyk 	group->spec = NULL;
26664449014Sreyk 	free(group);
26745ae9d61Sreyk }
26845ae9d61Sreyk 
26945ae9d61Sreyk struct group *
270d09d3a7dSreyk group_get(uint32_t id)
27145ae9d61Sreyk {
272e254d6eaSmikeb 	const struct group_id	*p;
27345ae9d61Sreyk 	struct group		*group;
27445ae9d61Sreyk 
275e254d6eaSmikeb 	if ((p = group_getid(id)) == NULL)
27645ae9d61Sreyk 		return (NULL);
27745ae9d61Sreyk 
27845ae9d61Sreyk 	if ((group = calloc(1, sizeof(*group))) == NULL)
27945ae9d61Sreyk 		return (NULL);
28045ae9d61Sreyk 
28145ae9d61Sreyk 	group->id = id;
28245ae9d61Sreyk 	group->spec = p;
28345ae9d61Sreyk 
28445ae9d61Sreyk 	switch (p->type) {
28545ae9d61Sreyk 	case GROUP_MODP:
28645ae9d61Sreyk 		group->init = modp_init;
28745ae9d61Sreyk 		group->getlen = modp_getlen;
28845ae9d61Sreyk 		group->exchange = modp_create_exchange;
28945ae9d61Sreyk 		group->shared = modp_create_shared;
29045ae9d61Sreyk 		break;
291369beec1Sreyk 	case GROUP_ECP:
29245ae9d61Sreyk 		group->init = ec_init;
29345ae9d61Sreyk 		group->getlen = ec_getlen;
294a6321d0fSpatrick 		group->secretlen = ec_secretlen;
29545ae9d61Sreyk 		group->exchange = ec_create_exchange;
29645ae9d61Sreyk 		group->shared = ec_create_shared;
29745ae9d61Sreyk 		break;
29845135ebcSreyk 	case GROUP_CURVE25519:
29945135ebcSreyk 		group->init = ec25519_init;
30045135ebcSreyk 		group->getlen = ec25519_getlen;
30145135ebcSreyk 		group->exchange = ec25519_create_exchange;
30245135ebcSreyk 		group->shared = ec25519_create_shared;
30345135ebcSreyk 		break;
30445ae9d61Sreyk 	default:
30545ae9d61Sreyk 		group_free(group);
30645ae9d61Sreyk 		return (NULL);
30745ae9d61Sreyk 	}
30845ae9d61Sreyk 
30945ae9d61Sreyk 	if (dh_init(group) != 0) {
31045ae9d61Sreyk 		group_free(group);
31145ae9d61Sreyk 		return (NULL);
31245ae9d61Sreyk 	}
31345ae9d61Sreyk 
31445ae9d61Sreyk 	return (group);
31545ae9d61Sreyk }
31645ae9d61Sreyk 
317e254d6eaSmikeb const struct group_id *
318e254d6eaSmikeb group_getid(uint32_t id)
319e254d6eaSmikeb {
320e254d6eaSmikeb 	const struct group_id	*p = NULL;
321e254d6eaSmikeb 	unsigned int		 i, items;
322e254d6eaSmikeb 
323e254d6eaSmikeb 	items = sizeof(ike_groups) / sizeof(ike_groups[0]);
324e254d6eaSmikeb 	for (i = 0; i < items; i++) {
325e254d6eaSmikeb 		if (id == ike_groups[i].id) {
326e254d6eaSmikeb 			p = &ike_groups[i];
327e254d6eaSmikeb 			break;
328e254d6eaSmikeb 		}
329e254d6eaSmikeb 	}
330e254d6eaSmikeb 	return (p);
331e254d6eaSmikeb }
332e254d6eaSmikeb 
33345ae9d61Sreyk int
33445ae9d61Sreyk dh_init(struct group *group)
33545ae9d61Sreyk {
33645ae9d61Sreyk 	return (group->init(group));
33745ae9d61Sreyk }
33845ae9d61Sreyk 
33945ae9d61Sreyk int
34045ae9d61Sreyk dh_getlen(struct group *group)
34145ae9d61Sreyk {
34245ae9d61Sreyk 	return (group->getlen(group));
34345ae9d61Sreyk }
34445ae9d61Sreyk 
34545ae9d61Sreyk int
346a6321d0fSpatrick dh_secretlen(struct group *group)
347a6321d0fSpatrick {
348a6321d0fSpatrick 	if (group->secretlen)
349a6321d0fSpatrick 		return (group->secretlen(group));
350a6321d0fSpatrick 	else
351a6321d0fSpatrick 		return (group->getlen(group));
352a6321d0fSpatrick }
353a6321d0fSpatrick 
354a6321d0fSpatrick int
355d09d3a7dSreyk dh_create_exchange(struct group *group, uint8_t *buf)
35645ae9d61Sreyk {
35745ae9d61Sreyk 	return (group->exchange(group, buf));
35845ae9d61Sreyk }
35945ae9d61Sreyk 
36045ae9d61Sreyk int
361d09d3a7dSreyk dh_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange)
36245ae9d61Sreyk {
36345ae9d61Sreyk 	return (group->shared(group, secret, exchange));
36445ae9d61Sreyk }
36545ae9d61Sreyk 
36645ae9d61Sreyk int
36745ae9d61Sreyk modp_init(struct group *group)
36845ae9d61Sreyk {
36945ae9d61Sreyk 	DH	*dh;
37045ae9d61Sreyk 
37145ae9d61Sreyk 	if ((dh = DH_new()) == NULL)
37245ae9d61Sreyk 		return (-1);
3737d7b0856Sreyk 	group->dh = dh;
37445ae9d61Sreyk 
37545ae9d61Sreyk 	if (!BN_hex2bn(&dh->p, group->spec->prime) ||
37645ae9d61Sreyk 	    !BN_hex2bn(&dh->g, group->spec->generator))
37745ae9d61Sreyk 		return (-1);
37845ae9d61Sreyk 
37945ae9d61Sreyk 	return (0);
38045ae9d61Sreyk }
38145ae9d61Sreyk 
38245ae9d61Sreyk int
38345ae9d61Sreyk modp_getlen(struct group *group)
38445ae9d61Sreyk {
38545ae9d61Sreyk 	if (group->spec == NULL)
38645ae9d61Sreyk 		return (0);
38745ae9d61Sreyk 	return (roundup(group->spec->bits, 8) / 8);
38845ae9d61Sreyk }
38945ae9d61Sreyk 
39045ae9d61Sreyk int
391d09d3a7dSreyk modp_create_exchange(struct group *group, uint8_t *buf)
39245ae9d61Sreyk {
39345ae9d61Sreyk 	DH	*dh = group->dh;
39412abf43bSmikeb 	int	 len, ret;
39545ae9d61Sreyk 
39645ae9d61Sreyk 	if (!DH_generate_key(dh))
39745ae9d61Sreyk 		return (-1);
39812abf43bSmikeb 	ret = BN_bn2bin(dh->pub_key, buf);
39912abf43bSmikeb 	if (!ret)
40045ae9d61Sreyk 		return (-1);
40145ae9d61Sreyk 
40212abf43bSmikeb 	len = dh_getlen(group);
40312abf43bSmikeb 
40412abf43bSmikeb 	/* add zero padding */
40512abf43bSmikeb 	if (ret < len) {
40612abf43bSmikeb 		bcopy(buf, buf + (len - ret), ret);
40712abf43bSmikeb 		bzero(buf, len - ret);
40812abf43bSmikeb 	}
40912abf43bSmikeb 
4107d7b0856Sreyk 	return (0);
41145ae9d61Sreyk }
41245ae9d61Sreyk 
41345ae9d61Sreyk int
414d09d3a7dSreyk modp_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange)
41545ae9d61Sreyk {
41645ae9d61Sreyk 	BIGNUM	*ex;
41712abf43bSmikeb 	int	 len, ret;
41845ae9d61Sreyk 
41912abf43bSmikeb 	len = dh_getlen(group);
42012abf43bSmikeb 
42112abf43bSmikeb 	if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL)
42245ae9d61Sreyk 		return (-1);
4237d7b0856Sreyk 
4247d7b0856Sreyk 	ret = DH_compute_key(secret, ex, group->dh);
4257d7b0856Sreyk 	BN_clear_free(ex);
4262ffa77eaSjsg 	if (ret <= 0)
42745ae9d61Sreyk 		return (-1);
42845ae9d61Sreyk 
42912abf43bSmikeb 	/* add zero padding */
43012abf43bSmikeb 	if (ret < len) {
43112abf43bSmikeb 		bcopy(secret, secret + (len - ret), ret);
43212abf43bSmikeb 		bzero(secret, len - ret);
43312abf43bSmikeb 	}
43412abf43bSmikeb 
4357d7b0856Sreyk 	return (0);
43645ae9d61Sreyk }
43745ae9d61Sreyk 
43845ae9d61Sreyk int
43945ae9d61Sreyk ec_init(struct group *group)
44045ae9d61Sreyk {
44145ae9d61Sreyk 	if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL)
44245ae9d61Sreyk 		return (-1);
44345ae9d61Sreyk 	if (!EC_KEY_generate_key(group->ec))
44445ae9d61Sreyk 		return (-1);
445c900656bSmarkus 	if (!EC_KEY_check_key(group->ec)) {
446c900656bSmarkus 		EC_KEY_free(group->ec);
447c900656bSmarkus 		return (-1);
448c900656bSmarkus 	}
44945ae9d61Sreyk 	return (0);
45045ae9d61Sreyk }
45145ae9d61Sreyk 
45245ae9d61Sreyk int
45345ae9d61Sreyk ec_getlen(struct group *group)
45445ae9d61Sreyk {
45545ae9d61Sreyk 	if (group->spec == NULL)
45645ae9d61Sreyk 		return (0);
45745b72fd1Smikeb 	/* NB:  Return value will always be even */
45845ae9d61Sreyk 	return ((roundup(group->spec->bits, 8) * 2) / 8);
45945ae9d61Sreyk }
46045ae9d61Sreyk 
461a6321d0fSpatrick /*
462a6321d0fSpatrick  * Note that the shared secret only includes the x value:
463a6321d0fSpatrick  *
464a6321d0fSpatrick  * See RFC 5903, 7. ECP Key Exchange Data Formats:
465a6321d0fSpatrick  *   The Diffie-Hellman shared secret value consists of the x value of the
466a6321d0fSpatrick  *   Diffie-Hellman common value.
467a6321d0fSpatrick  * See also RFC 5903, 9. Changes from RFC 4753.
468a6321d0fSpatrick  */
469a6321d0fSpatrick int
470a6321d0fSpatrick ec_secretlen(struct group *group)
471a6321d0fSpatrick {
472a6321d0fSpatrick 	return (ec_getlen(group) / 2);
473a6321d0fSpatrick }
474a6321d0fSpatrick 
47545ae9d61Sreyk int
476d09d3a7dSreyk ec_create_exchange(struct group *group, uint8_t *buf)
47745ae9d61Sreyk {
4780d5bf58dSreyk 	size_t	 len;
4790d5bf58dSreyk 
4800d5bf58dSreyk 	len = ec_getlen(group);
4810d5bf58dSreyk 	bzero(buf, len);
4820d5bf58dSreyk 
48345ae9d61Sreyk 	return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec),
484a6321d0fSpatrick 	    buf, len, EC_POINT2RAW_FULL));
48545ae9d61Sreyk }
48645ae9d61Sreyk 
48745ae9d61Sreyk int
488d09d3a7dSreyk ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange)
48945ae9d61Sreyk {
49045ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
49145ae9d61Sreyk 	const BIGNUM	*privkey;
492c900656bSmarkus 	EC_KEY		*exkey = NULL;
49345ae9d61Sreyk 	EC_POINT	*exchangep = NULL, *secretp = NULL;
49445ae9d61Sreyk 	int		 ret = -1;
49545ae9d61Sreyk 
49645ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL ||
49745ae9d61Sreyk 	    (privkey = EC_KEY_get0_private_key(group->ec)) == NULL)
49845ae9d61Sreyk 		goto done;
49945ae9d61Sreyk 
50045ae9d61Sreyk 	if ((exchangep =
50145ae9d61Sreyk 	    ec_raw2point(group, exchange, ec_getlen(group))) == NULL)
50245ae9d61Sreyk 		goto done;
50345ae9d61Sreyk 
504c900656bSmarkus 	if ((exkey = EC_KEY_new()) == NULL)
505c900656bSmarkus 		goto done;
506c900656bSmarkus 	if (!EC_KEY_set_group(exkey, ecgroup))
507c900656bSmarkus 		goto done;
508c900656bSmarkus 	if (!EC_KEY_set_public_key(exkey, exchangep))
509c900656bSmarkus 		goto done;
510c900656bSmarkus 
511c900656bSmarkus 	/* validate exchangep */
512c900656bSmarkus 	if (!EC_KEY_check_key(exkey))
513c900656bSmarkus 		goto done;
514c900656bSmarkus 
51545ae9d61Sreyk 	if ((secretp = EC_POINT_new(ecgroup)) == NULL)
51645ae9d61Sreyk 		goto done;
51745ae9d61Sreyk 
51845ae9d61Sreyk 	if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL))
51945ae9d61Sreyk 		goto done;
52045ae9d61Sreyk 
521a6321d0fSpatrick 	ret = ec_point2raw(group, secretp, secret, ec_secretlen(group),
522a6321d0fSpatrick 	    EC_POINT2RAW_XONLY);
52345ae9d61Sreyk 
52445ae9d61Sreyk  done:
525c900656bSmarkus 	if (exkey != NULL)
526c900656bSmarkus 		EC_KEY_free(exkey);
52745ae9d61Sreyk 	if (exchangep != NULL)
52845ae9d61Sreyk 		EC_POINT_clear_free(exchangep);
52945ae9d61Sreyk 	if (secretp != NULL)
53045ae9d61Sreyk 		EC_POINT_clear_free(secretp);
53145ae9d61Sreyk 
53245ae9d61Sreyk 	return (ret);
53345ae9d61Sreyk }
53445ae9d61Sreyk 
53545ae9d61Sreyk int
53645ae9d61Sreyk ec_point2raw(struct group *group, const EC_POINT *point,
537a6321d0fSpatrick     uint8_t *buf, size_t len, int mode)
53845ae9d61Sreyk {
53945ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
54045ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
54145ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
54245ae9d61Sreyk 	int		 ret = -1;
54345b72fd1Smikeb 	size_t		 eclen, xlen, ylen;
54445ae9d61Sreyk 	off_t		 xoff, yoff;
54545ae9d61Sreyk 
54645ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
54745ae9d61Sreyk 		goto done;
54845ae9d61Sreyk 	BN_CTX_start(bnctx);
54945ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
55045ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
55145ae9d61Sreyk 		goto done;
55245ae9d61Sreyk 
55345b72fd1Smikeb 	eclen = ec_getlen(group);
554a6321d0fSpatrick 	switch (mode) {
555a6321d0fSpatrick 	case EC_POINT2RAW_XONLY:
556a6321d0fSpatrick 		xlen = eclen / 2;
557a6321d0fSpatrick 		ylen = 0;
558a6321d0fSpatrick 		break;
559a6321d0fSpatrick 	case EC_POINT2RAW_FULL:
56045b72fd1Smikeb 		xlen = ylen = eclen / 2;
561a6321d0fSpatrick 		break;
562a6321d0fSpatrick 	default:
563a6321d0fSpatrick 		goto done;
564a6321d0fSpatrick 	}
565a6321d0fSpatrick 	if (len < xlen + ylen)
566a6321d0fSpatrick 		goto done;
56745b72fd1Smikeb 
56845ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
56945ae9d61Sreyk 		goto done;
57045ae9d61Sreyk 
57145ae9d61Sreyk 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) ==
57245ae9d61Sreyk 	    NID_X9_62_prime_field) {
57345ae9d61Sreyk 		if (!EC_POINT_get_affine_coordinates_GFp(ecgroup,
57445ae9d61Sreyk 		    point, x, y, bnctx))
57545ae9d61Sreyk 			goto done;
57645ae9d61Sreyk 	} else {
57745ae9d61Sreyk 		if (!EC_POINT_get_affine_coordinates_GF2m(ecgroup,
57845ae9d61Sreyk 		    point, x, y, bnctx))
57945ae9d61Sreyk 			goto done;
58045ae9d61Sreyk 	}
58145ae9d61Sreyk 
58245ae9d61Sreyk 	xoff = xlen - BN_num_bytes(x);
58345b72fd1Smikeb 	bzero(buf, xoff);
58445ae9d61Sreyk 	if (!BN_bn2bin(x, buf + xoff))
58545ae9d61Sreyk 		goto done;
58645ae9d61Sreyk 
587a6321d0fSpatrick 	if (ylen > 0) {
58845ae9d61Sreyk 		yoff = (ylen - BN_num_bytes(y)) + xlen;
58945b72fd1Smikeb 		bzero(buf + xlen, yoff - xlen);
59045ae9d61Sreyk 		if (!BN_bn2bin(y, buf + yoff))
59145ae9d61Sreyk 			goto done;
592a6321d0fSpatrick 	}
59345ae9d61Sreyk 
59445ae9d61Sreyk 	ret = 0;
59545ae9d61Sreyk  done:
596c900656bSmarkus 	/* Make sure to erase sensitive data */
597c900656bSmarkus 	if (x != NULL)
598c900656bSmarkus 		BN_clear(x);
599c900656bSmarkus 	if (y != NULL)
600c900656bSmarkus 		BN_clear(y);
60145ae9d61Sreyk 	BN_CTX_end(bnctx);
60245ae9d61Sreyk 	BN_CTX_free(bnctx);
60345ae9d61Sreyk 
60445ae9d61Sreyk 	return (ret);
60545ae9d61Sreyk }
60645ae9d61Sreyk 
60745ae9d61Sreyk EC_POINT *
608d09d3a7dSreyk ec_raw2point(struct group *group, uint8_t *buf, size_t len)
60945ae9d61Sreyk {
61045ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
61145ae9d61Sreyk 	EC_POINT	*point = NULL;
61245ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
61345ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
61445ae9d61Sreyk 	int		 ret = -1;
61545ae9d61Sreyk 	size_t		 eclen;
61645ae9d61Sreyk 	size_t		 xlen, ylen;
61745ae9d61Sreyk 
61845ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
61945ae9d61Sreyk 		goto done;
62045ae9d61Sreyk 	BN_CTX_start(bnctx);
62145ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
62245ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
62345ae9d61Sreyk 		goto done;
62445ae9d61Sreyk 
62545ae9d61Sreyk 	eclen = ec_getlen(group);
62645ae9d61Sreyk 	if (len < eclen)
62745ae9d61Sreyk 		goto done;
62845ae9d61Sreyk 	xlen = ylen = eclen / 2;
62945ae9d61Sreyk 	if ((x = BN_bin2bn(buf, xlen, x)) == NULL ||
63045ae9d61Sreyk 	    (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL)
63145ae9d61Sreyk 		goto done;
63245ae9d61Sreyk 
63345ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
63445ae9d61Sreyk 		goto done;
63545ae9d61Sreyk 
63645ae9d61Sreyk 	if ((point = EC_POINT_new(ecgroup)) == NULL)
63745ae9d61Sreyk 		goto done;
63845ae9d61Sreyk 
63945ae9d61Sreyk 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) ==
64045ae9d61Sreyk 	    NID_X9_62_prime_field) {
64145ae9d61Sreyk 		if (!EC_POINT_set_affine_coordinates_GFp(ecgroup,
64245ae9d61Sreyk 		    point, x, y, bnctx))
64345ae9d61Sreyk 			goto done;
64445ae9d61Sreyk 	} else {
64545ae9d61Sreyk 		if (!EC_POINT_set_affine_coordinates_GF2m(ecgroup,
64645ae9d61Sreyk 		    point, x, y, bnctx))
64745ae9d61Sreyk 			goto done;
64845ae9d61Sreyk 	}
64945ae9d61Sreyk 
65045ae9d61Sreyk 	ret = 0;
65145ae9d61Sreyk  done:
65245ae9d61Sreyk 	if (ret != 0 && point != NULL)
65345ae9d61Sreyk 		EC_POINT_clear_free(point);
654c900656bSmarkus 	/* Make sure to erase sensitive data */
655c900656bSmarkus 	if (x != NULL)
656c900656bSmarkus 		BN_clear(x);
657c900656bSmarkus 	if (y != NULL)
658c900656bSmarkus 		BN_clear(y);
65945ae9d61Sreyk 	BN_CTX_end(bnctx);
66045ae9d61Sreyk 	BN_CTX_free(bnctx);
66145ae9d61Sreyk 
66245ae9d61Sreyk 	return (point);
66345ae9d61Sreyk }
66445135ebcSreyk 
66545135ebcSreyk int
66645135ebcSreyk ec25519_init(struct group *group)
66745135ebcSreyk {
668d09d3a7dSreyk 	static const uint8_t	 basepoint[CURVE25519_SIZE] = { 9 };
66945135ebcSreyk 	struct curve25519_key	*curve25519;
67045135ebcSreyk 
67145135ebcSreyk 	if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL)
67245135ebcSreyk 		return (-1);
67345135ebcSreyk 
67445135ebcSreyk 	group->curve25519 = curve25519;
67545135ebcSreyk 
67645135ebcSreyk 	arc4random_buf(curve25519->secret, CURVE25519_SIZE);
67745135ebcSreyk 	crypto_scalarmult_curve25519(curve25519->public,
67845135ebcSreyk 	    curve25519->secret, basepoint);
67945135ebcSreyk 
68045135ebcSreyk 	return (0);
68145135ebcSreyk }
68245135ebcSreyk 
68345135ebcSreyk int
68445135ebcSreyk ec25519_getlen(struct group *group)
68545135ebcSreyk {
68645135ebcSreyk 	if (group->spec == NULL)
68745135ebcSreyk 		return (0);
68845135ebcSreyk 	return (CURVE25519_SIZE);
68945135ebcSreyk }
69045135ebcSreyk 
69145135ebcSreyk int
692d09d3a7dSreyk ec25519_create_exchange(struct group *group, uint8_t *buf)
69345135ebcSreyk {
69445135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
69545135ebcSreyk 
69645135ebcSreyk 	memcpy(buf, curve25519->public, ec25519_getlen(group));
69745135ebcSreyk 	return (0);
69845135ebcSreyk }
69945135ebcSreyk 
70045135ebcSreyk int
701d09d3a7dSreyk ec25519_create_shared(struct group *group, uint8_t *shared, uint8_t *public)
70245135ebcSreyk {
70345135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
70445135ebcSreyk 
70545135ebcSreyk 	crypto_scalarmult_curve25519(shared, curve25519->secret, public);
70645135ebcSreyk 	return (0);
70745135ebcSreyk }
708