From: Andreas Steffen Date: Wed, 27 Jun 2018 11:22:58 +0000 (+0200) Subject: oqs: Created QSKE plugin based on OQS library X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1d9976c31b52dace048ae89897d5bb07144e21f5;p=thirdparty%2Fstrongswan.git oqs: Created QSKE plugin based on OQS library --- diff --git a/configure.ac b/configure.ac index d8f2b37db6..97664df26c 100644 --- a/configure.ac +++ b/configure.ac @@ -143,6 +143,7 @@ ARG_DISBL_SET([md5], [disable MD5 software implementation plugin.]) ARG_ENABL_SET([mgf1], [enable the MGF1 software implementation plugin.]) ARG_ENABL_SET([newhope], [enable NewHope crypto plugin.]) ARG_ENABL_SET([qske-newhope], [enable NewHope QSKE plugin.]) +ARG_ENABL_SET([oqs], [enable Open Quantum Safe (liboqs) plugin.]) ARG_DISBL_SET([nonce], [disable nonce generation plugin.]) ARG_ENABL_SET([ntru], [enables the NTRU crypto plugin.]) ARG_ENABL_SET([openssl], [enables the OpenSSL crypto plugin.]) @@ -1166,6 +1167,14 @@ if test x$botan = xtrue; then AC_SUBST(botan_LIBS) fi +if test x$oqs = xtrue; then + saved_LIBS=$LIBS + LIBS="-lm" + AC_CHECK_LIB([oqs],[_init],,[AC_MSG_ERROR([Open Quantum-Safe library oqs not found])],[]) + LIBS=$saved_LIBS + AC_CHECK_HEADER([oqs/oqs.h],,[AC_MSG_ERROR([Open Quantum-Safe header oqs/oqs.h not found!])]) +fi + if test x$uci = xtrue; then AC_CHECK_LIB([uci],[uci_alloc_context],[LIBS="$LIBS"],[AC_MSG_ERROR([UCI library libuci not found])],[]) AC_CHECK_HEADER([uci.h],,[AC_MSG_ERROR([UCI header uci.h not found!])]) @@ -1437,6 +1446,7 @@ ADD_PLUGIN([gcm], [s charon scripts nm cmd]) ADD_PLUGIN([ntru], [s charon scripts nm cmd]) ADD_PLUGIN([newhope], [s charon scripts nm cmd]) ADD_PLUGIN([qske-newhope], [s charon scripts nm cmd]) +ADD_PLUGIN([oqs], [s charon scripts nm cmd]) ADD_PLUGIN([bliss], [s charon pki scripts nm cmd]) ADD_PLUGIN([curl], [s charon scepclient pki scripts nm cmd]) ADD_PLUGIN([files], [s charon scepclient pki scripts nm cmd]) @@ -1605,6 +1615,7 @@ AM_CONDITIONAL(USE_AF_ALG, test x$af_alg = xtrue) AM_CONDITIONAL(USE_NTRU, test x$ntru = xtrue) AM_CONDITIONAL(USE_NEWHOPE, test x$newhope = xtrue) AM_CONDITIONAL(USE_QSKE_NEWHOPE, test x$qske_newhope = xtrue) +AM_CONDITIONAL(USE_OQS, test x$oqs = xtrue) AM_CONDITIONAL(USE_BLISS, test x$bliss = xtrue) # charon plugins @@ -1889,6 +1900,7 @@ AC_CONFIG_FILES([ src/libstrongswan/plugins/newhope/tests/Makefile src/libstrongswan/plugins/qske_newhope/Makefile src/libstrongswan/plugins/qske_newhope/tests/Makefile + src/libstrongswan/plugins/oqs/Makefile src/libstrongswan/plugins/test_vectors/Makefile src/libstrongswan/tests/Makefile src/libipsec/Makefile diff --git a/scripts/test.sh b/scripts/test.sh index ba5fd6da8e..90d2a5fd66 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -186,6 +186,8 @@ all|coverage|sonarcloud) --disable-soup --disable-unwind-backtraces --disable-svc --disable-dbghelp-backtraces --disable-socket-win --disable-kernel-wfp --disable-kernel-iph --disable-winhttp" + # liboqs would have to be installed manually + CONFIG="$CONFIG --disable-oqs" # not enabled on the build server CONFIG="$CONFIG --disable-af-alg" if test "$TEST" != "coverage"; then diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 3d351efb07..d44e02ffbe 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -670,6 +670,13 @@ if MONOLITHIC endif endif +if USE_OQS + SUBDIRS += plugins/oqs +if MONOLITHIC + libstrongswan_la_LIBADD += plugins/oqs/libstrongswan-oqs.la +endif +endif + if USE_TEST_VECTORS SUBDIRS += plugins/test_vectors if MONOLITHIC diff --git a/src/libstrongswan/crypto/qske_mechanism.c b/src/libstrongswan/crypto/qske_mechanism.c index b3ef470413..5e28a55807 100644 --- a/src/libstrongswan/crypto/qske_mechanism.c +++ b/src/libstrongswan/crypto/qske_mechanism.c @@ -15,7 +15,7 @@ #include "qske_mechanism.h" -ENUM(qske_mechanism_names, QSKE_NONE, QSKE_FRODO, +ENUM(qske_mechanism_names, QSKE_NONE, QSKE_LIMA_SP_L5, "QSKE_NONE", "QSKE_NEWHOPE", "QSKE_NEWHOPE_L1", diff --git a/src/libstrongswan/plugins/oqs/Makefile.am b/src/libstrongswan/plugins/oqs/Makefile.am new file mode 100644 index 0000000000..3e377f4570 --- /dev/null +++ b/src/libstrongswan/plugins/oqs/Makefile.am @@ -0,0 +1,27 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +# these files are also used by the tests, we can't directly refer to them +# because of the subdirectory, which would cause distclean to fail +noinst_LTLIBRARIES = libqske-oqs.la +libqske_oqs_la_SOURCES = \ + oqs_qske.h oqs_qske.c + +libqske_oqs_la_LIBADD = \ + -loqs -lcrypto -lm + +if MONOLITHIC +noinst_LTLIBRARIES += libstrongswan-oqs.la +else +plugin_LTLIBRARIES = libstrongswan-oqs.la +endif + +libstrongswan_oqs_la_SOURCES = \ + oqs_plugin.h oqs_plugin.c + +libstrongswan_oqs_la_LDFLAGS = -module -avoid-version + +libstrongswan_oqs_la_LIBADD = libqske-oqs.la diff --git a/src/libstrongswan/plugins/oqs/oqs_plugin.c b/src/libstrongswan/plugins/oqs/oqs_plugin.c new file mode 100644 index 0000000000..4b38ab4cf2 --- /dev/null +++ b/src/libstrongswan/plugins/oqs/oqs_plugin.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2018 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "oqs_plugin.h" +#include "oqs_qske.h" + +#include + +typedef struct private_oqs_plugin_t private_oqs_plugin_t; + +/** + * private data of oqs_plugin + */ +struct private_oqs_plugin_t { + + /** + * public functions + */ + oqs_plugin_t public; +}; + +METHOD(plugin_t, get_name, char*, + private_oqs_plugin_t *this) +{ + return "oqs"; +} + +METHOD(plugin_t, get_features, int, + private_oqs_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + /* QSKE groups */ + PLUGIN_REGISTER(QSKE, oqs_qske_create), + PLUGIN_PROVIDE(QSKE, QSKE_NEWHOPE_L1), + PLUGIN_PROVIDE(QSKE, QSKE_NEWHOPE_L5), + PLUGIN_PROVIDE(QSKE, QSKE_FRODO_AES_L1), + PLUGIN_PROVIDE(QSKE, QSKE_FRODO_AES_L3), + PLUGIN_PROVIDE(QSKE, QSKE_FRODO_SHAKE_L1), + PLUGIN_PROVIDE(QSKE, QSKE_FRODO_SHAKE_L3), + PLUGIN_PROVIDE(QSKE, QSKE_KYBER_L1), + PLUGIN_PROVIDE(QSKE, QSKE_KYBER_L3), + PLUGIN_PROVIDE(QSKE, QSKE_KYBER_L5), + PLUGIN_PROVIDE(QSKE, QSKE_BIKE1_L1), + PLUGIN_PROVIDE(QSKE, QSKE_BIKE1_L3), + PLUGIN_PROVIDE(QSKE, QSKE_BIKE1_L5), + PLUGIN_PROVIDE(QSKE, QSKE_BIKE2_L1), + PLUGIN_PROVIDE(QSKE, QSKE_BIKE2_L3), + PLUGIN_PROVIDE(QSKE, QSKE_BIKE2_L5), + PLUGIN_PROVIDE(QSKE, QSKE_BIKE3_L1), + PLUGIN_PROVIDE(QSKE, QSKE_BIKE3_L3), + PLUGIN_PROVIDE(QSKE, QSKE_BIKE3_L5), + PLUGIN_PROVIDE(QSKE, QSKE_SIKE_L1), + PLUGIN_PROVIDE(QSKE, QSKE_SIKE_L3), + PLUGIN_PROVIDE(QSKE, QSKE_SABER_L1), + PLUGIN_PROVIDE(QSKE, QSKE_SABER_L3), + PLUGIN_PROVIDE(QSKE, QSKE_SABER_L5), + PLUGIN_PROVIDE(QSKE, QSKE_LIMA_2P_L3), + PLUGIN_PROVIDE(QSKE, QSKE_LIMA_2P_L5), + PLUGIN_PROVIDE(QSKE, QSKE_LIMA_SP_L1), + PLUGIN_PROVIDE(QSKE, QSKE_LIMA_SP_L2), + PLUGIN_PROVIDE(QSKE, QSKE_LIMA_SP_L3), + PLUGIN_PROVIDE(QSKE, QSKE_LIMA_SP_L5) + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_oqs_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *oqs_plugin_create() +{ + private_oqs_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + ); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/oqs/oqs_plugin.h b/src/libstrongswan/plugins/oqs/oqs_plugin.h new file mode 100644 index 0000000000..88c36779d5 --- /dev/null +++ b/src/libstrongswan/plugins/oqs/oqs_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup oqs_p oqs + * @ingroup plugins + * + * @defgroup oqs_plugin oqs_plugin + * @{ @ingroup oqs_p + */ + +#ifndef OQS_PLUGIN_H_ +#define OQS_PLUGIN_H_ + +#include + +typedef struct oqs_plugin_t oqs_plugin_t; + +/** + * Plugin implementing quantum-safe crypto algorithms using the OQS library. + */ +struct oqs_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** OQS_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/oqs/oqs_qske.c b/src/libstrongswan/plugins/oqs/oqs_qske.c new file mode 100644 index 0000000000..725630bcf6 --- /dev/null +++ b/src/libstrongswan/plugins/oqs/oqs_qske.c @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2018 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * Based on public domain code by Erdem Alkim, Léo Ducas, Thomas Pöppelmann, + * and Peter Schwabe. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "oqs_qske.h" + +#include + +#include + +typedef struct private_oqs_qske_t private_oqs_qske_t; + +/** + * Private data of an oqs_qske_t object. + */ +struct private_oqs_qske_t { + + /** + * Public oqs_qske_t interface. + */ + oqs_qske_t public; + + /** + * QSKE_MECHANISM; + */ + qske_mechanism_t qske_mechanism; + + /** + * Internal OQS_KEM object + */ + OQS_KEM *kem; + + /** + * Public Key + */ + uint8_t *public_key; + + /** + * Secret Key + */ + uint8_t *secret_key; + + /** + * Ciphertext + */ + uint8_t *ciphertext; + + /** + * Shared secret + */ + uint8_t *shared_secret; + +}; + + +METHOD(qske_t, get_public_key, bool, + private_oqs_qske_t *this, chunk_t *value) +{ + OQS_STATUS rc; + + if (!this->public_key) + { + this->public_key = malloc(this->kem->length_public_key); + this->secret_key = malloc(this->kem->length_secret_key); + rc = OQS_KEM_keypair(this->kem, this->public_key, this->secret_key); + if (rc != OQS_SUCCESS) + { + DBG1(DBG_LIB, "%N keypair generation failed", + qske_mechanism_names, this->qske_mechanism); + return FALSE; + } + } + *value = chunk_clone(chunk_create(this->public_key, + this->kem->length_public_key)); + return TRUE; +} + +METHOD(qske_t, get_ciphertext, bool, + private_oqs_qske_t *this, chunk_t *value) +{ + OQS_STATUS rc; + + if (!this->ciphertext) + { + if (!this->public_key) + { + DBG1(DBG_LIB, "no public key available for %N encapsulation", + qske_mechanism_names, this->qske_mechanism); + return FALSE; + } + this->ciphertext = malloc(this->kem->length_ciphertext); + this->shared_secret = malloc(this->kem->length_shared_secret); + memset(this->shared_secret, 0x00, this->kem->length_shared_secret); + rc = OQS_KEM_encaps(this->kem, this->ciphertext, this->shared_secret, + this->public_key); + if (rc != OQS_SUCCESS) + { + DBG1(DBG_LIB, "%N encapsulation failed", + qske_mechanism_names, this->qske_mechanism); + return FALSE; + } + } + *value = chunk_clone(chunk_create(this->ciphertext, + this->kem->length_ciphertext)); + return TRUE; +} + +METHOD(qske_t, get_shared_secret, bool, + private_oqs_qske_t *this, chunk_t *secret) +{ + if (!this->shared_secret) + { + return FALSE; + } + *secret = chunk_clone(chunk_create(this->shared_secret, + this->kem->length_shared_secret)); + return TRUE; +} + +METHOD(qske_t, set_public_key, bool, + private_oqs_qske_t *this, chunk_t value) +{ + if (value.len != this->kem->length_public_key) + { + DBG1(DBG_LIB, "wrong %N public key size of %u bytes, %u bytes expected", + qske_mechanism_names, this->qske_mechanism, value.len, + this->kem->length_public_key); + return FALSE; + } + if (!this->public_key) + { + this->public_key = malloc(this->kem->length_public_key); + } + memcpy(this->public_key, value.ptr, value.len); + + return TRUE; +} + +METHOD(qske_t, set_ciphertext, bool, + private_oqs_qske_t *this, chunk_t value) +{ + OQS_STATUS rc; + + if (!this->public_key) + { + DBG1(DBG_LIB, "no secret key available for %N decapsulation", + qske_mechanism_names, this->qske_mechanism); + return FALSE; + } + + if (value.len != this->kem->length_ciphertext) + { + DBG1(DBG_LIB, "wrong %N ciphertext size of %u bytes, %u bytes expected", + qske_mechanism_names, this->qske_mechanism, value.len, + this->kem->length_ciphertext); + return FALSE; + } + + if (!this->shared_secret) + { + this->shared_secret = malloc(this->kem->length_shared_secret); + } + + rc = OQS_KEM_decaps(this->kem, this->shared_secret, value.ptr, + this->secret_key); + if (rc != OQS_SUCCESS) + { + DBG1(DBG_LIB, "%N decapsulation failed", + qske_mechanism_names, this->qske_mechanism); + return FALSE; + } + + return TRUE; +} + +METHOD(qske_t, get_qske_mechanism, qske_mechanism_t, + private_oqs_qske_t *this) +{ + return this->qske_mechanism; +} + +METHOD(qske_t, set_nist_drbg_mode, bool, + private_oqs_qske_t *this, bool enable, chunk_t seed) +{ + OQS_STATUS rc; + + if (enable) + { + if (seed.len < 48) + { + DBG1(DBG_LIB, "not enough entropy input for NIST DRBG"); + return FALSE; + } + + rc = OQS_randombytes_switch_algorithm(OQS_RAND_alg_nist_kat); + if (rc != OQS_SUCCESS) + { + return FALSE; + } + OQS_randombytes_nist_kat_init(seed.ptr, NULL, 256); + } + else + { + rc = OQS_randombytes_switch_algorithm(OQS_RAND_alg_openssl); + if (rc != OQS_SUCCESS) + { + return FALSE; + } + } + + return TRUE; +} + +METHOD(qske_t, destroy, void, + private_oqs_qske_t *this) +{ + if (this->secret_key) + { + memwipe(this->secret_key, this->kem->length_secret_key); + free(this->secret_key); + } + if (this->shared_secret) + { + memwipe(this->shared_secret, this->kem->length_shared_secret); + free(this->shared_secret); + } + OQS_KEM_free(this->kem); + free(this->public_key); + free(this->ciphertext); + free(this); +} + +/* + * Described in header. + */ +oqs_qske_t *oqs_qske_create(qske_mechanism_t mechanism) +{ + private_oqs_qske_t *this; + char *kem_alg = NULL; + OQS_KEM *kem; + + switch (mechanism) + { + case QSKE_NEWHOPE_L1: + kem_alg = OQS_KEM_alg_newhope_512_cca_kem; + break; + case QSKE_NEWHOPE_L5: + kem_alg = OQS_KEM_alg_newhope_1024_cca_kem; + break; + case QSKE_FRODO_AES_L1: + kem_alg = OQS_KEM_alg_frodokem_640_aes; + break; + case QSKE_FRODO_AES_L3: + kem_alg = OQS_KEM_alg_frodokem_976_aes; + break; + case QSKE_FRODO_SHAKE_L1: + kem_alg = OQS_KEM_alg_frodokem_640_cshake; + break; + case QSKE_FRODO_SHAKE_L3: + kem_alg = OQS_KEM_alg_frodokem_976_cshake; + break; + case QSKE_KYBER_L1: + kem_alg = OQS_KEM_alg_kyber512; + break; + case QSKE_KYBER_L3: + kem_alg = OQS_KEM_alg_kyber768; + break; + case QSKE_KYBER_L5: + kem_alg = OQS_KEM_alg_kyber1024; + break; + case QSKE_BIKE1_L1: + kem_alg = OQS_KEM_alg_bike1_l1; + break; + case QSKE_BIKE1_L3: + kem_alg = OQS_KEM_alg_bike1_l3; + break; + case QSKE_BIKE1_L5: + kem_alg = OQS_KEM_alg_bike1_l5; + break; + case QSKE_BIKE2_L1: + kem_alg = OQS_KEM_alg_bike2_l1; + break; + case QSKE_BIKE2_L3: + kem_alg = OQS_KEM_alg_bike2_l3; + break; + case QSKE_BIKE2_L5: + kem_alg = OQS_KEM_alg_bike2_l5; + break; + case QSKE_BIKE3_L1: + kem_alg = OQS_KEM_alg_bike3_l1; + break; + case QSKE_BIKE3_L3: + kem_alg = OQS_KEM_alg_bike3_l3; + break; + case QSKE_BIKE3_L5: + kem_alg = OQS_KEM_alg_bike3_l5; + break; + case QSKE_SIKE_L1: + kem_alg = OQS_KEM_alg_sike_p503; + break; + case QSKE_SIKE_L3: + kem_alg = OQS_KEM_alg_sike_p751; + break; + case QSKE_SABER_L1: + kem_alg = OQS_KEM_alg_saber_light_saber_kem; + break; + case QSKE_SABER_L3: + kem_alg = OQS_KEM_alg_saber_saber_kem; + break; + case QSKE_SABER_L5: + kem_alg = OQS_KEM_alg_saber_fire_saber_kem; + break; + case QSKE_LIMA_2P_L3: + kem_alg = OQS_KEM_alg_lima_2p_1024_cca_kem; + break; + case QSKE_LIMA_2P_L5: + kem_alg = OQS_KEM_alg_lima_2p_2048_cca_kem; + break; + case QSKE_LIMA_SP_L1: + kem_alg = OQS_KEM_alg_lima_sp_1018_cca_kem; + break; + case QSKE_LIMA_SP_L2: + kem_alg = OQS_KEM_alg_lima_sp_1306_cca_kem; + break; + case QSKE_LIMA_SP_L3: + kem_alg = OQS_KEM_alg_lima_sp_1822_cca_kem; + break; + case QSKE_LIMA_SP_L5: + kem_alg = OQS_KEM_alg_lima_sp_2062_cca_kem; + break; + default: + return NULL; + } + + kem = OQS_KEM_new(kem_alg); + if (!kem) + { + DBG1(DBG_LIB, "OQS KEM '%s' not available", kem_alg); + return NULL; + } + + INIT(this, + .public = { + .qske = { + .get_qske_mechanism = _get_qske_mechanism, + .get_public_key = _get_public_key, + .set_public_key = _set_public_key, + .get_ciphertext = _get_ciphertext, + .set_ciphertext = _set_ciphertext, + .get_shared_secret = _get_shared_secret, + .set_nist_drbg_mode = _set_nist_drbg_mode, + .destroy = _destroy, + }, + }, + .qske_mechanism = mechanism, + .kem = kem, + ); + + return &this->public; +} diff --git a/src/libstrongswan/plugins/oqs/oqs_qske.h b/src/libstrongswan/plugins/oqs/oqs_qske.h new file mode 100644 index 0000000000..5479b78378 --- /dev/null +++ b/src/libstrongswan/plugins/oqs/oqs_qske.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup oqs_qske oqs_qske + * @{ @ingroup oqs_p + */ + +#ifndef OQS_QSKE_H_ +#define OQS_QSKE_H_ + +typedef struct oqs_qske_t oqs_qske_t; + +#include + +/** + * Quantum-safe key encapsulation implementation using the OQS_QSKE library + */ +struct oqs_qske_t { + + /** + * Implements qske_t interface. + */ + qske_t qske; +}; + +/** + * Creates a new oqs_qske_t object. + * + * @param mechanism QSKE mechanism number + * @return oqs_qske_t object, NULL if not supported + */ +oqs_qske_t *oqs_qske_create(qske_mechanism_t mechanism); + +#endif /** OQS_QSKE_H_ @}*/ +