1*0e1bb3dcStobhe /* $OpenBSD: dh.c,v 1.27 2021/02/04 20:38:26 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 22710c50d7Stobhe #include <sys/queue.h> 23710c50d7Stobhe #include <sys/socket.h> 24710c50d7Stobhe #include <sys/uio.h> 25710c50d7Stobhe #include <event.h> 26710c50d7Stobhe #include <imsg.h> 27710c50d7Stobhe 28710c50d7Stobhe #include <openssl/evp.h> 29710c50d7Stobhe #include <openssl/sha.h> 3045ae9d61Sreyk #include <openssl/obj_mac.h> 3145ae9d61Sreyk #include <openssl/dh.h> 3245ae9d61Sreyk #include <openssl/ec.h> 3345ae9d61Sreyk #include <openssl/ecdh.h> 34a4194998Sjsg #include <openssl/bn.h> 3545ae9d61Sreyk 3645ae9d61Sreyk #include "dh.h" 37710c50d7Stobhe #include "iked.h" 380d5bf58dSreyk 39*0e1bb3dcStobhe int dh_init(struct dh_group *); 40*0e1bb3dcStobhe int dh_getlen(struct dh_group *); 41*0e1bb3dcStobhe int dh_secretlen(struct dh_group *); 4245ae9d61Sreyk 4345135ebcSreyk /* MODP */ 44*0e1bb3dcStobhe int modp_init(struct dh_group *); 45*0e1bb3dcStobhe int modp_getlen(struct dh_group *); 46*0e1bb3dcStobhe int modp_create_exchange(struct dh_group *, uint8_t *); 47*0e1bb3dcStobhe int modp_create_shared(struct dh_group *, uint8_t *, uint8_t *); 4845ae9d61Sreyk 49bc77414bStobhe /* ECP */ 50*0e1bb3dcStobhe int ec_init(struct dh_group *); 51*0e1bb3dcStobhe int ec_getlen(struct dh_group *); 52*0e1bb3dcStobhe int ec_secretlen(struct dh_group *); 53*0e1bb3dcStobhe int ec_create_exchange(struct dh_group *, uint8_t *); 54*0e1bb3dcStobhe int ec_create_shared(struct dh_group *, uint8_t *, uint8_t *); 5545ae9d61Sreyk 56a6321d0fSpatrick #define EC_POINT2RAW_FULL 0 57a6321d0fSpatrick #define EC_POINT2RAW_XONLY 1 58*0e1bb3dcStobhe int ec_point2raw(struct dh_group *, const EC_POINT *, uint8_t *, size_t, int); 5945ae9d61Sreyk EC_POINT * 60*0e1bb3dcStobhe ec_raw2point(struct dh_group *, uint8_t *, size_t); 6145ae9d61Sreyk 6245135ebcSreyk /* curve25519 */ 63*0e1bb3dcStobhe int ec25519_init(struct dh_group *); 64*0e1bb3dcStobhe int ec25519_getlen(struct dh_group *); 65*0e1bb3dcStobhe int ec25519_create_exchange(struct dh_group *, uint8_t *); 66*0e1bb3dcStobhe int ec25519_create_shared(struct dh_group *, uint8_t *, uint8_t *); 6745135ebcSreyk 6845135ebcSreyk #define CURVE25519_SIZE 32 /* 256 bits */ 6945135ebcSreyk struct curve25519_key { 70d09d3a7dSreyk uint8_t secret[CURVE25519_SIZE]; 71d09d3a7dSreyk uint8_t public[CURVE25519_SIZE]; 7245135ebcSreyk }; 73d09d3a7dSreyk extern int crypto_scalarmult_curve25519(unsigned char a[CURVE25519_SIZE], 74d09d3a7dSreyk const unsigned char b[CURVE25519_SIZE], 75d09d3a7dSreyk const unsigned char c[CURVE25519_SIZE]) 7645135ebcSreyk __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) 7745135ebcSreyk __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))) 7845135ebcSreyk __attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE))); 7945135ebcSreyk 80e254d6eaSmikeb const struct group_id ike_groups[] = { 8145ae9d61Sreyk { GROUP_MODP, 1, 768, 8245ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 8345ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 8445ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 8545ae9d61Sreyk "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 8645ae9d61Sreyk "02" 8745ae9d61Sreyk }, 8845ae9d61Sreyk { GROUP_MODP, 2, 1024, 8945ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 9045ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 9145ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 9245ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 9345ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" 9445ae9d61Sreyk "FFFFFFFFFFFFFFFF", 9545ae9d61Sreyk "02" 9645ae9d61Sreyk }, 9745ae9d61Sreyk { GROUP_MODP, 5, 1536, 9845ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 9945ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 10045ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 10145ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 10245ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 10345ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 10445ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 10545ae9d61Sreyk "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 10645ae9d61Sreyk "02" 10745ae9d61Sreyk }, 10845ae9d61Sreyk { GROUP_MODP, 14, 2048, 10945ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 11045ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 11145ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 11245ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 11345ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 11445ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 11545ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 11645ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 11745ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 11845ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 11945ae9d61Sreyk "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 12045ae9d61Sreyk "02" 12145ae9d61Sreyk }, 12245ae9d61Sreyk { GROUP_MODP, 15, 3072, 12345ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 12445ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 12545ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 12645ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 12745ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 12845ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 12945ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 13045ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 13145ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 13245ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 13345ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 13445ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 13545ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 13645ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 13745ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 13845ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 13945ae9d61Sreyk "02" 14045ae9d61Sreyk }, 14145ae9d61Sreyk { GROUP_MODP, 16, 4096, 14245ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 14345ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 14445ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 14545ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 14645ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 14745ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 14845ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 14945ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 15045ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 15145ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 15245ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 15345ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 15445ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 15545ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 15645ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 15745ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" 15845ae9d61Sreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" 15945ae9d61Sreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" 16045ae9d61Sreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" 16145ae9d61Sreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" 16245ae9d61Sreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" 16345ae9d61Sreyk "FFFFFFFFFFFFFFFF", 16445ae9d61Sreyk "02" 16545ae9d61Sreyk }, 16645ae9d61Sreyk { GROUP_MODP, 17, 6144, 16745ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 16845ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 16945ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 17045ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 17145ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 17245ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 17345ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 17445ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 17545ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 17645ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 17745ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 17845ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 17945ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 18045ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 18145ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 18245ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" 18345ae9d61Sreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" 18445ae9d61Sreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" 18545ae9d61Sreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" 18645ae9d61Sreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" 18745ae9d61Sreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" 18845ae9d61Sreyk "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" 18945ae9d61Sreyk "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" 19045ae9d61Sreyk "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" 19145ae9d61Sreyk "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" 19245ae9d61Sreyk "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" 19345ae9d61Sreyk "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" 19445ae9d61Sreyk "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" 19545ae9d61Sreyk "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" 19645ae9d61Sreyk "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" 19745ae9d61Sreyk "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" 19845ae9d61Sreyk "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", 19945ae9d61Sreyk "02" 20045ae9d61Sreyk }, 20145ae9d61Sreyk { GROUP_MODP, 18, 8192, 20245ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 20345ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 20445ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 20545ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 20645ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 20745ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 20845ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 20945ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 21045ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 21145ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 21245ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 21345ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 21445ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 21545ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 21645ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 21745ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" 21845ae9d61Sreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" 21945ae9d61Sreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" 22045ae9d61Sreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" 22145ae9d61Sreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" 22245ae9d61Sreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" 22345ae9d61Sreyk "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" 22445ae9d61Sreyk "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" 22545ae9d61Sreyk "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" 22645ae9d61Sreyk "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" 22745ae9d61Sreyk "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" 22845ae9d61Sreyk "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" 22945ae9d61Sreyk "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" 23045ae9d61Sreyk "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" 23145ae9d61Sreyk "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" 23245ae9d61Sreyk "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" 23345ae9d61Sreyk "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" 23445ae9d61Sreyk "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" 23545ae9d61Sreyk "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" 23645ae9d61Sreyk "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" 23745ae9d61Sreyk "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" 23845ae9d61Sreyk "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" 23945ae9d61Sreyk "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" 24045ae9d61Sreyk "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" 24145ae9d61Sreyk "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" 24245ae9d61Sreyk "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" 24345ae9d61Sreyk "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" 24445ae9d61Sreyk "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 24545ae9d61Sreyk "02" 24645ae9d61Sreyk }, 247369beec1Sreyk { GROUP_ECP, 19, 256, NULL, NULL, NID_X9_62_prime256v1 }, 248369beec1Sreyk { GROUP_ECP, 20, 384, NULL, NULL, NID_secp384r1 }, 249369beec1Sreyk { GROUP_ECP, 21, 521, NULL, NULL, NID_secp521r1 }, 250369beec1Sreyk { GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 }, 251547eb84dSreyk { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 }, 252547eb84dSreyk { GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 }, 253547eb84dSreyk { GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 }, 254547eb84dSreyk { GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 }, 25545135ebcSreyk { GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 }, 256337280ecSsthen { GROUP_CURVE25519, 31, CURVE25519_SIZE * 8 } 25745ae9d61Sreyk }; 25845ae9d61Sreyk 25945ae9d61Sreyk void 26045ae9d61Sreyk group_init(void) 26145ae9d61Sreyk { 2620d5bf58dSreyk /* currently not used */ 26345ae9d61Sreyk return; 26445ae9d61Sreyk } 26545ae9d61Sreyk 26645ae9d61Sreyk void 267*0e1bb3dcStobhe group_free(struct dh_group *group) 26845ae9d61Sreyk { 26945ae9d61Sreyk if (group == NULL) 27045ae9d61Sreyk return; 27145ae9d61Sreyk if (group->dh != NULL) 27245ae9d61Sreyk DH_free(group->dh); 27345ae9d61Sreyk if (group->ec != NULL) 27445ae9d61Sreyk EC_KEY_free(group->ec); 27529b4e2eaSderaadt freezero(group->curve25519, sizeof(struct curve25519_key)); 27645ae9d61Sreyk group->spec = NULL; 27764449014Sreyk free(group); 27845ae9d61Sreyk } 27945ae9d61Sreyk 280*0e1bb3dcStobhe struct dh_group * 281d09d3a7dSreyk group_get(uint32_t id) 28245ae9d61Sreyk { 283e254d6eaSmikeb const struct group_id *p; 284*0e1bb3dcStobhe struct dh_group *group; 28545ae9d61Sreyk 286e254d6eaSmikeb if ((p = group_getid(id)) == NULL) 28745ae9d61Sreyk return (NULL); 28845ae9d61Sreyk 28945ae9d61Sreyk if ((group = calloc(1, sizeof(*group))) == NULL) 29045ae9d61Sreyk return (NULL); 29145ae9d61Sreyk 29245ae9d61Sreyk group->id = id; 29345ae9d61Sreyk group->spec = p; 29445ae9d61Sreyk 29545ae9d61Sreyk switch (p->type) { 29645ae9d61Sreyk case GROUP_MODP: 29745ae9d61Sreyk group->init = modp_init; 29845ae9d61Sreyk group->getlen = modp_getlen; 29945ae9d61Sreyk group->exchange = modp_create_exchange; 30045ae9d61Sreyk group->shared = modp_create_shared; 30145ae9d61Sreyk break; 302369beec1Sreyk case GROUP_ECP: 30345ae9d61Sreyk group->init = ec_init; 30445ae9d61Sreyk group->getlen = ec_getlen; 305a6321d0fSpatrick group->secretlen = ec_secretlen; 30645ae9d61Sreyk group->exchange = ec_create_exchange; 30745ae9d61Sreyk group->shared = ec_create_shared; 30845ae9d61Sreyk break; 30945135ebcSreyk case GROUP_CURVE25519: 31045135ebcSreyk group->init = ec25519_init; 31145135ebcSreyk group->getlen = ec25519_getlen; 31245135ebcSreyk group->exchange = ec25519_create_exchange; 31345135ebcSreyk group->shared = ec25519_create_shared; 31445135ebcSreyk break; 31545ae9d61Sreyk default: 31645ae9d61Sreyk group_free(group); 31745ae9d61Sreyk return (NULL); 31845ae9d61Sreyk } 31945ae9d61Sreyk 32045ae9d61Sreyk if (dh_init(group) != 0) { 32145ae9d61Sreyk group_free(group); 32245ae9d61Sreyk return (NULL); 32345ae9d61Sreyk } 32445ae9d61Sreyk 32545ae9d61Sreyk return (group); 32645ae9d61Sreyk } 32745ae9d61Sreyk 328e254d6eaSmikeb const struct group_id * 329e254d6eaSmikeb group_getid(uint32_t id) 330e254d6eaSmikeb { 331e254d6eaSmikeb const struct group_id *p = NULL; 332e254d6eaSmikeb unsigned int i, items; 333e254d6eaSmikeb 334e254d6eaSmikeb items = sizeof(ike_groups) / sizeof(ike_groups[0]); 335e254d6eaSmikeb for (i = 0; i < items; i++) { 336e254d6eaSmikeb if (id == ike_groups[i].id) { 337e254d6eaSmikeb p = &ike_groups[i]; 338e254d6eaSmikeb break; 339e254d6eaSmikeb } 340e254d6eaSmikeb } 341e254d6eaSmikeb return (p); 342e254d6eaSmikeb } 343e254d6eaSmikeb 34445ae9d61Sreyk int 345*0e1bb3dcStobhe dh_init(struct dh_group *group) 34645ae9d61Sreyk { 34745ae9d61Sreyk return (group->init(group)); 34845ae9d61Sreyk } 34945ae9d61Sreyk 35045ae9d61Sreyk int 351*0e1bb3dcStobhe dh_getlen(struct dh_group *group) 35245ae9d61Sreyk { 35345ae9d61Sreyk return (group->getlen(group)); 35445ae9d61Sreyk } 35545ae9d61Sreyk 35645ae9d61Sreyk int 357*0e1bb3dcStobhe dh_secretlen(struct dh_group *group) 358a6321d0fSpatrick { 359a6321d0fSpatrick if (group->secretlen) 360a6321d0fSpatrick return (group->secretlen(group)); 361a6321d0fSpatrick else 362a6321d0fSpatrick return (group->getlen(group)); 363a6321d0fSpatrick } 364a6321d0fSpatrick 365a6321d0fSpatrick int 366*0e1bb3dcStobhe dh_create_exchange(struct dh_group *group, struct ibuf **bufp, struct ibuf *iexchange) 36745ae9d61Sreyk { 368710c50d7Stobhe struct ibuf *buf; 369710c50d7Stobhe 370710c50d7Stobhe *bufp = NULL; 371710c50d7Stobhe buf = ibuf_new(NULL, dh_getlen(group)); 372710c50d7Stobhe if (buf == NULL) 373710c50d7Stobhe return -1; 374710c50d7Stobhe *bufp = buf; 375710c50d7Stobhe return (group->exchange(group, buf->buf)); 37645ae9d61Sreyk } 37745ae9d61Sreyk 37845ae9d61Sreyk int 379*0e1bb3dcStobhe dh_create_shared(struct dh_group *group, struct ibuf **secretp, struct ibuf *exchange) 38045ae9d61Sreyk { 381710c50d7Stobhe struct ibuf *buf; 382710c50d7Stobhe 383710c50d7Stobhe *secretp = NULL; 384710c50d7Stobhe if (exchange == NULL || 385710c50d7Stobhe (ssize_t)ibuf_size(exchange) != dh_getlen(group)) 386710c50d7Stobhe return -1; 387710c50d7Stobhe buf = ibuf_new(NULL, dh_secretlen(group)); 388710c50d7Stobhe if (buf == NULL) 389710c50d7Stobhe return -1; 390710c50d7Stobhe *secretp = buf; 391710c50d7Stobhe return (group->shared(group, buf->buf, exchange->buf)); 39245ae9d61Sreyk } 39345ae9d61Sreyk 39445ae9d61Sreyk int 395*0e1bb3dcStobhe modp_init(struct dh_group *group) 39645ae9d61Sreyk { 39708c24fddStobhe BIGNUM *g = NULL, *p = NULL; 39845ae9d61Sreyk DH *dh; 39908c24fddStobhe int ret = -1; 40045ae9d61Sreyk 40145ae9d61Sreyk if ((dh = DH_new()) == NULL) 40245ae9d61Sreyk return (-1); 40308c24fddStobhe 40408c24fddStobhe if (!BN_hex2bn(&p, group->spec->prime) || 40508c24fddStobhe !BN_hex2bn(&g, group->spec->generator) || 40608c24fddStobhe DH_set0_pqg(dh, p, NULL, g) == 0) 40708c24fddStobhe goto done; 40808c24fddStobhe 40908c24fddStobhe p = g = NULL; 4107d7b0856Sreyk group->dh = dh; 41145ae9d61Sreyk 41208c24fddStobhe ret = 0; 41308c24fddStobhe done: 41408c24fddStobhe BN_clear_free(g); 41508c24fddStobhe BN_clear_free(p); 41645ae9d61Sreyk 41708c24fddStobhe return (ret); 41845ae9d61Sreyk } 41945ae9d61Sreyk 42045ae9d61Sreyk int 421*0e1bb3dcStobhe modp_getlen(struct dh_group *group) 42245ae9d61Sreyk { 42345ae9d61Sreyk if (group->spec == NULL) 42445ae9d61Sreyk return (0); 42545ae9d61Sreyk return (roundup(group->spec->bits, 8) / 8); 42645ae9d61Sreyk } 42745ae9d61Sreyk 42845ae9d61Sreyk int 429*0e1bb3dcStobhe modp_create_exchange(struct dh_group *group, uint8_t *buf) 43045ae9d61Sreyk { 43108c24fddStobhe const BIGNUM *pub; 43245ae9d61Sreyk DH *dh = group->dh; 43312abf43bSmikeb int len, ret; 43445ae9d61Sreyk 43545ae9d61Sreyk if (!DH_generate_key(dh)) 43645ae9d61Sreyk return (-1); 43708c24fddStobhe DH_get0_key(group->dh, &pub, NULL); 43808c24fddStobhe ret = BN_bn2bin(pub, buf); 43912abf43bSmikeb if (!ret) 44045ae9d61Sreyk return (-1); 44145ae9d61Sreyk 44212abf43bSmikeb len = dh_getlen(group); 44312abf43bSmikeb 44412abf43bSmikeb /* add zero padding */ 44512abf43bSmikeb if (ret < len) { 44612abf43bSmikeb bcopy(buf, buf + (len - ret), ret); 44712abf43bSmikeb bzero(buf, len - ret); 44812abf43bSmikeb } 44912abf43bSmikeb 4507d7b0856Sreyk return (0); 45145ae9d61Sreyk } 45245ae9d61Sreyk 45345ae9d61Sreyk int 454*0e1bb3dcStobhe modp_create_shared(struct dh_group *group, uint8_t *secret, uint8_t *exchange) 45545ae9d61Sreyk { 45645ae9d61Sreyk BIGNUM *ex; 45712abf43bSmikeb int len, ret; 45845ae9d61Sreyk 45912abf43bSmikeb len = dh_getlen(group); 46012abf43bSmikeb 46112abf43bSmikeb if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL) 46245ae9d61Sreyk return (-1); 4637d7b0856Sreyk 4647d7b0856Sreyk ret = DH_compute_key(secret, ex, group->dh); 4657d7b0856Sreyk BN_clear_free(ex); 4662ffa77eaSjsg if (ret <= 0) 46745ae9d61Sreyk return (-1); 46845ae9d61Sreyk 46912abf43bSmikeb /* add zero padding */ 47012abf43bSmikeb if (ret < len) { 47112abf43bSmikeb bcopy(secret, secret + (len - ret), ret); 47212abf43bSmikeb bzero(secret, len - ret); 47312abf43bSmikeb } 47412abf43bSmikeb 4757d7b0856Sreyk return (0); 47645ae9d61Sreyk } 47745ae9d61Sreyk 47845ae9d61Sreyk int 479*0e1bb3dcStobhe ec_init(struct dh_group *group) 48045ae9d61Sreyk { 48145ae9d61Sreyk if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL) 48245ae9d61Sreyk return (-1); 48345ae9d61Sreyk if (!EC_KEY_generate_key(group->ec)) 48445ae9d61Sreyk return (-1); 485c900656bSmarkus if (!EC_KEY_check_key(group->ec)) { 486c900656bSmarkus EC_KEY_free(group->ec); 487c900656bSmarkus return (-1); 488c900656bSmarkus } 48945ae9d61Sreyk return (0); 49045ae9d61Sreyk } 49145ae9d61Sreyk 49245ae9d61Sreyk int 493*0e1bb3dcStobhe ec_getlen(struct dh_group *group) 49445ae9d61Sreyk { 49545ae9d61Sreyk if (group->spec == NULL) 49645ae9d61Sreyk return (0); 49745b72fd1Smikeb /* NB: Return value will always be even */ 49845ae9d61Sreyk return ((roundup(group->spec->bits, 8) * 2) / 8); 49945ae9d61Sreyk } 50045ae9d61Sreyk 501a6321d0fSpatrick /* 502a6321d0fSpatrick * Note that the shared secret only includes the x value: 503a6321d0fSpatrick * 504a6321d0fSpatrick * See RFC 5903, 7. ECP Key Exchange Data Formats: 505a6321d0fSpatrick * The Diffie-Hellman shared secret value consists of the x value of the 506a6321d0fSpatrick * Diffie-Hellman common value. 507a6321d0fSpatrick * See also RFC 5903, 9. Changes from RFC 4753. 508a6321d0fSpatrick */ 509a6321d0fSpatrick int 510*0e1bb3dcStobhe ec_secretlen(struct dh_group *group) 511a6321d0fSpatrick { 512a6321d0fSpatrick return (ec_getlen(group) / 2); 513a6321d0fSpatrick } 514a6321d0fSpatrick 51545ae9d61Sreyk int 516*0e1bb3dcStobhe ec_create_exchange(struct dh_group *group, uint8_t *buf) 51745ae9d61Sreyk { 5180d5bf58dSreyk size_t len; 5190d5bf58dSreyk 5200d5bf58dSreyk len = ec_getlen(group); 5210d5bf58dSreyk bzero(buf, len); 5220d5bf58dSreyk 52345ae9d61Sreyk return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec), 524a6321d0fSpatrick buf, len, EC_POINT2RAW_FULL)); 52545ae9d61Sreyk } 52645ae9d61Sreyk 52745ae9d61Sreyk int 528*0e1bb3dcStobhe ec_create_shared(struct dh_group *group, uint8_t *secret, uint8_t *exchange) 52945ae9d61Sreyk { 53045ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 53145ae9d61Sreyk const BIGNUM *privkey; 532c900656bSmarkus EC_KEY *exkey = NULL; 53345ae9d61Sreyk EC_POINT *exchangep = NULL, *secretp = NULL; 53445ae9d61Sreyk int ret = -1; 53545ae9d61Sreyk 53645ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL || 53745ae9d61Sreyk (privkey = EC_KEY_get0_private_key(group->ec)) == NULL) 53845ae9d61Sreyk goto done; 53945ae9d61Sreyk 54045ae9d61Sreyk if ((exchangep = 54145ae9d61Sreyk ec_raw2point(group, exchange, ec_getlen(group))) == NULL) 54245ae9d61Sreyk goto done; 54345ae9d61Sreyk 544c900656bSmarkus if ((exkey = EC_KEY_new()) == NULL) 545c900656bSmarkus goto done; 546c900656bSmarkus if (!EC_KEY_set_group(exkey, ecgroup)) 547c900656bSmarkus goto done; 548c900656bSmarkus if (!EC_KEY_set_public_key(exkey, exchangep)) 549c900656bSmarkus goto done; 550c900656bSmarkus 551c900656bSmarkus /* validate exchangep */ 552c900656bSmarkus if (!EC_KEY_check_key(exkey)) 553c900656bSmarkus goto done; 554c900656bSmarkus 55545ae9d61Sreyk if ((secretp = EC_POINT_new(ecgroup)) == NULL) 55645ae9d61Sreyk goto done; 55745ae9d61Sreyk 55845ae9d61Sreyk if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL)) 55945ae9d61Sreyk goto done; 56045ae9d61Sreyk 561a6321d0fSpatrick ret = ec_point2raw(group, secretp, secret, ec_secretlen(group), 562a6321d0fSpatrick EC_POINT2RAW_XONLY); 56345ae9d61Sreyk 56445ae9d61Sreyk done: 565c900656bSmarkus if (exkey != NULL) 566c900656bSmarkus EC_KEY_free(exkey); 56745ae9d61Sreyk if (exchangep != NULL) 56845ae9d61Sreyk EC_POINT_clear_free(exchangep); 56945ae9d61Sreyk if (secretp != NULL) 57045ae9d61Sreyk EC_POINT_clear_free(secretp); 57145ae9d61Sreyk 57245ae9d61Sreyk return (ret); 57345ae9d61Sreyk } 57445ae9d61Sreyk 57545ae9d61Sreyk int 576*0e1bb3dcStobhe ec_point2raw(struct dh_group *group, const EC_POINT *point, 577a6321d0fSpatrick uint8_t *buf, size_t len, int mode) 57845ae9d61Sreyk { 57945ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 58045ae9d61Sreyk BN_CTX *bnctx = NULL; 58145ae9d61Sreyk BIGNUM *x = NULL, *y = NULL; 58245ae9d61Sreyk int ret = -1; 58345b72fd1Smikeb size_t eclen, xlen, ylen; 58445ae9d61Sreyk off_t xoff, yoff; 58545ae9d61Sreyk 58645ae9d61Sreyk if ((bnctx = BN_CTX_new()) == NULL) 58745ae9d61Sreyk goto done; 58845ae9d61Sreyk BN_CTX_start(bnctx); 58945ae9d61Sreyk if ((x = BN_CTX_get(bnctx)) == NULL || 59045ae9d61Sreyk (y = BN_CTX_get(bnctx)) == NULL) 59145ae9d61Sreyk goto done; 59245ae9d61Sreyk 59345b72fd1Smikeb eclen = ec_getlen(group); 594a6321d0fSpatrick switch (mode) { 595a6321d0fSpatrick case EC_POINT2RAW_XONLY: 596a6321d0fSpatrick xlen = eclen / 2; 597a6321d0fSpatrick ylen = 0; 598a6321d0fSpatrick break; 599a6321d0fSpatrick case EC_POINT2RAW_FULL: 60045b72fd1Smikeb xlen = ylen = eclen / 2; 601a6321d0fSpatrick break; 602a6321d0fSpatrick default: 603a6321d0fSpatrick goto done; 604a6321d0fSpatrick } 605a6321d0fSpatrick if (len < xlen + ylen) 606a6321d0fSpatrick goto done; 60745b72fd1Smikeb 60845ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL) 60945ae9d61Sreyk goto done; 61045ae9d61Sreyk 61145ae9d61Sreyk if (!EC_POINT_get_affine_coordinates_GFp(ecgroup, 61245ae9d61Sreyk point, x, y, bnctx)) 61345ae9d61Sreyk goto done; 61445ae9d61Sreyk 61545ae9d61Sreyk xoff = xlen - BN_num_bytes(x); 61645b72fd1Smikeb bzero(buf, xoff); 61745ae9d61Sreyk if (!BN_bn2bin(x, buf + xoff)) 61845ae9d61Sreyk goto done; 61945ae9d61Sreyk 620a6321d0fSpatrick if (ylen > 0) { 62145ae9d61Sreyk yoff = (ylen - BN_num_bytes(y)) + xlen; 62245b72fd1Smikeb bzero(buf + xlen, yoff - xlen); 62345ae9d61Sreyk if (!BN_bn2bin(y, buf + yoff)) 62445ae9d61Sreyk goto done; 625a6321d0fSpatrick } 62645ae9d61Sreyk 62745ae9d61Sreyk ret = 0; 62845ae9d61Sreyk done: 629c900656bSmarkus /* Make sure to erase sensitive data */ 630c900656bSmarkus if (x != NULL) 631c900656bSmarkus BN_clear(x); 632c900656bSmarkus if (y != NULL) 633c900656bSmarkus BN_clear(y); 63445ae9d61Sreyk BN_CTX_end(bnctx); 63545ae9d61Sreyk BN_CTX_free(bnctx); 63645ae9d61Sreyk 63745ae9d61Sreyk return (ret); 63845ae9d61Sreyk } 63945ae9d61Sreyk 64045ae9d61Sreyk EC_POINT * 641*0e1bb3dcStobhe ec_raw2point(struct dh_group *group, uint8_t *buf, size_t len) 64245ae9d61Sreyk { 64345ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 64445ae9d61Sreyk EC_POINT *point = NULL; 64545ae9d61Sreyk BN_CTX *bnctx = NULL; 64645ae9d61Sreyk BIGNUM *x = NULL, *y = NULL; 64745ae9d61Sreyk int ret = -1; 64845ae9d61Sreyk size_t eclen; 64945ae9d61Sreyk size_t xlen, ylen; 65045ae9d61Sreyk 65145ae9d61Sreyk if ((bnctx = BN_CTX_new()) == NULL) 65245ae9d61Sreyk goto done; 65345ae9d61Sreyk BN_CTX_start(bnctx); 65445ae9d61Sreyk if ((x = BN_CTX_get(bnctx)) == NULL || 65545ae9d61Sreyk (y = BN_CTX_get(bnctx)) == NULL) 65645ae9d61Sreyk goto done; 65745ae9d61Sreyk 65845ae9d61Sreyk eclen = ec_getlen(group); 65945ae9d61Sreyk if (len < eclen) 66045ae9d61Sreyk goto done; 66145ae9d61Sreyk xlen = ylen = eclen / 2; 66245ae9d61Sreyk if ((x = BN_bin2bn(buf, xlen, x)) == NULL || 66345ae9d61Sreyk (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL) 66445ae9d61Sreyk goto done; 66545ae9d61Sreyk 66645ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL) 66745ae9d61Sreyk goto done; 66845ae9d61Sreyk 66945ae9d61Sreyk if ((point = EC_POINT_new(ecgroup)) == NULL) 67045ae9d61Sreyk goto done; 67145ae9d61Sreyk 67245ae9d61Sreyk if (!EC_POINT_set_affine_coordinates_GFp(ecgroup, 67345ae9d61Sreyk point, x, y, bnctx)) 67445ae9d61Sreyk goto done; 67545ae9d61Sreyk 67645ae9d61Sreyk ret = 0; 67745ae9d61Sreyk done: 67845ae9d61Sreyk if (ret != 0 && point != NULL) 67945ae9d61Sreyk EC_POINT_clear_free(point); 680c900656bSmarkus /* Make sure to erase sensitive data */ 681c900656bSmarkus if (x != NULL) 682c900656bSmarkus BN_clear(x); 683c900656bSmarkus if (y != NULL) 684c900656bSmarkus BN_clear(y); 68545ae9d61Sreyk BN_CTX_end(bnctx); 68645ae9d61Sreyk BN_CTX_free(bnctx); 68745ae9d61Sreyk 68845ae9d61Sreyk return (point); 68945ae9d61Sreyk } 69045135ebcSreyk 69145135ebcSreyk int 692*0e1bb3dcStobhe ec25519_init(struct dh_group *group) 69345135ebcSreyk { 694d09d3a7dSreyk static const uint8_t basepoint[CURVE25519_SIZE] = { 9 }; 69545135ebcSreyk struct curve25519_key *curve25519; 69645135ebcSreyk 69745135ebcSreyk if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL) 69845135ebcSreyk return (-1); 69945135ebcSreyk 70045135ebcSreyk group->curve25519 = curve25519; 70145135ebcSreyk 70245135ebcSreyk arc4random_buf(curve25519->secret, CURVE25519_SIZE); 70345135ebcSreyk crypto_scalarmult_curve25519(curve25519->public, 70445135ebcSreyk curve25519->secret, basepoint); 70545135ebcSreyk 70645135ebcSreyk return (0); 70745135ebcSreyk } 70845135ebcSreyk 70945135ebcSreyk int 710*0e1bb3dcStobhe ec25519_getlen(struct dh_group *group) 71145135ebcSreyk { 71245135ebcSreyk if (group->spec == NULL) 71345135ebcSreyk return (0); 71445135ebcSreyk return (CURVE25519_SIZE); 71545135ebcSreyk } 71645135ebcSreyk 71745135ebcSreyk int 718*0e1bb3dcStobhe ec25519_create_exchange(struct dh_group *group, uint8_t *buf) 71945135ebcSreyk { 72045135ebcSreyk struct curve25519_key *curve25519 = group->curve25519; 72145135ebcSreyk 72245135ebcSreyk memcpy(buf, curve25519->public, ec25519_getlen(group)); 72345135ebcSreyk return (0); 72445135ebcSreyk } 72545135ebcSreyk 72645135ebcSreyk int 727*0e1bb3dcStobhe ec25519_create_shared(struct dh_group *group, uint8_t *shared, uint8_t *public) 72845135ebcSreyk { 72945135ebcSreyk struct curve25519_key *curve25519 = group->curve25519; 73045135ebcSreyk 73145135ebcSreyk crypto_scalarmult_curve25519(shared, curve25519->secret, public); 73245135ebcSreyk return (0); 73345135ebcSreyk } 734