aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac99
-rw-r--r--src/common/crypto_curve25519.c88
-rw-r--r--src/common/crypto_curve25519.h43
-rw-r--r--src/common/include.am20
-rw-r--r--src/test/test_crypto.c82
5 files changed, 331 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index 9963a97d4..927283435 100644
--- a/configure.ac
+++ b/configure.ac
@@ -36,6 +36,8 @@ AC_ARG_ENABLE(static-zlib,
AS_HELP_STRING(--enable-static-zlib, Link against a static zlib library. Requires --with-zlib-dir))
AC_ARG_ENABLE(static-tor,
AS_HELP_STRING(--enable-static-tor, Create an entirely static Tor binary. Requires --with-openssl-dir and --with-libevent-dir and --with-zlib-dir))
+AC_ARG_ENABLE(curve25519,
+ AS_HELP_STRING(--disable-curve25519, Build Tor with no curve25519 elliptic-curve crypto support))
if test "$enable_static_tor" = "yes"; then
enable_static_libevent="yes";
@@ -638,6 +640,103 @@ if test "$upnp" = "true"; then
fi
fi
+dnl ============================================================
+dnl We need an implementation of curve25519.
+
+dnl set these defaults.
+have_a_curve25519=no
+build_curve25519_donna=no
+build_curve25519_donna_c64=no
+use_curve25519_donna=no
+use_curve25519_nacl=no
+CURVE25519_LIBS=
+
+if test x$enable_curve25519 != xno; then
+
+ dnl The best choice is using curve25519-donna-c64, but that requires
+ dnl that we
+ AC_CACHE_CHECK([whether we can use curve25519-donna-c64],
+ tor_cv_can_use_curve25519_donna_c64,
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([dnl
+ #include <stdint.h>
+ typedef unsigned uint128_t __attribute__((mode(TI)));
+ ], [dnl
+ uint64_t a = ((uint64_t)2000000000) * 1000000000;
+ uint64_t b = ((uint64_t)1234567890) << 24;
+ uint128_t c = ((uint128_t)a) * b;
+ return ((uint64_t)(c>>96)) == 522859 &&
+ ((uint64_t)(c>>64))&0xffffffffL == 3604448702L &&
+ ((uint64_t)(c>>32))&0xffffffffL == 2351960064L &&
+ ((uint64_t)(c))&0xffffffffL == 0;
+ ])],
+ [tor_cv_can_use_curve25519_donna_c64=yes],
+ [tor_cv_can_use_curve25519_donna_c64=no],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([dnl
+ #include <stdint.h>
+ typedef unsigned uint128_t __attribute__((mode(TI)));
+ ], [dnl
+ uint64_t a = ((uint64_t)2000000000) * 1000000000;
+ uint64_t b = ((uint64_t)1234567890) << 24;
+ uint128_t c = ((uint128_t)a) * b;
+ return ((uint64_t)(c>>96)) == 522859 &&
+ ((uint64_t)(c>>64))&0xffffffffL == 3604448702L &&
+ ((uint64_t)(c>>32))&0xffffffffL == 2351960064L &&
+ ((uint64_t)(c))&0xffffffffL == 0;
+ ])],
+ [tor_cv_can_use_curve25519_donna_c64=cross],
+ [tor_cv_can_use_curve25519_donna_c64=no])])])
+
+ AC_CACHE_CHECK([whether we can use curve25519 from nacl],
+ tor_cv_can_use_curve25519_nacl,
+ [tor_saved_LIBS="$LIBS"
+ LIBS="$LIBS -lnacl"
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([dnl
+ #include <crypto_scalarmult_curve25519.h>
+ #ifdef crypto_scalarmult_curve25519_ref_BYTES
+ #error Hey, this is the reference implementation!
+ #endif
+ ], [
+ unsigned char *a, *b, *c; crypto_scalarmult_curve25519(a,b,c);
+ ])], [tor_cv_can_use_curve25519_nacl=yes],
+ [tor_cv_can_use_curve25519_nacl=no])
+ LIBS="$tor_saved_LIBS" ])
+
+ dnl Okay, now we need to figure out which one to actually use. Fall back
+ dnl to curve25519-donna.c
+
+ if test x$tor_cv_can_use_curve25519_donna_c64 != xno; then
+ build_curve25519_donna_c64=yes
+ use_curve25519_donna=yes
+ elif test x$tor_cv_can_use_curve25519_nacl = xyes; then
+ use_curve25519_nacl=yes
+ CURVE25519_LIBS=-lnacl
+ else
+ build_curve25519_donna=yes
+ use_curve25519_donna=yes
+ fi
+ have_a_curve25519=yes
+fi
+
+if test x$have_a_curve25519 = xyes; then
+ AC_DEFINE(CURVE25519_ENABLED, 1,
+ [Defined if we have a curve25519 implementation])
+fi
+if test x$use_curve25519_donna = xyes; then
+ AC_DEFINE(USE_CURVE25519_DONNA, 1,
+ [Defined if we should use an internal curve25519_donna{,_c64} implementation])
+fi
+if test x$use_curve25519_nacl = xyes; then
+ AC_DEFINE(USE_CURVE25519_NACL, 1,
+ [Defined if we should use a curve25519 from nacl])
+fi
+AM_CONDITIONAL(BUILD_CURVE25519_DONNA, test x$build_curve25519_donna = xyes)
+AM_CONDITIONAL(BUILD_CURVE25519_DONNA_C64, test x$build_curve25519_donna_c64 = xyes)
+AM_CONDITIONAL(CURVE25519_ENABLED, test x$have_a_curve25519 = xyes)
+AC_SUBST(CURVE25519_LIBS)
+
dnl Make sure to enable support for large off_t if available.
AC_SYS_LARGEFILE
diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c
new file mode 100644
index 000000000..1985e8af2
--- /dev/null
+++ b/src/common/crypto_curve25519.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Wrapper code for a curve25519 implementation. */
+
+#define CRYPTO_CURVE25519_PRIVATE
+#include "orconfig.h"
+#include "crypto.h"
+#include "crypto_curve25519.h"
+#include "util.h"
+
+/* ==============================
+ Part 1: wrap a suitable curve25519 implementation as curve25519_impl
+ ============================== */
+
+#ifdef USE_CURVE25519_DONNA
+int curve25519_donna(uint8_t *mypublic,
+ const uint8_t *secret, const uint8_t *basepoint);
+#endif
+#ifdef USE_CURVE25519_NACL
+#include <crypto_scalarmult_curve25519.h>
+#endif
+
+int
+curve25519_impl(uint8_t *output, const uint8_t *secret,
+ const uint8_t *basepoint)
+{
+#ifdef USE_CURVE25519_DONNA
+ return curve25519_donna(output, secret, basepoint);
+#elif defined(USE_CURVE25519_NACL)
+ return crypto_scalarmult_curve25519(output, secret, basepoint);
+#else
+#error "No implementation of curve25519 is available."
+#endif
+}
+
+/* ==============================
+ Part 2: Wrap curve25519_impl with some convenience types and functions.
+ ============================== */
+
+/**
+ * Return true iff a curve25519_public_key_t seems valid. (It's not necessary
+ * to see if the point is on the curve, since the twist is also secure, but we
+ * do need to make sure that it isn't the point at infinity.) */
+int
+curve25519_public_key_is_ok(const curve25519_public_key_t *key)
+{
+ static const uint8_t zero[] =
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+ return tor_memneq(key->public_key, zero, CURVE25519_PUBKEY_LEN);
+}
+
+/** Generate a new keypair and return the secret key. If <b>extra_strong</b>
+ * is true, this key is possibly going to get used more than once, so
+ * use a better-than-usual RNG. */
+void
+curve25519_secret_key_generate(curve25519_secret_key_t *key_out,
+ int extra_strong)
+{
+ (void)extra_strong;
+
+ crypto_rand((char*)key_out->secret_key, 32);
+ key_out->secret_key[0] &= 248;
+ key_out->secret_key[31] &= 127;
+ key_out->secret_key[31] |= 64;
+}
+
+void
+curve25519_public_key_generate(curve25519_public_key_t *key_out,
+ const curve25519_secret_key_t *seckey)
+{
+ static const uint8_t basepoint[32] = {9};
+
+ curve25519_impl(key_out->public_key, seckey->secret_key, basepoint);
+}
+
+/** Perform the curve25519 ECDH handshake with <b>skey</b> and <b>pkey</b>,
+ * writing CURVE25519_OUTPUT_LEN bytes of output into <b>output</b>. */
+void
+curve25519_handshake(uint8_t *output,
+ const curve25519_secret_key_t *skey,
+ const curve25519_public_key_t *pkey)
+{
+ curve25519_impl(output, skey->secret_key, pkey->public_key);
+}
+
diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h
new file mode 100644
index 000000000..3e093be7b
--- /dev/null
+++ b/src/common/crypto_curve25519.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_CRYPTO_CURVE25519_H
+#define TOR_CRYPTO_CURVE25519_H
+
+#include "torint.h"
+
+/** Length of a curve25519 public key when encoded. */
+#define CURVE25519_PUBKEY_LEN 32
+/** Length of a curve25519 secret key when encoded. */
+#define CURVE25519_SECKEY_LEN 32
+/** Length of the result of a curve25519 handshake. */
+#define CURVE25519_OUTPUT_LEN 32
+
+/** Wrapper type for a curve25519 public key */
+typedef struct curve25519_public_key_t {
+ uint8_t public_key[CURVE25519_PUBKEY_LEN];
+} curve25519_public_key_t;
+
+/** Wrapper type for a curve25519 secret key */
+typedef struct curve25519_secret_key_t {
+ uint8_t secret_key[CURVE25519_SECKEY_LEN];
+} curve25519_secret_key_t;
+
+int curve25519_public_key_is_ok(const curve25519_public_key_t *);
+
+void curve25519_secret_key_generate(curve25519_secret_key_t *key_out,
+ int extra_strong);
+void curve25519_public_key_generate(curve25519_public_key_t *key_out,
+ const curve25519_secret_key_t *seckey);
+
+void curve25519_handshake(uint8_t *output,
+ const curve25519_secret_key_t *,
+ const curve25519_public_key_t *);
+
+#ifdef CRYPTO_CURVE25519_PRIVATE
+int curve25519_impl(uint8_t *output, const uint8_t *secret,
+ const uint8_t *basepoint);
+#endif
+
+#endif
+
diff --git a/src/common/include.am b/src/common/include.am
index 0fdc72057..f986ba66d 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -14,6 +14,22 @@ else
libor_extra_source=
endif
+if BUILD_CURVE25519_DONNA
+libcrypto_extra_source= \
+ src/ext/curve25519_donna/curve25519-donna.c \
+ src/common/crypto_curve25519.c
+else
+if BUILD_CURVE25519_DONNA_C64
+libcrypto_extra_source= \
+ src/ext/curve25519_donna/curve25519-donna-c64.c \
+ src/common/crypto_curve25519.c
+else
+if CURVE25519_ENABLED
+libcrypto_extra_source=src/common/crypto_curve25519.c
+endif
+endif
+endif
+
src_common_libor_a_SOURCES = \
src/common/address.c \
src/common/compat.c \
@@ -31,7 +47,8 @@ src_common_libor_crypto_a_SOURCES = \
src/common/aes.c \
src/common/crypto.c \
src/common/torgzip.c \
- src/common/tortls.c
+ src/common/tortls.c \
+ $(libcrypto_extra_source)
src_common_libor_event_a_SOURCES = src/common/compat_libevent.c
@@ -43,6 +60,7 @@ COMMONHEADERS = \
src/common/compat_libevent.h \
src/common/container.h \
src/common/crypto.h \
+ src/common/crypto_curve25519.h \
src/common/di_ops.h \
src/common/memarea.h \
src/common/mempool.h \
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 28e293743..8aadd979a 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -5,9 +5,13 @@
#include "orconfig.h"
#define CRYPTO_PRIVATE
+#define CRYPTO_CURVE25519_PRIVATE
#include "or.h"
#include "test.h"
#include "aes.h"
+#ifdef CURVE25519_ENABLED
+#include "crypto_curve25519.h"
+#endif
/** Run unit tests for Diffie-Hellman functionality. */
static void
@@ -929,6 +933,80 @@ test_crypto_hkdf_sha256(void *arg)
#undef EXPAND
}
+#ifdef CURVE25519_ENABLED
+static void
+test_crypto_curve25519_impl(void *arg)
+{
+ /* adapted from curve25519_donna, which adapted it from test-curve25519
+ version 20050915, by D. J. Bernstein, Public domain. */
+
+ unsigned char e1k[32];
+ unsigned char e2k[32];
+ unsigned char e1e2k[32];
+ unsigned char e2e1k[32];
+ unsigned char e1[32] = {3};
+ unsigned char e2[32] = {5};
+ unsigned char k[32] = {9};
+ int loop, i;
+ const int loop_max=10000;
+ char *mem_op_hex_tmp = NULL;
+
+ (void)arg;
+
+ for (loop = 0; loop < loop_max; ++loop) {
+ curve25519_impl(e1k,e1,k);
+ curve25519_impl(e2e1k,e2,e1k);
+ curve25519_impl(e2k,e2,k);
+ curve25519_impl(e1e2k,e1,e2k);
+ test_memeq(e1e2k, e2e1k, 32);
+ if (loop == loop_max-1) {
+ break;
+ }
+ for (i = 0;i < 32;++i) e1[i] ^= e2k[i];
+ for (i = 0;i < 32;++i) e2[i] ^= e1k[i];
+ for (i = 0;i < 32;++i) k[i] ^= e1e2k[i];
+ }
+
+ test_memeq_hex(e1,
+ "4faf81190869fd742a33691b0e0824d5"
+ "7e0329f4dd2819f5f32d130f1296b500");
+ test_memeq_hex(e2k,
+ "05aec13f92286f3a781ccae98995a3b9"
+ "e0544770bc7de853b38f9100489e3e79");
+ test_memeq_hex(e1e2k,
+ "cd6e8269104eb5aaee886bd2071fba88"
+ "bd13861475516bc2cd2b6e005e805064");
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_crypto_curve25519_wrappers(void *arg)
+{
+ curve25519_public_key_t pubkey1, pubkey2;
+ curve25519_secret_key_t seckey1, seckey2;
+
+ uint8_t output1[CURVE25519_OUTPUT_LEN];
+ uint8_t output2[CURVE25519_OUTPUT_LEN];
+ (void)arg;
+
+ /* Test a simple handshake, serializing and deserializing some stuff. */
+ curve25519_secret_key_generate(&seckey1, 0);
+ curve25519_secret_key_generate(&seckey2, 0);
+ curve25519_public_key_generate(&pubkey1, &seckey1);
+ curve25519_public_key_generate(&pubkey2, &seckey2);
+ test_assert(curve25519_public_key_is_ok(&pubkey1));
+ test_assert(curve25519_public_key_is_ok(&pubkey2));
+ curve25519_handshake(output1, &seckey1, &pubkey2);
+ curve25519_handshake(output2, &seckey2, &pubkey1);
+ test_memeq(output1, output2, sizeof(output1));
+
+ done:
+ ;
+}
+#endif
+
static void *
pass_data_setup_fn(const struct testcase_t *testcase)
{
@@ -962,6 +1040,10 @@ struct testcase_t crypto_tests[] = {
CRYPTO_LEGACY(base32_decode),
{ "kdf_TAP", test_crypto_kdf_TAP, 0, NULL, NULL },
{ "hkdf_sha256", test_crypto_hkdf_sha256, 0, NULL, NULL },
+#ifdef CURVE25519_ENABLED
+ { "curve25519_impl", test_crypto_curve25519_impl, 0, NULL, NULL },
+ { "curve25519_wrappers", test_crypto_curve25519_wrappers, 0, NULL, NULL },
+#endif
END_OF_TESTCASES
};