From 0c2d9264a5ba79a013c5212a7d0d1541c0a58b41 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Fri, 29 Jan 2016 14:47:52 +0000 Subject: [PATCH] Add ed25519 reference implementation --- src/libcryptobox/CMakeLists.txt | 5 +- src/libcryptobox/curve25519/fe.h | 1 + src/libcryptobox/ed25519/ed25519.c | 107 ++++++++++++++++++++++ src/libcryptobox/ed25519/ed25519.h | 41 +++++++++ src/libcryptobox/ed25519/ref.c | 140 +++++++++++++++++++++++++++++ 5 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 src/libcryptobox/ed25519/ed25519.c create mode 100644 src/libcryptobox/ed25519/ed25519.h create mode 100644 src/libcryptobox/ed25519/ref.c diff --git a/src/libcryptobox/CMakeLists.txt b/src/libcryptobox/CMakeLists.txt index 18736dc06..874e94567 100644 --- a/src/libcryptobox/CMakeLists.txt +++ b/src/libcryptobox/CMakeLists.txt @@ -13,6 +13,9 @@ SET(BLAKE2SRC ${CMAKE_CURRENT_SOURCE_DIR}/blake2/blake2.c SET(CURVESRC ${CMAKE_CURRENT_SOURCE_DIR}/curve25519/ref.c ${CMAKE_CURRENT_SOURCE_DIR}/curve25519/curve25519.c) +SET(EDSRC ${CMAKE_CURRENT_SOURCE_DIR}/ed25519/ref.c + ${CMAKE_CURRENT_SOURCE_DIR}/ed25519/ed25519.c) + SET(ASM_CODE " .macro TEST1 op \\op %eax, %eax @@ -85,4 +88,4 @@ INCLUDE_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}") SET(LIBCRYPTOBOXSRC ${CMAKE_CURRENT_SOURCE_DIR}/cryptobox.c) SET(RSPAMD_CRYPTOBOX ${LIBCRYPTOBOXSRC} ${CHACHASRC} ${POLYSRC} ${SIPHASHSRC} - ${CURVESRC} ${BLAKE2SRC} PARENT_SCOPE) + ${CURVESRC} ${BLAKE2SRC} ${EDSRC} PARENT_SCOPE) diff --git a/src/libcryptobox/curve25519/fe.h b/src/libcryptobox/curve25519/fe.h index 1c4589659..d5d8b93fd 100644 --- a/src/libcryptobox/curve25519/fe.h +++ b/src/libcryptobox/curve25519/fe.h @@ -114,6 +114,7 @@ void ge_sub(ge_p1p1 *,const ge_p3 *,const ge_cached *); void ge_scalarmult_base(ge_p3 *,const unsigned char *); void ge_double_scalarmult_vartime(ge_p2 *,const unsigned char *,const ge_p3 *,const unsigned char *); void ge_scalarmult_vartime(ge_p3 *,const unsigned char *,const ge_p3 *); +int verify_32(const unsigned char *x, const unsigned char *y); /* The set of scalars is \Z/l diff --git a/src/libcryptobox/ed25519/ed25519.c b/src/libcryptobox/ed25519/ed25519.c new file mode 100644 index 000000000..776ac4e13 --- /dev/null +++ b/src/libcryptobox/ed25519/ed25519.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016, Vsevolod Stakhov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "cryptobox.h" +#include "ed25519.h" +#include "platform_config.h" + +extern unsigned long cpu_config; + +typedef struct ed25519_impl_s { + unsigned long cpu_flags; + const char *desc; + + void (*keypair) (unsigned char *pk, unsigned char *sk); + void (*sign) (unsigned char *sig, unsigned long long *siglen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk); + bool (*verify) (const unsigned char *sig, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *pk); +} ed25519_impl_t; + +#define ED25519_DECLARE(ext) \ + void ed_keypair_##ext(unsigned char *pk, unsigned char *sk); \ + void ed_sign_##ext(unsigned char *sig, unsigned long long *siglen_p, \ + const unsigned char *m, unsigned long long mlen, \ + const unsigned char *sk); \ + bool ed_verify_##ext(const unsigned char *sig, \ + const unsigned char *m, \ + unsigned long long mlen, \ + const unsigned char *pk) + +#define ED25519_IMPL(cpuflags, desc, ext) \ + {(cpuflags), desc, ed_keypair_##ext, ed_sign_##ext, ed_verify_##ext} + +ED25519_DECLARE(ref); +#define ED25519_REF ED25519_IMPL(0, "ref", ref) + +static const ed25519_impl_t ed25519_list[] = { + ED25519_REF, +}; + +static const ed25519_impl_t *ed25519_opt = &ed25519_list[0]; + +const char* +ed25519_load (void) +{ + guint i; + + if (cpu_config != 0) { + for (i = 0; i < G_N_ELEMENTS(ed25519_list); i++) { + if (ed25519_list[i].cpu_flags & cpu_config) { + ed25519_opt = &ed25519_list[i]; + break; + } + } + } + + + return ed25519_opt->desc; +} + +void +ed25519_keypair (unsigned char *pk, unsigned char *sk) +{ + ed25519_opt->keypair (pk, sk); +} + +void +ed25519_sign (unsigned char *sig, unsigned long long *siglen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk) +{ + ed25519_opt->sign (sig, siglen_p, m, mlen, sk); +} + +bool +ed25519_verify (const unsigned char *sig, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *pk) +{ + return ed25519_opt->verify (sig, m, mlen, pk); +} diff --git a/src/libcryptobox/ed25519/ed25519.h b/src/libcryptobox/ed25519/ed25519.h new file mode 100644 index 000000000..34814782b --- /dev/null +++ b/src/libcryptobox/ed25519/ed25519.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, Vsevolod Stakhov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_LIBCRYPTOBOX_ED25519_ED25519_H_ +#define SRC_LIBCRYPTOBOX_ED25519_ED25519_H_ + +#include "config.h" +#include + +const char* ed25519_load (void); +void ed25519_keypair (unsigned char *pk, unsigned char *sk); +void ed25519_sign (unsigned char *sig, unsigned long long *siglen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk); +bool ed25519_verify (const unsigned char *sig, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *pk); + +#endif /* SRC_LIBCRYPTOBOX_ED25519_ED25519_H_ */ diff --git a/src/libcryptobox/ed25519/ref.c b/src/libcryptobox/ed25519/ref.c new file mode 100644 index 000000000..a1053c607 --- /dev/null +++ b/src/libcryptobox/ed25519/ref.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2013-2016 + * Frank Denis + * Vsevolod Stakhov + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" +#include "ed25519.h" +#include "cryptobox.h" +#include "../curve25519/fe.h" +#include "ottery.h" +#include /* SHA512 */ + +static int +ed_seed_keypair_ref (unsigned char *pk, unsigned char *sk, + const unsigned char *seed) +{ + ge_p3 A; + + memmove (sk, seed, 32); + sk[0] &= 248; + sk[31] &= 63; + sk[31] |= 64; + + ge_scalarmult_base (&A, sk); + ge_p3_tobytes (pk, &A); + + memmove (sk, seed, 32); + memmove (sk + 32, pk, 32); + + return 0; +} + +int +ed_keypair_ref (unsigned char *pk, unsigned char *sk) +{ + unsigned char seed[rspamd_cryptobox_HASHBYTES]; + int ret; + + ottery_rand_bytes (seed, sizeof (seed)); + rspamd_cryptobox_hash (seed, seed, sizeof (seed), NULL, 0); + ret = ed_seed_keypair_ref (pk, sk, seed); + rspamd_explicit_memzero (seed, sizeof (seed)); + + return ret; +} + +int +ed_verify_ref(const unsigned char *sig, const unsigned char *m, + unsigned long long mlen, const unsigned char *pk) +{ + EVP_MD_CTX sha_ctx; + unsigned char h[64]; + unsigned char rcheck[32]; + unsigned int i; + unsigned char d = 0; + ge_p3 A; + ge_p2 R; + + if (sig[63] & 224) { + return -1; + } + if (ge_frombytes_negate_vartime (&A, pk) != 0) { + return -1; + } + for (i = 0; i < 32; ++i) { + d |= pk[i]; + } + if (d == 0) { + return -1; + } + + g_assert (EVP_DigestInit (&sha_ctx, EVP_sha512()) == 1); + EVP_DigestUpdate (&sha_ctx, sig, 32); + EVP_DigestUpdate (&sha_ctx, pk, 32); + EVP_DigestUpdate (&sha_ctx, m, mlen); + EVP_DigestFinal (&sha_ctx, h, NULL); + sc_reduce (h); + + ge_double_scalarmult_vartime (&R, h, &A, sig + 32); + ge_tobytes (rcheck, &R); + + return verify_32 (rcheck, sig) | (-(rcheck == sig)); +} + +void +ed_sign_ref(unsigned char *sig, unsigned long long *siglen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk) +{ + EVP_MD_CTX sha_ctx; + unsigned char az[64]; + unsigned char nonce[64]; + unsigned char hram[64]; + ge_p3 R; + + g_assert (EVP_DigestInit (&sha_ctx, EVP_sha512()) == 1); + EVP_DigestUpdate (&sha_ctx, sk, 32); + EVP_DigestFinal (&sha_ctx, az, NULL); + az[0] &= 248; + az[31] &= 63; + az[31] |= 64; + + g_assert (EVP_DigestInit (&sha_ctx, EVP_sha512()) == 1); + EVP_DigestUpdate (&sha_ctx, az + 32, 32); + EVP_DigestUpdate (&sha_ctx, m, mlen); + EVP_DigestFinal (&sha_ctx, nonce, NULL); + + memmove (sig + 32, sk + 32, 32); + + sc_reduce (nonce); + ge_scalarmult_base (&R, nonce); + ge_p3_tobytes (sig, &R); + + g_assert (EVP_DigestInit (&sha_ctx, EVP_sha512()) == 1); + EVP_DigestUpdate (&sha_ctx, sig, 64); + EVP_DigestUpdate (&sha_ctx, m, mlen); + EVP_DigestFinal (&sha_ctx, hram, NULL); + + sc_reduce (hram); + sc_muladd (sig + 32, hram, az, nonce); + + rspamd_explicit_memzero (az, sizeof (az)); + + if (siglen_p != NULL) { + *siglen_p = 64U; + } +} -- 2.39.5