xref: /openbsd/sbin/iked/dh.c (revision a6321d0f)
1*a6321d0fSpatrick /*	$OpenBSD: dh.c,v 1.21 2017/10/27 14:26:35 patrick 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 
3845135ebcSreyk /* EC2N/ECP */
3945ae9d61Sreyk int	ec_init(struct group *);
4045ae9d61Sreyk int	ec_getlen(struct group *);
41*a6321d0fSpatrick 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 
45*a6321d0fSpatrick #define EC_POINT2RAW_FULL	0
46*a6321d0fSpatrick #define EC_POINT2RAW_XONLY	1
47*a6321d0fSpatrick 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 	},
86369beec1Sreyk 	{ GROUP_EC2N, 3, 155, NULL, NULL, NID_ipsec3 },
87369beec1Sreyk 	{ GROUP_EC2N, 4, 185, NULL, NULL, NID_ipsec4 },
8845ae9d61Sreyk 	{ GROUP_MODP, 5, 1536,
8945ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
9045ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
9145ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
9245ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
9345ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
9445ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
9545ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
9645ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
9745ae9d61Sreyk 	    "02"
9845ae9d61Sreyk 	},
9945ae9d61Sreyk 	{ GROUP_MODP, 14, 2048,
10045ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
10145ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
10245ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
10345ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
10445ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
10545ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
10645ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
10745ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
10845ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
10945ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
11045ae9d61Sreyk 	    "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
11145ae9d61Sreyk 	    "02"
11245ae9d61Sreyk 	},
11345ae9d61Sreyk 	{ GROUP_MODP, 15, 3072,
11445ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
11545ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
11645ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
11745ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
11845ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
11945ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
12045ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
12145ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
12245ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
12345ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
12445ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
12545ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
12645ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
12745ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
12845ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
12945ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF",
13045ae9d61Sreyk 	    "02"
13145ae9d61Sreyk 	},
13245ae9d61Sreyk 	{ GROUP_MODP, 16, 4096,
13345ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
13445ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
13545ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
13645ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
13745ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
13845ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
13945ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
14045ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
14145ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
14245ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
14345ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
14445ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
14545ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
14645ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
14745ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
14845ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
14945ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
15045ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
15145ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
15245ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
15345ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
15445ae9d61Sreyk 	    "FFFFFFFFFFFFFFFF",
15545ae9d61Sreyk 	    "02"
15645ae9d61Sreyk 	},
15745ae9d61Sreyk 	{ GROUP_MODP, 17, 6144,
15845ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
15945ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
16045ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
16145ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
16245ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
16345ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
16445ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
16545ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
16645ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
16745ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
16845ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
16945ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
17045ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
17145ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
17245ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
17345ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
17445ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
17545ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
17645ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
17745ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
17845ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
17945ae9d61Sreyk 	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
18045ae9d61Sreyk 	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
18145ae9d61Sreyk 	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
18245ae9d61Sreyk 	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
18345ae9d61Sreyk 	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
18445ae9d61Sreyk 	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
18545ae9d61Sreyk 	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
18645ae9d61Sreyk 	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
18745ae9d61Sreyk 	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
18845ae9d61Sreyk 	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
18945ae9d61Sreyk 	    "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF",
19045ae9d61Sreyk 	    "02"
19145ae9d61Sreyk 	},
19245ae9d61Sreyk 	{ GROUP_MODP, 18, 8192,
19345ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
19445ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
19545ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
19645ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
19745ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
19845ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
19945ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
20045ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
20145ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
20245ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
20345ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
20445ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
20545ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
20645ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
20745ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
20845ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
20945ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
21045ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
21145ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
21245ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
21345ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
21445ae9d61Sreyk 	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
21545ae9d61Sreyk 	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
21645ae9d61Sreyk 	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
21745ae9d61Sreyk 	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
21845ae9d61Sreyk 	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
21945ae9d61Sreyk 	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
22045ae9d61Sreyk 	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
22145ae9d61Sreyk 	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
22245ae9d61Sreyk 	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
22345ae9d61Sreyk 	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
22445ae9d61Sreyk 	    "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
22545ae9d61Sreyk 	    "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
22645ae9d61Sreyk 	    "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
22745ae9d61Sreyk 	    "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
22845ae9d61Sreyk 	    "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
22945ae9d61Sreyk 	    "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
23045ae9d61Sreyk 	    "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
23145ae9d61Sreyk 	    "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
23245ae9d61Sreyk 	    "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
23345ae9d61Sreyk 	    "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
23445ae9d61Sreyk 	    "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
23545ae9d61Sreyk 	    "60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
23645ae9d61Sreyk 	    "02"
23745ae9d61Sreyk 	},
238369beec1Sreyk 	{ GROUP_ECP, 19, 256, NULL, NULL, NID_X9_62_prime256v1 },
239369beec1Sreyk 	{ GROUP_ECP, 20, 384, NULL, NULL, NID_secp384r1 },
240369beec1Sreyk 	{ GROUP_ECP, 21, 521, NULL, NULL, NID_secp521r1 },
241369beec1Sreyk 	{ GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 },
242547eb84dSreyk 	{ GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 },
243547eb84dSreyk 	{ GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 },
244547eb84dSreyk 	{ GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 },
245547eb84dSreyk 	{ GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 },
24645135ebcSreyk 	{ GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 },
24745135ebcSreyk 
24845135ebcSreyk 	/* "Private use" extensions */
24945135ebcSreyk 	{ GROUP_CURVE25519, 1034, CURVE25519_SIZE * 8 }
25045ae9d61Sreyk };
25145ae9d61Sreyk 
25245ae9d61Sreyk void
25345ae9d61Sreyk group_init(void)
25445ae9d61Sreyk {
2550d5bf58dSreyk 	/* currently not used */
25645ae9d61Sreyk 	return;
25745ae9d61Sreyk }
25845ae9d61Sreyk 
25945ae9d61Sreyk void
26045ae9d61Sreyk group_free(struct group *group)
26145ae9d61Sreyk {
26245ae9d61Sreyk 	if (group == NULL)
26345ae9d61Sreyk 		return;
26445ae9d61Sreyk 	if (group->dh != NULL)
26545ae9d61Sreyk 		DH_free(group->dh);
26645ae9d61Sreyk 	if (group->ec != NULL)
26745ae9d61Sreyk 		EC_KEY_free(group->ec);
26829b4e2eaSderaadt 	freezero(group->curve25519, sizeof(struct curve25519_key));
26945ae9d61Sreyk 	group->spec = NULL;
27064449014Sreyk 	free(group);
27145ae9d61Sreyk }
27245ae9d61Sreyk 
27345ae9d61Sreyk struct group *
274d09d3a7dSreyk group_get(uint32_t id)
27545ae9d61Sreyk {
276e254d6eaSmikeb 	const struct group_id	*p;
27745ae9d61Sreyk 	struct group		*group;
27845ae9d61Sreyk 
279e254d6eaSmikeb 	if ((p = group_getid(id)) == NULL)
28045ae9d61Sreyk 		return (NULL);
28145ae9d61Sreyk 
28245ae9d61Sreyk 	if ((group = calloc(1, sizeof(*group))) == NULL)
28345ae9d61Sreyk 		return (NULL);
28445ae9d61Sreyk 
28545ae9d61Sreyk 	group->id = id;
28645ae9d61Sreyk 	group->spec = p;
28745ae9d61Sreyk 
28845ae9d61Sreyk 	switch (p->type) {
28945ae9d61Sreyk 	case GROUP_MODP:
29045ae9d61Sreyk 		group->init = modp_init;
29145ae9d61Sreyk 		group->getlen = modp_getlen;
29245ae9d61Sreyk 		group->exchange = modp_create_exchange;
29345ae9d61Sreyk 		group->shared = modp_create_shared;
29445ae9d61Sreyk 		break;
295369beec1Sreyk 	case GROUP_EC2N:
296369beec1Sreyk 	case GROUP_ECP:
29745ae9d61Sreyk 		group->init = ec_init;
29845ae9d61Sreyk 		group->getlen = ec_getlen;
299*a6321d0fSpatrick 		group->secretlen = ec_secretlen;
30045ae9d61Sreyk 		group->exchange = ec_create_exchange;
30145ae9d61Sreyk 		group->shared = ec_create_shared;
30245ae9d61Sreyk 		break;
30345135ebcSreyk 	case GROUP_CURVE25519:
30445135ebcSreyk 		group->init = ec25519_init;
30545135ebcSreyk 		group->getlen = ec25519_getlen;
30645135ebcSreyk 		group->exchange = ec25519_create_exchange;
30745135ebcSreyk 		group->shared = ec25519_create_shared;
30845135ebcSreyk 		break;
30945ae9d61Sreyk 	default:
31045ae9d61Sreyk 		group_free(group);
31145ae9d61Sreyk 		return (NULL);
31245ae9d61Sreyk 	}
31345ae9d61Sreyk 
31445ae9d61Sreyk 	if (dh_init(group) != 0) {
31545ae9d61Sreyk 		group_free(group);
31645ae9d61Sreyk 		return (NULL);
31745ae9d61Sreyk 	}
31845ae9d61Sreyk 
31945ae9d61Sreyk 	return (group);
32045ae9d61Sreyk }
32145ae9d61Sreyk 
322e254d6eaSmikeb const struct group_id *
323e254d6eaSmikeb group_getid(uint32_t id)
324e254d6eaSmikeb {
325e254d6eaSmikeb 	const struct group_id	*p = NULL;
326e254d6eaSmikeb 	unsigned int		 i, items;
327e254d6eaSmikeb 
328e254d6eaSmikeb 	items = sizeof(ike_groups) / sizeof(ike_groups[0]);
329e254d6eaSmikeb 	for (i = 0; i < items; i++) {
330e254d6eaSmikeb 		if (id == ike_groups[i].id) {
331e254d6eaSmikeb 			p = &ike_groups[i];
332e254d6eaSmikeb 			break;
333e254d6eaSmikeb 		}
334e254d6eaSmikeb 	}
335e254d6eaSmikeb 	return (p);
336e254d6eaSmikeb }
337e254d6eaSmikeb 
33845ae9d61Sreyk int
33945ae9d61Sreyk dh_init(struct group *group)
34045ae9d61Sreyk {
34145ae9d61Sreyk 	return (group->init(group));
34245ae9d61Sreyk }
34345ae9d61Sreyk 
34445ae9d61Sreyk int
34545ae9d61Sreyk dh_getlen(struct group *group)
34645ae9d61Sreyk {
34745ae9d61Sreyk 	return (group->getlen(group));
34845ae9d61Sreyk }
34945ae9d61Sreyk 
35045ae9d61Sreyk int
351*a6321d0fSpatrick dh_secretlen(struct group *group)
352*a6321d0fSpatrick {
353*a6321d0fSpatrick 	if (group->secretlen)
354*a6321d0fSpatrick 		return (group->secretlen(group));
355*a6321d0fSpatrick 	else
356*a6321d0fSpatrick 		return (group->getlen(group));
357*a6321d0fSpatrick }
358*a6321d0fSpatrick 
359*a6321d0fSpatrick int
360d09d3a7dSreyk dh_create_exchange(struct group *group, uint8_t *buf)
36145ae9d61Sreyk {
36245ae9d61Sreyk 	return (group->exchange(group, buf));
36345ae9d61Sreyk }
36445ae9d61Sreyk 
36545ae9d61Sreyk int
366d09d3a7dSreyk dh_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange)
36745ae9d61Sreyk {
36845ae9d61Sreyk 	return (group->shared(group, secret, exchange));
36945ae9d61Sreyk }
37045ae9d61Sreyk 
37145ae9d61Sreyk int
37245ae9d61Sreyk modp_init(struct group *group)
37345ae9d61Sreyk {
37445ae9d61Sreyk 	DH	*dh;
37545ae9d61Sreyk 
37645ae9d61Sreyk 	if ((dh = DH_new()) == NULL)
37745ae9d61Sreyk 		return (-1);
3787d7b0856Sreyk 	group->dh = dh;
37945ae9d61Sreyk 
38045ae9d61Sreyk 	if (!BN_hex2bn(&dh->p, group->spec->prime) ||
38145ae9d61Sreyk 	    !BN_hex2bn(&dh->g, group->spec->generator))
38245ae9d61Sreyk 		return (-1);
38345ae9d61Sreyk 
38445ae9d61Sreyk 	return (0);
38545ae9d61Sreyk }
38645ae9d61Sreyk 
38745ae9d61Sreyk int
38845ae9d61Sreyk modp_getlen(struct group *group)
38945ae9d61Sreyk {
39045ae9d61Sreyk 	if (group->spec == NULL)
39145ae9d61Sreyk 		return (0);
39245ae9d61Sreyk 	return (roundup(group->spec->bits, 8) / 8);
39345ae9d61Sreyk }
39445ae9d61Sreyk 
39545ae9d61Sreyk int
396d09d3a7dSreyk modp_create_exchange(struct group *group, uint8_t *buf)
39745ae9d61Sreyk {
39845ae9d61Sreyk 	DH	*dh = group->dh;
39912abf43bSmikeb 	int	 len, ret;
40045ae9d61Sreyk 
40145ae9d61Sreyk 	if (!DH_generate_key(dh))
40245ae9d61Sreyk 		return (-1);
40312abf43bSmikeb 	ret = BN_bn2bin(dh->pub_key, buf);
40412abf43bSmikeb 	if (!ret)
40545ae9d61Sreyk 		return (-1);
40645ae9d61Sreyk 
40712abf43bSmikeb 	len = dh_getlen(group);
40812abf43bSmikeb 
40912abf43bSmikeb 	/* add zero padding */
41012abf43bSmikeb 	if (ret < len) {
41112abf43bSmikeb 		bcopy(buf, buf + (len - ret), ret);
41212abf43bSmikeb 		bzero(buf, len - ret);
41312abf43bSmikeb 	}
41412abf43bSmikeb 
4157d7b0856Sreyk 	return (0);
41645ae9d61Sreyk }
41745ae9d61Sreyk 
41845ae9d61Sreyk int
419d09d3a7dSreyk modp_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange)
42045ae9d61Sreyk {
42145ae9d61Sreyk 	BIGNUM	*ex;
42212abf43bSmikeb 	int	 len, ret;
42345ae9d61Sreyk 
42412abf43bSmikeb 	len = dh_getlen(group);
42512abf43bSmikeb 
42612abf43bSmikeb 	if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL)
42745ae9d61Sreyk 		return (-1);
4287d7b0856Sreyk 
4297d7b0856Sreyk 	ret = DH_compute_key(secret, ex, group->dh);
4307d7b0856Sreyk 	BN_clear_free(ex);
4312ffa77eaSjsg 	if (ret <= 0)
43245ae9d61Sreyk 		return (-1);
43345ae9d61Sreyk 
43412abf43bSmikeb 	/* add zero padding */
43512abf43bSmikeb 	if (ret < len) {
43612abf43bSmikeb 		bcopy(secret, secret + (len - ret), ret);
43712abf43bSmikeb 		bzero(secret, len - ret);
43812abf43bSmikeb 	}
43912abf43bSmikeb 
4407d7b0856Sreyk 	return (0);
44145ae9d61Sreyk }
44245ae9d61Sreyk 
44345ae9d61Sreyk int
44445ae9d61Sreyk ec_init(struct group *group)
44545ae9d61Sreyk {
44645ae9d61Sreyk 	if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL)
44745ae9d61Sreyk 		return (-1);
44845ae9d61Sreyk 	if (!EC_KEY_generate_key(group->ec))
44945ae9d61Sreyk 		return (-1);
450c900656bSmarkus 	if (!EC_KEY_check_key(group->ec)) {
451c900656bSmarkus 		EC_KEY_free(group->ec);
452c900656bSmarkus 		return (-1);
453c900656bSmarkus 	}
45445ae9d61Sreyk 	return (0);
45545ae9d61Sreyk }
45645ae9d61Sreyk 
45745ae9d61Sreyk int
45845ae9d61Sreyk ec_getlen(struct group *group)
45945ae9d61Sreyk {
46045ae9d61Sreyk 	if (group->spec == NULL)
46145ae9d61Sreyk 		return (0);
46245b72fd1Smikeb 	/* NB:  Return value will always be even */
46345ae9d61Sreyk 	return ((roundup(group->spec->bits, 8) * 2) / 8);
46445ae9d61Sreyk }
46545ae9d61Sreyk 
466*a6321d0fSpatrick /*
467*a6321d0fSpatrick  * Note that the shared secret only includes the x value:
468*a6321d0fSpatrick  *
469*a6321d0fSpatrick  * See RFC 5903, 7. ECP Key Exchange Data Formats:
470*a6321d0fSpatrick  *   The Diffie-Hellman shared secret value consists of the x value of the
471*a6321d0fSpatrick  *   Diffie-Hellman common value.
472*a6321d0fSpatrick  * See also RFC 5903, 9. Changes from RFC 4753.
473*a6321d0fSpatrick  */
474*a6321d0fSpatrick int
475*a6321d0fSpatrick ec_secretlen(struct group *group)
476*a6321d0fSpatrick {
477*a6321d0fSpatrick 	return (ec_getlen(group) / 2);
478*a6321d0fSpatrick }
479*a6321d0fSpatrick 
48045ae9d61Sreyk int
481d09d3a7dSreyk ec_create_exchange(struct group *group, uint8_t *buf)
48245ae9d61Sreyk {
4830d5bf58dSreyk 	size_t	 len;
4840d5bf58dSreyk 
4850d5bf58dSreyk 	len = ec_getlen(group);
4860d5bf58dSreyk 	bzero(buf, len);
4870d5bf58dSreyk 
48845ae9d61Sreyk 	return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec),
489*a6321d0fSpatrick 	    buf, len, EC_POINT2RAW_FULL));
49045ae9d61Sreyk }
49145ae9d61Sreyk 
49245ae9d61Sreyk int
493d09d3a7dSreyk ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange)
49445ae9d61Sreyk {
49545ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
49645ae9d61Sreyk 	const BIGNUM	*privkey;
497c900656bSmarkus 	EC_KEY		*exkey = NULL;
49845ae9d61Sreyk 	EC_POINT	*exchangep = NULL, *secretp = NULL;
49945ae9d61Sreyk 	int		 ret = -1;
50045ae9d61Sreyk 
50145ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL ||
50245ae9d61Sreyk 	    (privkey = EC_KEY_get0_private_key(group->ec)) == NULL)
50345ae9d61Sreyk 		goto done;
50445ae9d61Sreyk 
50545ae9d61Sreyk 	if ((exchangep =
50645ae9d61Sreyk 	    ec_raw2point(group, exchange, ec_getlen(group))) == NULL)
50745ae9d61Sreyk 		goto done;
50845ae9d61Sreyk 
509c900656bSmarkus 	if ((exkey = EC_KEY_new()) == NULL)
510c900656bSmarkus 		goto done;
511c900656bSmarkus 	if (!EC_KEY_set_group(exkey, ecgroup))
512c900656bSmarkus 		goto done;
513c900656bSmarkus 	if (!EC_KEY_set_public_key(exkey, exchangep))
514c900656bSmarkus 		goto done;
515c900656bSmarkus 
516c900656bSmarkus 	/* validate exchangep */
517c900656bSmarkus 	if (!EC_KEY_check_key(exkey))
518c900656bSmarkus 		goto done;
519c900656bSmarkus 
52045ae9d61Sreyk 	if ((secretp = EC_POINT_new(ecgroup)) == NULL)
52145ae9d61Sreyk 		goto done;
52245ae9d61Sreyk 
52345ae9d61Sreyk 	if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL))
52445ae9d61Sreyk 		goto done;
52545ae9d61Sreyk 
526*a6321d0fSpatrick 	ret = ec_point2raw(group, secretp, secret, ec_secretlen(group),
527*a6321d0fSpatrick 	    EC_POINT2RAW_XONLY);
52845ae9d61Sreyk 
52945ae9d61Sreyk  done:
530c900656bSmarkus 	if (exkey != NULL)
531c900656bSmarkus 		EC_KEY_free(exkey);
53245ae9d61Sreyk 	if (exchangep != NULL)
53345ae9d61Sreyk 		EC_POINT_clear_free(exchangep);
53445ae9d61Sreyk 	if (secretp != NULL)
53545ae9d61Sreyk 		EC_POINT_clear_free(secretp);
53645ae9d61Sreyk 
53745ae9d61Sreyk 	return (ret);
53845ae9d61Sreyk }
53945ae9d61Sreyk 
54045ae9d61Sreyk int
54145ae9d61Sreyk ec_point2raw(struct group *group, const EC_POINT *point,
542*a6321d0fSpatrick     uint8_t *buf, size_t len, int mode)
54345ae9d61Sreyk {
54445ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
54545ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
54645ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
54745ae9d61Sreyk 	int		 ret = -1;
54845b72fd1Smikeb 	size_t		 eclen, xlen, ylen;
54945ae9d61Sreyk 	off_t		 xoff, yoff;
55045ae9d61Sreyk 
55145ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
55245ae9d61Sreyk 		goto done;
55345ae9d61Sreyk 	BN_CTX_start(bnctx);
55445ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
55545ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
55645ae9d61Sreyk 		goto done;
55745ae9d61Sreyk 
55845b72fd1Smikeb 	eclen = ec_getlen(group);
559*a6321d0fSpatrick 	switch (mode) {
560*a6321d0fSpatrick 	case EC_POINT2RAW_XONLY:
561*a6321d0fSpatrick 		xlen = eclen / 2;
562*a6321d0fSpatrick 		ylen = 0;
563*a6321d0fSpatrick 		break;
564*a6321d0fSpatrick 	case EC_POINT2RAW_FULL:
56545b72fd1Smikeb 		xlen = ylen = eclen / 2;
566*a6321d0fSpatrick 		break;
567*a6321d0fSpatrick 	default:
568*a6321d0fSpatrick 		goto done;
569*a6321d0fSpatrick 	}
570*a6321d0fSpatrick 	if (len < xlen + ylen)
571*a6321d0fSpatrick 		goto done;
57245b72fd1Smikeb 
57345ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
57445ae9d61Sreyk 		goto done;
57545ae9d61Sreyk 
57645ae9d61Sreyk 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) ==
57745ae9d61Sreyk 	    NID_X9_62_prime_field) {
57845ae9d61Sreyk 		if (!EC_POINT_get_affine_coordinates_GFp(ecgroup,
57945ae9d61Sreyk 		    point, x, y, bnctx))
58045ae9d61Sreyk 			goto done;
58145ae9d61Sreyk 	} else {
58245ae9d61Sreyk 		if (!EC_POINT_get_affine_coordinates_GF2m(ecgroup,
58345ae9d61Sreyk 		    point, x, y, bnctx))
58445ae9d61Sreyk 			goto done;
58545ae9d61Sreyk 	}
58645ae9d61Sreyk 
58745ae9d61Sreyk 	xoff = xlen - BN_num_bytes(x);
58845b72fd1Smikeb 	bzero(buf, xoff);
58945ae9d61Sreyk 	if (!BN_bn2bin(x, buf + xoff))
59045ae9d61Sreyk 		goto done;
59145ae9d61Sreyk 
592*a6321d0fSpatrick 	if (ylen > 0) {
59345ae9d61Sreyk 		yoff = (ylen - BN_num_bytes(y)) + xlen;
59445b72fd1Smikeb 		bzero(buf + xlen, yoff - xlen);
59545ae9d61Sreyk 		if (!BN_bn2bin(y, buf + yoff))
59645ae9d61Sreyk 			goto done;
597*a6321d0fSpatrick 	}
59845ae9d61Sreyk 
59945ae9d61Sreyk 	ret = 0;
60045ae9d61Sreyk  done:
601c900656bSmarkus 	/* Make sure to erase sensitive data */
602c900656bSmarkus 	if (x != NULL)
603c900656bSmarkus 		BN_clear(x);
604c900656bSmarkus 	if (y != NULL)
605c900656bSmarkus 		BN_clear(y);
60645ae9d61Sreyk 	BN_CTX_end(bnctx);
60745ae9d61Sreyk 	BN_CTX_free(bnctx);
60845ae9d61Sreyk 
60945ae9d61Sreyk 	return (ret);
61045ae9d61Sreyk }
61145ae9d61Sreyk 
61245ae9d61Sreyk EC_POINT *
613d09d3a7dSreyk ec_raw2point(struct group *group, uint8_t *buf, size_t len)
61445ae9d61Sreyk {
61545ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
61645ae9d61Sreyk 	EC_POINT	*point = NULL;
61745ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
61845ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
61945ae9d61Sreyk 	int		 ret = -1;
62045ae9d61Sreyk 	size_t		 eclen;
62145ae9d61Sreyk 	size_t		 xlen, ylen;
62245ae9d61Sreyk 
62345ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
62445ae9d61Sreyk 		goto done;
62545ae9d61Sreyk 	BN_CTX_start(bnctx);
62645ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
62745ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
62845ae9d61Sreyk 		goto done;
62945ae9d61Sreyk 
63045ae9d61Sreyk 	eclen = ec_getlen(group);
63145ae9d61Sreyk 	if (len < eclen)
63245ae9d61Sreyk 		goto done;
63345ae9d61Sreyk 	xlen = ylen = eclen / 2;
63445ae9d61Sreyk 	if ((x = BN_bin2bn(buf, xlen, x)) == NULL ||
63545ae9d61Sreyk 	    (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL)
63645ae9d61Sreyk 		goto done;
63745ae9d61Sreyk 
63845ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
63945ae9d61Sreyk 		goto done;
64045ae9d61Sreyk 
64145ae9d61Sreyk 	if ((point = EC_POINT_new(ecgroup)) == NULL)
64245ae9d61Sreyk 		goto done;
64345ae9d61Sreyk 
64445ae9d61Sreyk 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) ==
64545ae9d61Sreyk 	    NID_X9_62_prime_field) {
64645ae9d61Sreyk 		if (!EC_POINT_set_affine_coordinates_GFp(ecgroup,
64745ae9d61Sreyk 		    point, x, y, bnctx))
64845ae9d61Sreyk 			goto done;
64945ae9d61Sreyk 	} else {
65045ae9d61Sreyk 		if (!EC_POINT_set_affine_coordinates_GF2m(ecgroup,
65145ae9d61Sreyk 		    point, x, y, bnctx))
65245ae9d61Sreyk 			goto done;
65345ae9d61Sreyk 	}
65445ae9d61Sreyk 
65545ae9d61Sreyk 	ret = 0;
65645ae9d61Sreyk  done:
65745ae9d61Sreyk 	if (ret != 0 && point != NULL)
65845ae9d61Sreyk 		EC_POINT_clear_free(point);
659c900656bSmarkus 	/* Make sure to erase sensitive data */
660c900656bSmarkus 	if (x != NULL)
661c900656bSmarkus 		BN_clear(x);
662c900656bSmarkus 	if (y != NULL)
663c900656bSmarkus 		BN_clear(y);
66445ae9d61Sreyk 	BN_CTX_end(bnctx);
66545ae9d61Sreyk 	BN_CTX_free(bnctx);
66645ae9d61Sreyk 
66745ae9d61Sreyk 	return (point);
66845ae9d61Sreyk }
66945135ebcSreyk 
67045135ebcSreyk int
67145135ebcSreyk ec25519_init(struct group *group)
67245135ebcSreyk {
673d09d3a7dSreyk 	static const uint8_t	 basepoint[CURVE25519_SIZE] = { 9 };
67445135ebcSreyk 	struct curve25519_key	*curve25519;
67545135ebcSreyk 
67645135ebcSreyk 	if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL)
67745135ebcSreyk 		return (-1);
67845135ebcSreyk 
67945135ebcSreyk 	group->curve25519 = curve25519;
68045135ebcSreyk 
68145135ebcSreyk 	arc4random_buf(curve25519->secret, CURVE25519_SIZE);
68245135ebcSreyk 	crypto_scalarmult_curve25519(curve25519->public,
68345135ebcSreyk 	    curve25519->secret, basepoint);
68445135ebcSreyk 
68545135ebcSreyk 	return (0);
68645135ebcSreyk }
68745135ebcSreyk 
68845135ebcSreyk int
68945135ebcSreyk ec25519_getlen(struct group *group)
69045135ebcSreyk {
69145135ebcSreyk 	if (group->spec == NULL)
69245135ebcSreyk 		return (0);
69345135ebcSreyk 	return (CURVE25519_SIZE);
69445135ebcSreyk }
69545135ebcSreyk 
69645135ebcSreyk int
697d09d3a7dSreyk ec25519_create_exchange(struct group *group, uint8_t *buf)
69845135ebcSreyk {
69945135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
70045135ebcSreyk 
70145135ebcSreyk 	memcpy(buf, curve25519->public, ec25519_getlen(group));
70245135ebcSreyk 	return (0);
70345135ebcSreyk }
70445135ebcSreyk 
70545135ebcSreyk int
706d09d3a7dSreyk ec25519_create_shared(struct group *group, uint8_t *shared, uint8_t *public)
70745135ebcSreyk {
70845135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
70945135ebcSreyk 
71045135ebcSreyk 	crypto_scalarmult_curve25519(shared, curve25519->secret, public);
71145135ebcSreyk 	return (0);
71245135ebcSreyk }
713