tor-commits
Threads by month
- ----- 2026 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 216106 discussions
commit 6161bb51a042e5ab6b3f4bdf929258307b86e759
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Sat Jun 2 14:09:54 2012 -0700
Fix compile errors with gcc 4.7
---
src/steg/jsSteg.cc | 2 +-
src/test/tinytest_macros.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/steg/jsSteg.cc b/src/steg/jsSteg.cc
index 6ff0b89..dbe4431 100644
--- a/src/steg/jsSteg.cc
+++ b/src/steg/jsSteg.cc
@@ -351,7 +351,7 @@ int encodeHTTPBody(char *data, char *jTemplate, char *jData,
char *jsStart, *jsEnd;
int skip;
int scriptLen;
- int fin;
+ int fin = 0;
unsigned int dlen2 = dlen;
dp = data;
jtp = jTemplate;
diff --git a/src/test/tinytest_macros.h b/src/test/tinytest_macros.h
index 00d8732..5dd2742 100644
--- a/src/test/tinytest_macros.h
+++ b/src/test/tinytest_macros.h
@@ -112,7 +112,7 @@
setup_block; \
_print2 = _print; \
TT_DECLARE(_tt_status?" OK":"FAIL", \
- ("assert(%s): "printf_fmt" vs "printf_fmt, \
+ ("assert(%s): " printf_fmt " vs " printf_fmt,\
str_test, _print1, _print2)); \
_print = _print1; \
cleanup_block; \
1
0
[stegotorus/master] Have configure activate extended C library features and large file support. Detect whether 'ranlib' is unnecessary.
by zwol@torproject.org 20 Jul '12
by zwol@torproject.org 20 Jul '12
20 Jul '12
commit 491d09efb9e90c8762954f68e37efb7f42f38a16
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Sat Jun 2 14:15:10 2012 -0700
Have configure activate extended C library features and large file support. Detect whether 'ranlib' is unnecessary.
---
configure.ac | 22 +++++++++----
m4/ranlib.m4 | 69 ++++++++++++++++++++++++++++++++++++++++
m4/system_extensions.m4 | 81 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 165 insertions(+), 7 deletions(-)
diff --git a/configure.ac b/configure.ac
index 647879a..6dc4fe3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,10 +9,22 @@ AC_LANG([C++])
AM_INIT_AUTOMAKE([foreign nostdinc silent-rules subdir-objects])
AM_MAINTAINER_MODE([enable])
-### Programs ###
+### Compiler and language features ###
+AC_PROG_CC
AC_PROG_CXX
-AC_PROG_RANLIB
+AC_PROG_CXXCPP
+
+AX_SYS_EXTENSIONS
+AC_SYS_LARGEFILE
+
+AX_CXXFLAGS_STDCXX_11([ext])
+AX_CXX_DELETE_METHOD
+AX_CXX_STATIC_ASSERT
+
+### Programs ###
+
+AX_PROG_RANLIB
PKG_PROG_PKG_CONFIG
# We need python 2.7 for TestLoader.discover().
@@ -60,14 +72,10 @@ AC_SUBST(lib_CPPFLAGS)
AX_LIB_WINSOCK2
LIBS="$LIBS $ws32_LIBS"
-### Language features ###
+### System features ###
AC_CHECK_HEADERS([execinfo.h],,,[/**/])
-AX_CXXFLAGS_STDCXX_11([ext])
-AX_CXX_DELETE_METHOD
-AX_CXX_STATIC_ASSERT
-
### Output ###
AC_CONFIG_FILES([Makefile])
diff --git a/m4/ranlib.m4 b/m4/ranlib.m4
new file mode 100644
index 0000000..ce4fe33
--- /dev/null
+++ b/m4/ranlib.m4
@@ -0,0 +1,69 @@
+# SYNOPSIS
+#
+# AX_PROG_RANLIB
+#
+# DESCRIPTION
+#
+# In addition to everything AC_PROG_RANLIB does, determine whether it is
+# _necessary_ to run 'ranlib' after 'ar'. If it is unnecessary (which is
+# the case on most modern systems), reset the RANLIB variable to ':'.
+#
+# LICENSE
+#
+# Same as Autoconf proper.
+
+# serial 1
+
+# 'ranlib' may be needed to make it possible for objects that occur
+# later in an archive library to refer to symbols defined by objects
+# earlier in the archive. Therefore, the testing strategy is to
+# compile three small files where A refers to B refers to C, put C and
+# B in an archive *in that order*, and then see if we can link A
+# against the archive.
+
+AC_DEFUN([AX_PROG_RANLIB],
+[AC_CHECK_TOOL([AR], [ar])
+AC_CHECK_TOOL([RANLIB], [ranlib], [:])
+if test x$RANLIB != x:; then
+ AC_CACHE_CHECK([whether ranlib is necessary], [ac_cv_prog_RANLIB_necessary],
+ [AC_LANG_PUSH([C])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ extern int B(void);
+ int main(void) { return B(); }
+ ]])],
+ [cp conftest.$ac_objext conftA.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file A])])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ extern int C(void);
+ int B(void) { return C(); }
+ ]])],
+ [cp conftest.$ac_objext conftB.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file B])])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ int C(void) { return 0; }
+ ]])],
+ [cp conftest.$ac_objext conftC.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file C])])
+
+ dnl There is no standard macro for creating an archive.
+ _AC_DO([$AR cru conftest.a conftC.$ac_objext conftB.$ac_objext]) ||
+ AC_MSG_ERROR([failed to create test archive])
+
+ dnl There's no good way to make AC_LINK_IFELSE do what we need.
+ AS_IF([_AC_DO([$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
+ [ac_cv_prog_RANLIB_necessary=no],
+ [AS_IF([_AC_DO([$RANLIB conftest.a && $CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
+ [ac_cv_prog_RANLIB_necessary=yes],
+ [AC_MSG_ERROR([test link failed with and without ranlib])])])
+
+ rm -f conftest$ac_exeext conft[ABC].$ac_objext conftest.a
+ AC_LANG_POP([C])
+ ])
+ if test $ac_cv_prog_RANLIB_necessary = no; then
+ RANLIB=:
+ fi
+fi
+])
diff --git a/m4/system_extensions.m4 b/m4/system_extensions.m4
new file mode 100644
index 0000000..46b2f9e
--- /dev/null
+++ b/m4/system_extensions.m4
@@ -0,0 +1,81 @@
+# SYNOPSIS
+#
+# AX_SYS_EXTENSIONS
+#
+# DESCRIPTION
+#
+# Functionally equivalent to the stock AC_USE_SYSTEM_EXTENSIONS, but:
+# does not trigger AC_CHECK_HEADER's backward compatibility mode;
+# does not make use of AC_INCLUDES_DEFAULT;
+# does not define _MINIX.
+#
+# LICENSE
+#
+# Same as Autoconf proper.
+
+# serial 1
+
+# Enable extensions on systems that normally disable them,
+# typically due to standards-conformance issues.
+#
+# Remember that #undef in AH_VERBATIM gets replaced with #define by
+# AC_DEFINE. The goal here is to define all known feature-enabling
+# macros, then, if reports of conflicts are made, disable macros that
+# cause problems on some platforms (such as __EXTENSIONS__).
+AC_DEFUN_ONCE([AX_SYS_EXTENSIONS],
+[AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
+AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
+AC_PROVIDE([AC_USE_SYSTEM_EXTENSIONS])dnl Suppress the stock macro if used.
+
+ AC_CHECK_HEADER([minix/config.h], [MINIX=yes], [MINIX=], [/**/])
+ if test "$MINIX" = yes; then
+ AC_DEFINE([_POSIX_SOURCE], [1],
+ [Define to 1 if you need to in order for `stat' and other
+ things to work.])
+ AC_DEFINE([_POSIX_1_SOURCE], [2],
+ [Define to 2 if the system does not provide POSIX.1 features
+ except with this defined.])
+ fi
+
+dnl Use a different key than __EXTENSIONS__, as that name broke existing
+dnl configure.ac when using autoheader 2.62.
+ AH_VERBATIM([USE_SYSTEM_EXTENSIONS],
+[/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+])
+ AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
+ [ac_cv_safe_to_define___extensions__],
+ [AC_COMPILE_IFELSE(
+ dnl http://lists.gnu.org/archive/html/bug-gnulib/2006-02/msg00002.html
+ dnl implies that testing <stdlib.h> is adequate.
+ [AC_LANG_PROGRAM([[
+# define __EXTENSIONS__ 1
+# include <stdlib.h>
+ ]])],
+ [ac_cv_safe_to_define___extensions__=yes],
+ [ac_cv_safe_to_define___extensions__=no])])
+ test $ac_cv_safe_to_define___extensions__ = yes &&
+ AC_DEFINE([__EXTENSIONS__])
+ AC_DEFINE([_ALL_SOURCE])
+ AC_DEFINE([_GNU_SOURCE])
+ AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
+ AC_DEFINE([_TANDEM_SOURCE])
+])# AX_SYS_EXTENSIONS
1
0
20 Jul '12
commit a6051fba5236f7866a3c0967b08e771224948816
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Sat Jun 2 19:18:10 2012 -0700
Add APRAdb registration helper support.
---
Makefile.am | 1 +
configure.ac | 3 +-
src/audit-globals.sh | 11 +-
src/listener.h | 15 ++
src/main.cc | 69 +++++++-
src/network.cc | 16 +--
src/protocol.h | 25 ++-
src/protocol/chop.cc | 12 +-
src/protocol/null.cc | 5 +-
src/steg.h | 6 +-
src/subprocess-unix.cc | 468 ++++++++++++++++++++++++++++++++++++++++++++++++
src/subprocess.h | 68 +++++++
12 files changed, 667 insertions(+), 32 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 88939fd..a21f053 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -37,6 +37,7 @@ libstegotorus_a_SOURCES = \
src/protocol.cc \
src/rng.cc \
src/socks.cc \
+ src/subprocess-unix.cc \
src/steg.cc \
src/util.cc \
$(PROTOCOLS) $(STEGANOGRAPHERS)
diff --git a/configure.ac b/configure.ac
index 6dc4fe3..4c23af6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,7 +74,8 @@ LIBS="$LIBS $ws32_LIBS"
### System features ###
-AC_CHECK_HEADERS([execinfo.h],,,[/**/])
+AC_CHECK_HEADERS([execinfo.h paths.h],,,[/**/])
+AC_CHECK_FUNCS([closefrom execvpe])
### Output ###
diff --git a/src/audit-globals.sh b/src/audit-globals.sh
index 2a94462..13565aa 100644
--- a/src/audit-globals.sh
+++ b/src/audit-globals.sh
@@ -27,27 +27,28 @@ sed '
# them. The above commands have stripped any leading src/ and/or
# .o or .obj extension.
- # These are genuinely OK.
/^compression ZLIB_CEILING$/d
/^compression ZLIB_UINT_MAX$/d
/^connections circuits$/d
- /^connections connections$/d
/^connections closing_all_connections$/d
+ /^connections connections$/d
/^connections last_ckt_serial$/d
/^connections last_conn_serial$/d
/^connections shutting_down$/d
+ /^crypt init_crypto()::initialized$/d
+ /^crypt log_crypto()::initialized$/d
/^main allow_kq$/d
- /^main the_event_base$/d
/^main handle_signal_cb(int, short, void\*)::got_sigint$/d
+ /^main registration_helper$/d
+ /^main the_event_base$/d
/^network listeners$/d
/^rng rng$/d
+ /^subprocess-unix already_waited$/d
/^util log_dest$/d
/^util log_min_sev$/d
/^util log_timestamps$/d
/^util log_ts_base$/d
/^util the_evdns_base$/d
- /^crypt log_crypto()::initialized$/d
- /^crypt init_crypto()::initialized$/d
')
if [ -n "$symbols" ]; then
diff --git a/src/listener.h b/src/listener.h
index 6a73d1d..6813686 100644
--- a/src/listener.h
+++ b/src/listener.h
@@ -4,8 +4,23 @@
#ifndef LISTENER_H
#define LISTENER_H
+#include <vector>
+
+/**
+ This struct defines the state of a listener on a particular address.
+ */
+struct listener_t
+{
+ config_t *cfg;
+ struct evconnlistener *listener;
+ char *address;
+ size_t index;
+};
+
/* returns 1 on success, 0 on failure */
int listener_open(struct event_base *base, config_t *cfg);
void listener_close_all(void);
+std::vector<listener_t *> const& get_all_listeners();
+
#endif
diff --git a/src/main.cc b/src/main.cc
index 8c1407f..9cc1300 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -10,6 +10,8 @@
#include "crypt.h"
#include "listener.h"
#include "protocol.h"
+#include "steg.h"
+#include "subprocess.h"
#include <vector>
#include <string>
@@ -35,6 +37,7 @@ using std::string;
static struct event_base *the_event_base;
static bool allow_kq = false;
+static string registration_helper;
/**
Puts stegotorus's networking subsystem on "closing time" mode. This
@@ -160,6 +163,59 @@ stdin_detect_eof_cb(evutil_socket_t fd, short, void *arg)
}
/**
+ APRAdb registration hook.
+*/
+static void
+call_registration_helper(string const& helper)
+{
+ vector<string> env = get_environ("ST_");
+ env.push_back("ST_SERVER_KEY=placeholder_server_key");
+
+ vector<listener_t*> const& listeners = get_all_listeners();
+ vector<listener_t*>::const_iterator el;
+ unsigned int n = 0;
+ char buf[512];
+
+ for (el = listeners.begin(); el != listeners.end(); el++, n++) {
+ const steg_config_t *sc = (*el)->cfg->get_steg((*el)->index);
+ if (!sc)
+ continue;
+
+ // The address is in the form x.y.z.w:port or [a:b:c...]:port.
+ // We want IP and port in separate strings. Also, in the latter
+ // case, we want to get rid of the square brackets.
+ string ap((*el)->address);
+ size_t colon = ap.rfind(':');
+ string addr(ap, 0, colon);
+ string port(ap, colon+1);
+
+ if (addr[0] == '[') {
+ addr.erase(addr.size()-1, 1);
+ addr.erase(0,1);
+ }
+
+ if (xsnprintf(buf, sizeof buf, "ST_LISTENER_%u=%s,tcp,%s,%s",
+ n, addr.c_str(), port.c_str(), sc->name()) == -1) {
+ log_warn("listener %u info is too big", n);
+ continue;
+ }
+ env.push_back(buf);
+ }
+
+ vector<string> args;
+ args.push_back(helper);
+ subprocess h = subprocess::call(args, env);
+ if (h.state == CLD_DUMPED) {
+ log_warn("%s: %s (core dumped)", helper.c_str(), strsignal(h.returncode));
+ } else if (h.state == CLD_KILLED) {
+ log_warn("%s: %s", helper.c_str(), strsignal(h.returncode));
+ } else if (h.state == CLD_EXITED && h.returncode != 0) {
+ log_warn("%s: exited unsuccessfully, status %d",
+ helper.c_str(), h.returncode);
+ }
+}
+
+/**
Prints usage instructions then exits.
*/
static void ATTR_NORETURN
@@ -200,6 +256,7 @@ handle_generic_args(const char *const *argv)
bool logsev_set = false;
bool allow_kq_set = false;
bool timestamps_set = false;
+ bool registration_helper_set=false;
int i = 1;
while (argv[i] &&
@@ -250,8 +307,15 @@ handle_generic_args(const char *const *argv)
}
allow_kq = true;
allow_kq_set = true;
+ } else if (!strncmp(argv[i], "--registration-helper=", 22)) {
+ if (registration_helper_set) {
+ fprintf(stderr, "you've already set a registration helper!\n");
+ exit(1);
+ }
+ registration_helper = string(argv[i]+22);
+ registration_helper_set = true;
} else {
- fprintf(stderr, "unrecognizable argument '%s'", argv[i]);
+ fprintf(stderr, "unrecognizable argument '%s'\n", argv[i]);
exit(1);
}
i++;
@@ -409,6 +473,9 @@ main(int, const char *const *argv)
log_abort("failed to open listeners for configuration %lu",
(unsigned long)(i - configs.begin()) + 1);
+ if (!registration_helper.empty())
+ call_registration_helper(registration_helper);
+
/* We are go for launch. As a signal to any monitoring process that may
be running, close stdout now. */
log_info("%s process %lu now initialized", argv[0], (unsigned long)getpid());
diff --git a/src/network.cc b/src/network.cc
index f436ef4..b5f6d4b 100644
--- a/src/network.cc
+++ b/src/network.cc
@@ -20,17 +20,6 @@
using std::vector;
-/**
- This struct defines the state of a listener on a particular address.
- */
-struct listener_t
-{
- config_t *cfg;
- struct evconnlistener *listener;
- char *address;
- size_t index;
-};
-
/** All our listeners. */
static vector<listener_t *> listeners;
@@ -57,6 +46,11 @@ static void downstream_event_cb(struct bufferevent *bev, short what, void *arg);
static void create_outbound_connections(circuit_t *ckt, bool is_socks);
static void create_outbound_connections_socks(circuit_t *ckt);
+vector<listener_t *> const& get_all_listeners()
+{
+ return listeners;
+}
+
/**
This function opens listening sockets configured according to the
provided 'config_t'. Returns 1 on success, 0 on failure.
diff --git a/src/protocol.h b/src/protocol.h
index fbc459e..a2e467d 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -7,6 +7,7 @@
#define PROTOCOL_H
struct proto_module;
+struct steg_config_t;
/** A 'config_t' is a set of addresses to listen on, and what to do
when connections are received. A protocol module must define a
@@ -29,7 +30,7 @@ struct config_t
/** Return the name of the protocol associated with this
configuration. You do not have to define this method in your
subclass, PROTO_DEFINE_MODULE does it for you. */
- virtual const char *name() = 0;
+ virtual const char *name() const = 0;
/** Initialize yourself from a set of command line options. This is
separate from the subclass constructor so that it can fail:
@@ -42,7 +43,7 @@ struct config_t
users of this function should call it repeatedly with successive
values of N, starting from zero, until it returns NULL, and
create listeners for every address returned. */
- virtual evutil_addrinfo *get_listen_addrs(size_t n) = 0;
+ virtual evutil_addrinfo *get_listen_addrs(size_t n) const = 0;
/** Return a set of addresses to attempt an outbound connection to,
in the form of an 'evutil_addrinfo' linked list. As with
@@ -50,7 +51,12 @@ struct config_t
should in general attempt simultaneous connection to at least
one address from every list. The maximum N is indicated in the
same way as for get_listen_addrs. */
- virtual evutil_addrinfo *get_target_addrs(size_t n) = 0;
+ virtual evutil_addrinfo *get_target_addrs(size_t n) const = 0;
+
+ /** Return the steganography module associated with either listener
+ or target address set N. If called on a protocol that doesn't
+ use steganography, will return NULL. */
+ virtual const steg_config_t *get_steg(size_t n) const = 0;
/** Return an extended 'circuit_t' object for a new socket using
this configuration. The 'index' argument is equal to the 'N'
@@ -87,7 +93,7 @@ extern const proto_module *const supported_protos[];
#define PROTO_DEFINE_MODULE(mod) \
/* canned methods */ \
- const char *mod##_config_t::name() \
+ const char *mod##_config_t::name() const \
{ return #mod; } \
\
static config_t * \
@@ -106,14 +112,19 @@ extern const proto_module *const supported_protos[];
#define CONFIG_DECLARE_METHODS(mod) \
mod##_config_t(); \
virtual ~mod##_config_t(); \
- virtual const char *name(); \
+ virtual const char *name() const; \
virtual bool init(int n_opts, const char *const *opts); \
- virtual evutil_addrinfo *get_listen_addrs(size_t n); \
- virtual evutil_addrinfo *get_target_addrs(size_t n); \
+ virtual evutil_addrinfo *get_listen_addrs(size_t n) const; \
+ virtual evutil_addrinfo *get_target_addrs(size_t n) const; \
+ virtual const steg_config_t *get_steg(size_t n) const; \
virtual circuit_t *circuit_create(size_t index); \
virtual conn_t *conn_create(size_t index) \
/* deliberate absence of semicolon */
+#define CONFIG_STEG_STUBS(mod) \
+ const steg_config_t *mod##_config_t::get_steg(size_t) const \
+ { return 0; }
+
#define CONN_DECLARE_METHODS(mod) \
mod##_conn_t(); \
virtual ~mod##_conn_t(); \
diff --git a/src/protocol/chop.cc b/src/protocol/chop.cc
index 5451925..f547303 100644
--- a/src/protocol/chop.cc
+++ b/src/protocol/chop.cc
@@ -475,7 +475,7 @@ chop_config_t::init(int n_options, const char *const *options)
}
struct evutil_addrinfo *
-chop_config_t::get_listen_addrs(size_t n)
+chop_config_t::get_listen_addrs(size_t n) const
{
if (mode == LSN_SIMPLE_SERVER) {
if (n < down_addresses.size())
@@ -488,7 +488,7 @@ chop_config_t::get_listen_addrs(size_t n)
}
struct evutil_addrinfo *
-chop_config_t::get_target_addrs(size_t n)
+chop_config_t::get_target_addrs(size_t n) const
{
if (mode == LSN_SIMPLE_SERVER) {
if (n == 0)
@@ -500,6 +500,14 @@ chop_config_t::get_target_addrs(size_t n)
return NULL;
}
+const steg_config_t *
+chop_config_t::get_steg(size_t n) const
+{
+ if (n < steg_targets.size())
+ return steg_targets[n];
+ return NULL;
+}
+
// Circuit methods
const char passphrase[] =
diff --git a/src/protocol/null.cc b/src/protocol/null.cc
index 90abec2..d8fe98b 100644
--- a/src/protocol/null.cc
+++ b/src/protocol/null.cc
@@ -102,7 +102,7 @@ null_config_t::init(int n_options, const char *const *options)
/** Retrieve the 'n'th set of listen addresses for this configuration. */
struct evutil_addrinfo *
-null_config_t::get_listen_addrs(size_t n)
+null_config_t::get_listen_addrs(size_t n) const
{
if (n > 0)
return 0;
@@ -111,7 +111,7 @@ null_config_t::get_listen_addrs(size_t n)
/* Retrieve the target address for this configuration. */
struct evutil_addrinfo *
-null_config_t::get_target_addrs(size_t n)
+null_config_t::get_target_addrs(size_t n) const
{
if (n > 0)
return 0;
@@ -287,4 +287,5 @@ null_conn_t::recv_eof()
return 0;
}
+CONFIG_STEG_STUBS(null);
CONN_STEG_STUBS(null);
diff --git a/src/steg.h b/src/steg.h
index fe8ef5e..f042864 100644
--- a/src/steg.h
+++ b/src/steg.h
@@ -26,7 +26,7 @@ struct steg_config_t
/** Report the name of this steg module. You do not have to define
this method in your subclass, STEG_DEFINE_MODULE does it for you. */
- virtual const char *name() = 0;
+ virtual const char *name() const = 0;
/** Create an extended 'steg_t' object (see below) from this
configuration, associated with connection CONN. */
@@ -110,7 +110,7 @@ steg_config_t *steg_new(const char *name, config_t *cfg);
{ return new mod##_steg_config_t(cfg); } \
\
/* canned methods */ \
- const char *mod##_steg_config_t::name() \
+ const char *mod##_steg_config_t::name() const \
{ return #mod; } \
\
/* module object */ \
@@ -121,7 +121,7 @@ steg_config_t *steg_new(const char *name, config_t *cfg);
#define STEG_CONFIG_DECLARE_METHODS(mod) \
mod##_steg_config_t(config_t *); \
virtual ~mod##_steg_config_t(); \
- virtual const char *name(); \
+ virtual const char *name() const; \
virtual steg_t *steg_create(conn_t *) \
/* deliberate absence of semicolon */
diff --git a/src/subprocess-unix.cc b/src/subprocess-unix.cc
new file mode 100644
index 0000000..7e4b8a2
--- /dev/null
+++ b/src/subprocess-unix.cc
@@ -0,0 +1,468 @@
+/* Copyright 2012 SRI International
+ * Portions copyright 2003-2011 Roger Dingledine, Nick Mathewson,
+ * and/or The Tor Project, Inc.
+ * Portions copyright 1991-2012 The Regents of the University of California
+ * and/or various FreeBSD contributors.
+ * See LICENSE for other credits and copying information.
+ */
+
+// N.B. This file will have to be rewritten more-or-less from scratch
+// for the Windows port. It should be acceptably portable to all Unix
+// implementations still in wide use.
+
+#include "util.h"
+#include "subprocess.h"
+
+#include <map>
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#ifndef _PATH_DEFPATH
+#define _PATH_DEFPATH "/usr/bin:/bin"
+#endif
+
+#ifndef PATH_MAX
+# ifdef MAXPATHLEN
+# define PATH_MAX MAXPATHLEN
+# else
+# define PATH_MAX 4096
+# endif
+#endif
+
+#ifndef OPEN_MAX
+# define OPEN_MAX 256
+#endif
+
+extern char **environ;
+
+using std::map;
+using std::vector;
+using std::string;
+
+
+// Space for hex values of child state, a slash, saved_errno (with
+// leading minus) and newline (no null)
+#define HEX_ERRNO_SIZE (sizeof(int)*2 + 4)
+
+// State codes for the child side of the fork.
+#define CHILD_STATE_REDIRECT_STDIN 1
+#define CHILD_STATE_REDIRECT_STDOUT 2
+#define CHILD_STATE_REDIRECT_STDERR 3
+#define CHILD_STATE_CLOSEFROM 4
+#define CHILD_STATE_EXEC 5
+
+// Some C libraries get very unhappy with you if you ignore the result
+// of a write call, but where it's used in this file, there is nothing
+// whatsoever we can do if it fails.
+#define IGNORE_FAILURE(expr) do { if (expr) {} } while (0)
+
+// We have not prevented copying of |subprocess| objects, so it is
+// possible that |wait| will be called more than once for the same
+// PID, with no state in the object to tell us so. To prevent
+// problems, maintain a table of processes that we have waited for.
+// We make no attempt to prune this table; its memory requirements
+// should be trivial for the expected uses of this API.
+static map<pid_t, int> already_waited;
+
+// Internal utilities and replacements for system library routines
+// that may or may not exist.
+
+#ifndef HAVE_CLOSEFROM
+static void
+closefrom(int lowfd)
+{
+#ifdef F_CLOSEM
+ // Try F_CLOSEM if it's defined. But it might not work.
+ if (fcntl(lowfd, F_CLOSEM, 0) == 0)
+ return;
+#endif
+
+ // If /proc/self/fd is available, use it.
+ // N.B. Theoretically you are not allowed to use opendir() after fork()
+ // as it's not async-signal-safe. This is overwhelmingly unlikely to
+ // cause problems in practice.
+ DIR *dirp;
+ if ((dirp = opendir("/proc/self/fd")) != 0) {
+ struct dirent *dent;
+ char *endp;
+ while ((dent = readdir(dirp)) != NULL) {
+ unsigned long fd = strtoul(dent->d_name, &endp, 10);
+ if (dent->d_name != endp && *endp == '\0' &&
+ fd < (unsigned long)INT_MAX &&
+ fd >= (unsigned long)lowfd &&
+ fd != (unsigned long)dirfd(dirp))
+ close((int)fd);
+ }
+ closedir(dirp);
+ return;
+ }
+
+ // As a last resort, blindly close all possible fd numbers
+ // between lowfd and _SC_OPEN_MAX.
+ unsigned long maxfd = sysconf(_SC_OPEN_MAX);
+ if (maxfd == (unsigned long)(-1L))
+ maxfd = OPEN_MAX;
+ for (unsigned long fd = lowfd; fd < maxfd; fd++)
+ close((int)fd);
+}
+#endif
+
+#ifndef HAVE_EXECVPE
+// Implementation courtesy FreeBSD 9.0 src/lib/libc/gen/exec.c
+// some adjustments made with reference to the glibc implementation
+static int
+execvpe(const char *name, char * const argv[], char * const envp[])
+{
+ const char *path;
+ const char *p, *q;
+ size_t lp, ln;
+ bool eacces = false;
+ char buf[PATH_MAX];
+
+ // If it's an empty path name, fail immediately.
+ if (*name == '\0') {
+ errno = ENOENT;
+ return -1;
+ }
+
+ // If it's an absolute or relative pathname, do not search $PATH.
+ if (strchr(name, '/')) {
+ execve(name, argv, envp);
+ return -1;
+ }
+ ln = strlen(name);
+
+ // Get the path to search. Intentionally uses the parent
+ // environment, not 'envp'.
+ if (!(path = getenv("PATH")))
+ path = _PATH_DEFPATH;
+
+ q = path;
+ do {
+ p = q;
+ while (*q != '\0' && *q != ':')
+ q++;
+
+ // Double, leading and trailing colons mean the current directory.
+ if (q == p) {
+ p = ".";
+ lp = 1;
+ } else
+ lp = q - p;
+ q++;
+
+ // If the path is too long, complain and skip it. This is a
+ // possible security issue; given a way to make the path too long
+ // the user may execute the wrong program.
+ if (lp + ln + 2 > sizeof(buf)) {
+ IGNORE_FAILURE(write(2, "execvpe: ", 8));
+ IGNORE_FAILURE(write(2, p, lp));
+ IGNORE_FAILURE(write(2, ": path too long\n", 16));
+ continue;
+ }
+
+ memcpy(buf, p, lp);
+ buf[lp] = '/';
+ memcpy(buf + lp + 1, name, ln);
+ buf[lp + ln + 1] = '\0';
+
+ execve(buf, argv, envp);
+ switch (errno) {
+ // These errors all indicate that we should try the next directory.
+ case EACCES:
+ // Remember that at least one failure was due to a permission check;
+ // this will be preferentially reported, unless we hit something even
+ // more serious.
+ eacces = true;
+ case ELOOP:
+ case ENAMETOOLONG:
+ case ENOENT:
+ case ENOTDIR:
+ case ESTALE:
+ case ETIMEDOUT:
+ continue;
+
+ default:
+ // On any other error, give up.
+ // Shell fallback for ENOEXEC deliberately removed, as it is a
+ // historical vestige and involves allocating memory.
+ return -1;
+ }
+ } while (*q);
+
+ if (eacces)
+ errno = EACCES;
+ return -1;
+}
+#endif
+
+/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in
+ * <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler
+ * safe.
+ *
+ * <b>hex_errno</b> must have at least HEX_ERRNO_SIZE bytes available.
+ *
+ * The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded
+ * with spaces. Note that there is no trailing \0. CHILD_STATE indicates where
+ * in the processs of starting the child process did the failure occur (see
+ * CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of
+ * errno when the failure occurred.
+ */
+static void
+format_helper_exit_status(unsigned char child_state, int saved_errno,
+ char *hex_errno)
+{
+ unsigned int unsigned_errno;
+ char *cur;
+ size_t i;
+
+ /* Fill hex_errno with spaces, and a trailing newline (memset may
+ not be signal handler safe, so we can't use it) */
+ for (i = 0; i < (HEX_ERRNO_SIZE - 1); i++)
+ hex_errno[i] = ' ';
+ hex_errno[HEX_ERRNO_SIZE - 1] = '\n';
+
+ /* Convert errno to be unsigned for hex conversion */
+ if (saved_errno < 0) {
+ unsigned_errno = (unsigned int) -saved_errno;
+ } else {
+ unsigned_errno = (unsigned int) saved_errno;
+ }
+
+ /* Convert errno to hex (start before \n) */
+ cur = hex_errno + HEX_ERRNO_SIZE - 2;
+
+ /* Check for overflow on first iteration of the loop */
+ if (cur < hex_errno)
+ return;
+
+ do {
+ *cur-- = "0123456789ABCDEF"[unsigned_errno % 16];
+ unsigned_errno /= 16;
+ } while (unsigned_errno != 0 && cur >= hex_errno);
+
+ /* Prepend the minus sign if errno was negative */
+ if (saved_errno < 0 && cur >= hex_errno)
+ *cur-- = '-';
+
+ /* Leave a gap */
+ if (cur >= hex_errno)
+ *cur-- = '/';
+
+ /* Check for overflow on first iteration of the loop */
+ if (cur < hex_errno)
+ return;
+
+ /* Convert child_state to hex */
+ do {
+ *cur-- = "0123456789ABCDEF"[child_state % 16];
+ child_state /= 16;
+ } while (child_state != 0 && cur >= hex_errno);
+}
+
+/** Start a program in the background. If <b>filename</b> contains a '/',
+ * then it will be treated as an absolute or relative path. Otherwise the
+ * system path will be searched for <b>filename</b>. The strings in
+ * <b>argv</b> will be passed as the command line arguments of the child
+ * program (following convention, argv[0] should normally be the filename of
+ * the executable), and the strings in <b>envp</b> will be passed as its
+ * environment variables.
+ *
+ * The child's standard input and output will both be /dev/null;
+ * the child's standard error will be whatever it is in the parent
+ * (unless it is closed in the parent, in which case it will also be
+ * /dev/null)
+ *
+ * All file descriptors numbered higher than 2 will be closed.
+ *
+ * On success, returns the PID of the child; on failure, returns -1.
+ */
+static pid_t
+do_fork_exec(const char *const filename,
+ const char **argv,
+ const char **envp)
+{
+ pid_t pid = fork();
+
+ if (pid == -1) {
+ log_warn("Failed to fork child process: %s", strerror(errno));
+ return -1;
+ }
+
+ if (pid != 0) {
+ // In parent.
+ // If we spawn a child, wait for it, the PID counter wraps
+ // completely around, and then we spawn another child which
+ // happens to get exactly the same PID as the first one, we had
+ // better remove the old record from the already_waited table or
+ // we won't ever actually wait for the new child. The odds of
+ // this are small, but not ridiculously small.
+ already_waited.erase(pid);
+ return pid;
+ }
+
+ // In child
+ char hex_errno[HEX_ERRNO_SIZE];
+ unsigned int child_state = CHILD_STATE_REDIRECT_STDIN;
+
+ close(0);
+ if (open("/dev/null", O_RDONLY) != 0)
+ goto error;
+
+ child_state = CHILD_STATE_REDIRECT_STDOUT;
+
+ close(1);
+ if (open("/dev/null", O_WRONLY) != 1)
+ goto error;
+
+ child_state = CHILD_STATE_REDIRECT_STDERR;
+ if (!isatty(2) && errno == EBADF) {
+ if (open("/dev/null", O_WRONLY) != 2)
+ goto error;
+ }
+
+ child_state = CHILD_STATE_CLOSEFROM;
+ closefrom(3);
+
+ child_state = CHILD_STATE_EXEC;
+
+ // We need the casts because execvpe doesn't declare argv or envp
+ // as const, even though it does not modify them.
+ execvpe(filename, (char *const *) argv, (char *const *)envp);
+
+ error:
+ format_helper_exit_status(child_state, errno, hex_errno);
+
+#define error_message "ERR: Failed to spawn child process: code "
+
+ IGNORE_FAILURE(write(2, error_message, sizeof error_message - 1));
+ IGNORE_FAILURE(write(2, hex_errno, sizeof hex_errno));
+
+#undef error_message
+
+ _exit(255);
+}
+
+// Wrapper: marshal the C++-y vector and map into the form the kernel
+// expects.
+static pid_t
+do_fork_exec(vector<string> const& args,
+ vector<string> const& env)
+{
+ char const* argv[args.size() + 1];
+ char const* envp[env.size() + 1];
+
+ for (size_t i = 0; i < args.size(); i++)
+ argv[i] = args[i].c_str();
+ argv[args.size()] = 0;
+
+ for (size_t i = 0; i < env.size(); i++)
+ envp[i] = env[i].c_str();
+ envp[env.size()] = 0;
+
+ return do_fork_exec(argv[0], argv, envp);
+}
+
+static void
+decode_status(int status, int& state, int& rc)
+{
+ if (WIFEXITED(status)) {
+ rc = WEXITSTATUS(status);
+ state = CLD_EXITED;
+ } else if (WIFSIGNALED(status)) {
+ rc = WTERMSIG(status);
+#ifdef WCOREDUMP
+ if (WCOREDUMP(status))
+ state = CLD_DUMPED;
+ else
+#endif
+ state = CLD_KILLED;
+ } else {
+ // we do not use WUNTRACED, WCONTINUED, or ptrace, so the other
+ // WIF* possibilities should never happen
+ log_abort("impossible wait status %04x", (unsigned int)status);
+ }
+}
+
+static bool
+wait_common(pid_t pid, int& state, int& rc, bool wnohang)
+{
+ if (pid == -1) {
+ // Map failure to fork into the same exit state that we get if
+ // there's a failure in between fork and exec.
+ state = CLD_EXITED;
+ rc = 255;
+ return true;
+ }
+
+ map<pid_t, int>::iterator p = already_waited.find(pid);
+ if (p != already_waited.end()) {
+ decode_status(p->second, state, rc);
+ return true;
+ }
+
+ int status;
+ pid_t rv = waitpid(pid, &status, wnohang ? WNOHANG : 0);
+ if (rv == pid) {
+ decode_status(status, state, rc);
+ already_waited.insert(std::make_pair(pid, status));
+ return true;
+ } else if (rv == 0 && wnohang) {
+ return false;
+ } else {
+ log_warn("waitpid(%d) failed: %s", pid, strerror(errno));
+ return false;
+ }
+}
+
+// subprocess methods
+
+subprocess::subprocess(vector<string> const& args,
+ vector<string> const& env)
+ : pid(do_fork_exec(args, env)),
+ state(0),
+ returncode(-1)
+{
+}
+
+subprocess
+subprocess::call(vector<string> const& args, vector<string> const& env)
+{
+ subprocess proc(args, env);
+ proc.wait();
+ return proc;
+}
+
+bool
+subprocess::poll()
+{
+ return wait_common(pid, state, returncode, true);
+}
+
+void
+subprocess::wait()
+{
+ wait_common(pid, state, returncode, false);
+}
+
+// public utilities
+
+vector<string>
+get_environ(const char *exclude)
+{
+ vector<string> result;
+ size_t exlen = exclude ? strlen(exclude) : 0;
+
+ for (char **p = environ; *p; p++)
+ if (!exclude || strncmp(exclude, *p, exlen))
+ result.push_back(*p);
+
+ return result;
+}
diff --git a/src/subprocess.h b/src/subprocess.h
new file mode 100644
index 0000000..95fe848
--- /dev/null
+++ b/src/subprocess.h
@@ -0,0 +1,68 @@
+/* Copyright 2012 SRI International
+ * See LICENSE for other credits and copying information
+ */
+
+#ifndef SUBPROCESS_H
+#define SUBPROCESS_H
+
+#include <string>
+#include <vector>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+// This API is inspired by the Python subprocess module. While it
+// could be extended to do everything that that does, at present it
+// does much less. If you add features, please consider matching
+// Python's presentation of same.
+
+#ifndef CLD_EXITED
+#define CLD_EXITED 1
+#endif
+#ifndef CLD_KILLED
+#define CLD_KILLED 2
+#endif
+#ifndef CLD_DUMPED
+#define CLD_DUMPED 3
+#endif
+
+struct subprocess
+{
+ // Start a new subprocess with argument vector |args| and environment
+ // vector |env|. stdin and stdout are /dev/null. stderr is inherited.
+ // All file descriptors numbered 3 and higher are closed.
+ // The current working directory is inherited.
+ subprocess(std::vector<std::string> const& args,
+ std::vector<std::string> const& env);
+
+ // Convenience: spawn a subprocess and wait for it to terminate.
+ static subprocess call(std::vector<std::string> const& args,
+ std::vector<std::string> const& env);
+
+ // Check whether the child process has terminated. Returns true if it
+ // has, false otherwise; sets 'state' and 'returncode'.
+ bool poll();
+
+ // Wait for the child process to terminate.
+ void wait();
+
+ // Process ID of the child. -1 on failure to spawn, in which case
+ // an error message has already been logged.
+ const pid_t pid;
+
+ // Child state, either 0 (running) or one of the <signal.h> constants
+ // CLD_EXITED, CLD_KILLED, or CLD_DUMPED.
+ int state;
+
+ // Exit status (if state == CLD_EXITED) or signal that terminated the
+ // process (if state == CLD_KILLED or CLD_DUMPED); -1 otherwise.
+ int returncode;
+};
+
+// Convert the global environment vector to a C++ vector.
+// If 'exclude' is not NULL, then any environment variable whose name
+// begins with those characters will be excluded from the result.
+extern std::vector<std::string> get_environ(const char *exclude = 0);
+
+#endif
1
0
[stegotorus/master] Prepare for having more than one file that touches OpenSSL.
by zwol@torproject.org 20 Jul '12
by zwol@torproject.org 20 Jul '12
20 Jul '12
commit 8a0c099d09284c6717b599c6d70c4cc1913ecc55
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Tue Jun 5 13:49:59 2012 -0700
Prepare for having more than one file that touches OpenSSL.
* Expose init_crypto, log_crypto_abort, and log_crypto_warn.
* Use an explicit teardown function for OpenSSL state instead of
relying on atexit().
Portability/reliability fixes en passant.
* Clarify situation with malloc/realloc in configure.ac.
* Actually check whether we need -lm for floor().
* Use CRYPTO_set_mem_functions to send OpenSSL-internal
memory allocations through xmalloc/xrealloc.
---
configure.ac | 11 +++++---
src/audit-globals.sh | 4 +-
src/crypt.cc | 72 +++++++++++++++++++++++++++++--------------------
src/crypt.h | 27 ++++++++++++++++++
src/main.cc | 3 ++
src/test/unittest.cc | 4 +++
6 files changed, 86 insertions(+), 35 deletions(-)
diff --git a/configure.ac b/configure.ac
index ab56311..889cfae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,14 +16,12 @@ dnl with a rationale for each:
dnl
dnl Defined by C89, therefore unnecessary to check for nowadays:
dnl
-dnl AC_CHECK_FUNCS([atexit floor memset strcasecmp strchr strerror
-dnl strrchr strstr strtoul])
+dnl AC_CHECK_FUNCS([memset strcasecmp strchr strerror strrchr strstr strtoul])
dnl AC_CHECK_HEADERS([limits.h stddef.h stdlib.h string.h])
dnl AC_CHECK_TYPES([ptrdiff_t])
dnl AC_TYPE_SIZE_T
dnl
-dnl We don't make use of the unspecified-behavior corner cases that
-dnl these pin down:
+dnl Dealt with by our 'xmalloc' and 'xrealloc' wrappers:
dnl
dnl AC_FUNC_MALLOC
dnl AC_FUNC_REALLOC
@@ -136,6 +134,11 @@ AC_SUBST(lib_CPPFLAGS)
AX_LIB_WINSOCK2
LIBS="$LIBS $ws32_LIBS"
+# We might need to explicitly link -lm for floor().
+AC_SEARCH_LIBS([floor], [m], [], [
+ AC_MSG_ERROR([unable to find 'floor'])
+])
+
### System features ###
AC_CHECK_HEADERS([execinfo.h paths.h],,,[/**/])
diff --git a/src/audit-globals.sh b/src/audit-globals.sh
index 13565aa..025549f 100644
--- a/src/audit-globals.sh
+++ b/src/audit-globals.sh
@@ -35,8 +35,8 @@ sed '
/^connections last_ckt_serial$/d
/^connections last_conn_serial$/d
/^connections shutting_down$/d
- /^crypt init_crypto()::initialized$/d
- /^crypt log_crypto()::initialized$/d
+ /^crypt crypto_initialized$/d
+ /^crypt crypto_errs_initialized$/d
/^main allow_kq$/d
/^main handle_signal_cb(int, short, void\*)::got_sigint$/d
/^main registration_helper$/d
diff --git a/src/crypt.cc b/src/crypt.cc
index 053f7e6..d4af5e0 100644
--- a/src/crypt.cc
+++ b/src/crypt.cc
@@ -11,30 +11,46 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
-static void
+static bool crypto_initialized = false;
+static bool crypto_errs_initialized = false;
+
+#define REQUIRE_INIT_CRYPTO() \
+ log_assert(crypto_initialized)
+
+void
init_crypto()
{
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
- ENGINE_load_builtin_engines();
- ENGINE_register_all_complete();
- atexit(ENGINE_cleanup);
-
- // we don't need to call OpenSSL_add_all_algorithms or EVP_cleanup,
- // since we never look up ciphers by textual name.
- }
+ log_assert(!crypto_initialized);
+
+ crypto_initialized = true;
+ CRYPTO_set_mem_functions(xmalloc, xrealloc, free);
+ ENGINE_load_builtin_engines();
+ ENGINE_register_all_complete();
+
+ // we don't need to call OpenSSL_add_all_algorithms, since we never
+ // look up ciphers by textual name.
+}
+
+void
+free_crypto()
+{
+ // we don't need to call EVP_cleanup, since we never called
+ // OpenSSL_add_all_algorithms.
+
+ if (crypto_initialized)
+ ENGINE_cleanup();
+ if (crypto_errs_initialized)
+ ERR_free_strings();
}
static void
log_crypto()
{
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
+ if (!crypto_errs_initialized) {
+ crypto_errs_initialized = true;
ERR_load_crypto_strings();
- atexit(ERR_free_strings);
}
+
unsigned long err;
while ((err = ERR_get_error()) != 0)
log_warn("%s: %s: %s",
@@ -43,14 +59,14 @@ log_crypto()
ERR_reason_error_string(err));
}
-static void ATTR_NORETURN
+void ATTR_NORETURN
log_crypto_abort(const char *msg)
{
log_crypto();
log_abort("libcrypto error in %s", msg);
}
-static int
+int
log_crypto_warn(const char *msg)
{
log_crypto();
@@ -145,7 +161,7 @@ namespace {
ecb_encryptor *
ecb_encryptor::create(const uint8_t *key, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
ecb_encryptor_impl *enc = new ecb_encryptor_impl;
if (!EVP_EncryptInit_ex(&enc->ctx, aes_ecb_by_size(keylen), 0, key, 0))
@@ -159,7 +175,7 @@ ecb_encryptor::create(const uint8_t *key, size_t keylen)
ecb_encryptor *
ecb_encryptor::create(key_generator *gen, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
MemBlock key(keylen);
size_t got = gen->generate(key, keylen);
@@ -177,7 +193,7 @@ ecb_encryptor::create(key_generator *gen, size_t keylen)
ecb_decryptor *
ecb_decryptor::create(const uint8_t *key, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
ecb_decryptor_impl *dec = new ecb_decryptor_impl;
if (!EVP_DecryptInit_ex(&dec->ctx, aes_ecb_by_size(keylen), 0, key, 0))
@@ -191,7 +207,7 @@ ecb_decryptor::create(const uint8_t *key, size_t keylen)
ecb_decryptor *
ecb_decryptor::create(key_generator *gen, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
MemBlock key(keylen);
size_t got = gen->generate(key, keylen);
@@ -272,7 +288,7 @@ namespace {
gcm_encryptor *
gcm_encryptor::create(const uint8_t *key, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
gcm_encryptor_impl *enc = new gcm_encryptor_impl;
if (!EVP_EncryptInit_ex(&enc->ctx, aes_gcm_by_size(keylen), 0, key, 0))
@@ -284,7 +300,7 @@ gcm_encryptor::create(const uint8_t *key, size_t keylen)
gcm_encryptor *
gcm_encryptor::create(key_generator *gen, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
MemBlock key(keylen);
size_t got = gen->generate(key, keylen);
@@ -300,7 +316,7 @@ gcm_encryptor::create(key_generator *gen, size_t keylen)
gcm_decryptor *
gcm_decryptor::create(const uint8_t *key, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
gcm_decryptor_impl *dec = new gcm_decryptor_impl;
if (!EVP_DecryptInit_ex(&dec->ctx, aes_gcm_by_size(keylen), 0, key, 0))
@@ -312,7 +328,7 @@ gcm_decryptor::create(const uint8_t *key, size_t keylen)
gcm_decryptor *
gcm_decryptor::create(key_generator *gen, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
MemBlock key(keylen);
size_t got = gen->generate(key, keylen);
@@ -430,6 +446,7 @@ key_generator::from_random_secret(const uint8_t *key, size_t klen,
const uint8_t *ctxt, size_t clen)
{
log_assert(klen <= INT_MAX && slen < INT_MAX && clen < INT_MAX);
+ REQUIRE_INIT_CRYPTO();
MemBlock prk(SHA256_LEN);
@@ -438,8 +455,6 @@ key_generator::from_random_secret(const uint8_t *key, size_t klen,
slen = SHA256_LEN;
}
- init_crypto();
-
if (HMAC(EVP_sha256(), salt, slen, key, klen, prk, 0) == 0)
log_crypto_abort("key_generator::from_random_secret");
@@ -460,6 +475,7 @@ key_generator::from_passphrase(const uint8_t *phra, size_t plen,
// salt, then put the result through HKDF-Extract with the salt.
log_assert(plen <= INT_MAX && slen < INT_MAX);
+ REQUIRE_INIT_CRYPTO();
MemBlock prk(SHA256_LEN);
@@ -468,8 +484,6 @@ key_generator::from_passphrase(const uint8_t *phra, size_t plen,
slen = SHA256_LEN;
}
- init_crypto();
-
if (!PKCS5_PBKDF2_HMAC((const char *)phra, plen, salt, slen,
10000, EVP_sha256(), SHA256_LEN, prk))
log_crypto_abort("key_generator::from_passphrase");
diff --git a/src/crypt.h b/src/crypt.h
index d7e5fbf..4da3309 100644
--- a/src/crypt.h
+++ b/src/crypt.h
@@ -9,6 +9,33 @@ const size_t AES_BLOCK_LEN = 16;
const size_t GCM_TAG_LEN = 16;
const size_t SHA256_LEN = 32;
+/**
+ * Initialize cryptography library. Must be called before anything that
+ * uses any of the APIs below.
+ */
+void init_crypto();
+
+/**
+ * Tear down cryptography library.
+ */
+void free_crypto();
+
+/**
+ * Report a cryptography failure.
+ * @msg should describe the operation that failed.
+ * Always returns -1; this allows you to write
+ * if (some operation failed)
+ * return log_crypto_warn("some operation");
+ */
+int log_crypto_warn(const char *msg);
+
+/**
+ * Report a cryptography failure which is a fatal error.
+ * @msg should describe the operation that failed.
+ * Does not return.
+ */
+void ATTR_NORETURN log_crypto_abort(const char *msg);
+
struct key_generator;
struct ecb_encryptor
diff --git a/src/main.cc b/src/main.cc
index 9cc1300..dd69e68 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -381,6 +381,8 @@ main(int, const char *const *argv)
/* Configurations have been established; proceed with initialization. */
+ init_crypto();
+
/* Ugly method to fix a Windows problem:
http://archives.seul.org/libevent/users/Oct-2010/msg00049.html */
#ifdef _WIN32
@@ -499,6 +501,7 @@ main(int, const char *const *argv)
free(stdin_eof);
event_base_free(the_event_base);
event_config_free(evcfg);
+ free_crypto();
log_close();
return 0;
diff --git a/src/test/unittest.cc b/src/test/unittest.cc
index cba4906..958c82c 100644
--- a/src/test/unittest.cc
+++ b/src/test/unittest.cc
@@ -108,6 +108,8 @@ main(int argc, const char **argv)
log_set_method(LOG_METHOD_NULL, 0);
}
+ init_crypto();
+
/* Ugly method to fix a Windows problem:
http://archives.seul.org/libevent/users/Oct-2010/msg00049.html */
#ifdef _WIN32
@@ -118,7 +120,9 @@ main(int argc, const char **argv)
#endif
rv = tinytest_main(argc, argv, unittest_groups);
+
conn_start_shutdown(1);
+ free_crypto();
return rv;
}
1
0
commit f0eff04bd637c4536f73fa7bc71d233c5e644036
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Tue Jun 5 10:14:18 2012 -0700
Top level directory tidying.
---
.gitignore | 7 +-
LICENSE | 14 +++-
Makefile.am | 2 +-
README.Linda | 117 ----------------------------
config-aux/cxx_delete_method.m4 | 78 +++++++++++++++++++
config-aux/cxx_static_assert.m4 | 57 ++++++++++++++
config-aux/cxxflags_stdcxx_11.m4 | 102 ++++++++++++++++++++++++
config-aux/maintainer.m4 | 39 +++++++++
config-aux/pkg.m4 | 159 ++++++++++++++++++++++++++++++++++++++
config-aux/ranlib.m4 | 69 ++++++++++++++++
config-aux/system_extensions.m4 | 81 +++++++++++++++++++
config-aux/winsock.m4 | 56 +++++++++++++
configure.ac | 1 +
doc/README.Linda | 117 ++++++++++++++++++++++++++++
m4/cxx_delete_method.m4 | 78 -------------------
m4/cxx_static_assert.m4 | 57 --------------
m4/cxxflags_stdcxx_11.m4 | 102 ------------------------
m4/maintainer.m4 | 39 ---------
m4/pkg.m4 | 159 --------------------------------------
m4/ranlib.m4 | 69 ----------------
m4/system_extensions.m4 | 81 -------------------
m4/winsock.m4 | 56 -------------
22 files changed, 773 insertions(+), 767 deletions(-)
diff --git a/.gitignore b/.gitignore
index 8de7c1e..aa3eb46 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,7 +16,6 @@
/aclocal.m4
/autom4te.cache
-/compile
/config.guess
/config.h
/config.h.in
@@ -24,12 +23,12 @@
/config.status
/config.sub
/configure
-/depcomp
-/install-sh
/Makefile
/Makefile.in
-/missing
/stamp-*
+/config-aux/depcomp
+/config-aux/install-sh
+/config-aux/missing
/protolist.c
/steglist.c
diff --git a/LICENSE b/LICENSE
index 3bcae2b..7aea274 100644
--- a/LICENSE
+++ b/LICENSE
@@ -34,7 +34,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=====
-The files in m4/ and scripts/ each have their own individual copyright
-and licensing, which may be more or less permissive than the above
-license. However, those licenses DO NOT extend to the collective
-work, the generated configure script, or to StegoTorus itself.
+Some files in src/ contain material which is copyright other people
+or organizations, and which may be licensed more permissively than the
+above. Comments at the top of each file document its precise provenance
+and licensing.
+
+All the files in config-aux/ and scripts/ have their own copyright and
+licensing, indicated in comments at the top of the file; these licenses
+may be more or *less* permissive than the above. Those licenses DO NOT
+extend to the collective work, the generated configure script, or to
+StegoTorus itself.
diff --git a/Makefile.am b/Makefile.am
index a21f053..64d1d33 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@
# Copyright 2011, 2012 SRI International
# See LICENSE for other credits and copying information
-ACLOCAL_AMFLAGS = -I m4 --install
+ACLOCAL_AMFLAGS = -I config-aux --install
AM_CXXFLAGS = -Werror -Wall -Wextra -Wformat=2
AM_CPPFLAGS = -I. -I$(srcdir)/src -D_FORTIFY_SOURCE=2 $(lib_CPPFLAGS)
diff --git a/README.Linda b/README.Linda
deleted file mode 100644
index 3cb4d2e..0000000
--- a/README.Linda
+++ /dev/null
@@ -1,117 +0,0 @@
-compiling stegotorus on Mac OS X 10.6
-=====================================
-
-0) prelims
-
-Install Mac Ports from http://www.macports.org (here v2.0.3).
-$> sudo port selfupdate [for good measure]
-
- a) autoconf 2.68
-
-$> sudo port install autoconf
-$> autoconf --version
-autoconf (GNU Autoconf) 2.68
-
- b) automake 1.11
-
-$> sudo port install automake
-$> automake --version
-automake (GNU automake) 1.11.1
-
- c) pkgconfig
-
-$> sudo port install pkgconfig
-
- d) openssl >= 1.0.1, libevent-2
-
-$> sudo port install openssl
-$> sudo port install libevent
-
- e) tor
-
-$> sudo port install tor
-$> tor --version
-[...]
-Tor version 0.2.2.34 (git-c4eae752f0d157ce).
-
-
-1) StegoTorus
-
-$> cd ~/src/DEFIANCE/stegotorus/sri
-$> autoreconf -i
-$> ./configure --disable-integration-tests --enable-silent-rules
-[...]
-configure: error: Package requirements (libcrypto++ >= 5.6.0) were not met:
-
-No package 'libcrypto++' found
-[...]
-$> sudo cp Desktop/libcrypto++.pc /usr/lib/pkgconfig/
-$> ./configure --disable-integration-tests --enable-silent-rules
-$> make
-
-
-compiling stegotorus under Ubuntu 11.10
-=======================================
-
-$> sudo apt-get install pkg-config libevent-2.0-5 libevent-dev
-
-Tor:
-----
-
-$> sudo cat >> /etc/apt/sources.list <<EOF
-> deb http://deb.torproject.org/torproject.org oneiric main
-> EOF
-$> gpg --keyserver keys.gnupg.net --recv 886DDD89
-$> gpg --export A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89 | sudo apt-key add -
-$> sudo apt-get install tor tor-geoipdb
-$> tor --version
-[É]
-Tor version 0.2.2.35 (git-73ff13ab3cc9570d).
-
-StegoTorus:
------------
-
-$> autoreconf -i
-$> ./configure --disable-integration-tests --enable-silent-rules
-[...]
-configure: error: Package requirements (libcrypto++ >= 5.6.0) were not met:
-
-No package 'libcrypto++' found
-[...]
-$> sudo apt-get install libcrypto++9 libcrypto++9-dbg libcrypto++-dev
-$> ./configure --disable-integration-tests --enable-silent-rules
-[...]
-configure: error: Package requirements (zlib >= 1.2.3.4) were not met:
-
-No package 'zlib' found
-[...]
-$> sudo apt-get install zlib1g-dbg zlib1g-dev
-$> ./configure --disable-integration-tests --enable-silent-rules
-[...]
-configure: error: Package requirements (zlib >= 1.2.3.4) were not met:
-
-No package 'zlib' found
-[...]
-$> sudo find /usr -name zlib.pc
-/usr/lib/i386-linux-gnu/pkgconfig/zlib.pc
-$> echo $PKG_CONFIG_PATH
-
-$> export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig
-$> ./configure --disable-integration-tests --enable-silent-rules
-$> make
-
-
-compiling obfsproxy under Ubuntu 10.04 (DETERlab)
-=================================================
-
-create local disk space:
-
-$> sudo /usr/local/etc/emulab/mkextrafs.pl /mnt
-
-copy source code there to compile:
-
-$> sudo mkdir /mnt/local/alice
-$> sudo chown linda:SAF-DEFIANCE /mnt/local/alice
-$> cd /mnt/local/alice
-$> tar -xzvf ~/src/stegotorus.tar.gz
-etc.
diff --git a/config-aux/cxx_delete_method.m4 b/config-aux/cxx_delete_method.m4
new file mode 100644
index 0000000..2d467e7
--- /dev/null
+++ b/config-aux/cxx_delete_method.m4
@@ -0,0 +1,78 @@
+# ============================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_cxx_delete_method.m4
+# ============================================================================
+#
+# SYNOPSIS
+#
+# AX_CXX_DELETE_METHOD
+#
+# DESCRIPTION
+#
+# Check whether the C++11 '= delete' syntax, for suppressing undesired
+# implicit methods, is supported. If it is, the macro DELETE_METHOD is
+# defined to '= delete'; otherwise it is defined to nothing. Thus, you
+# can write
+#
+# class foo {
+# ...
+# private:
+# foo(foo const&) DELETE_METHOD;
+# };
+#
+# to delete the 'foo' copy constructor or fall back to the idiom of
+# a private undefined method if the compiler doesn't support this.
+#
+# Does not test '= delete' on a template specialization.
+# Does not ensure that the compiler is in C++11 mode.
+#
+# LICENSE
+#
+# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+AC_DEFUN([AX_CXX_DELETE_METHOD], [dnl
+ AC_LANG_ASSERT([C++])
+ # This compilation should succeed...
+ AC_CACHE_CHECK(whether $CXX accepts method deletion,
+ ax_cv_cxx_delete_method_syntax, [
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ struct foo {
+ foo(double);
+ foo(int) = delete;
+ };
+ extern void t(foo const&);
+ void tt(double n) { t(n); }
+ ]])],
+ [ax_cv_cxx_delete_method_syntax=yes],
+ [ax_cv_cxx_delete_method_syntax=no])])
+ # ... and this one should fail.
+ if test x$ax_cv_cxx_delete_method_syntax = xyes; then
+ AC_CACHE_CHECK(whether $CXX enforces method deletion,
+ ax_cv_cxx_delete_method_enforced, [
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ struct foo {
+ foo(double);
+ foo(int) = delete;
+ };
+ extern void t(foo const&);
+ void tt(int n) { t(n); }
+ ]])],
+ [ax_cv_cxx_delete_method_enforced=no],
+ [ax_cv_cxx_delete_method_enforced=yes])])
+ fi
+ if test x$ax_cv_cxx_delete_method_syntax = xyes &&
+ test x$ax_cv_cxx_delete_method_enforced = xyes
+ then
+ AC_DEFINE([DELETE_METHOD], [= delete],
+ [Define as `= delete' if your compiler supports C++11 method
+ deletion, as nothing otherwise.])
+ else
+ AC_DEFINE([DELETE_METHOD], [],
+ [Define as `= delete' if your compiler supports C++11 method
+ deletion, as nothing otherwise.])
+ fi
+])
diff --git a/config-aux/cxx_static_assert.m4 b/config-aux/cxx_static_assert.m4
new file mode 100644
index 0000000..7bf69f8
--- /dev/null
+++ b/config-aux/cxx_static_assert.m4
@@ -0,0 +1,57 @@
+# SYNOPSIS
+#
+# AX_CXX_STATIC_ASSERT
+#
+# DESCRIPTION
+#
+# Detect whether the C++ compiler, in its present operating mode,
+# supports the C++11 'static_assert' construct. If it doesn't,
+# define 'static_assert' as a preprocessor macro which provides
+# more-or-less the same functionality.
+#
+# LICENSE
+#
+# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 1
+
+AC_DEFUN([AX_CXX_STATIC_ASSERT], [dnl
+ AC_LANG_ASSERT([C++])dnl
+ AC_CACHE_CHECK(whether $CXX accepts static_assert, ax_cv_cxx_static_assert,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([dnl
+ template <typename T>
+ struct check
+ { static_assert(sizeof(int) <= sizeof(T), "not big enough"); };
+ check<int> ok;])],
+ [ax_cv_cxx_static_assert=yes], [ax_cv_cxx_static_assert=no])])
+ if test x$ax_cv_cxx_static_assert = xyes; then
+ AC_CACHE_CHECK(whether $CXX enforces static_assert, ax_cv_cxx_static_assert_e,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([dnl
+ template <typename T>
+ struct check
+ { static_assert(sizeof(char[2]) <= sizeof(T), "not big enough"); };
+ check<char> bad;])],
+ [ax_cv_cxx_static_assert_e=no], [ax_cv_cxx_static_assert_e=yes])])
+ fi
+ if test x$ax_cv_cxx_static_assert = xyes &&
+ test x$ax_cv_cxx_static_assert_e = xyes; then
+ AC_DEFINE(HAVE_STATIC_ASSERT, 1,
+ [Define to 1 if the C++ compiler supports static_assert.])
+ fi
+ AH_VERBATIM([HAVE_STATIC_ASSERT_],
+[#ifndef HAVE_STATIC_ASSERT
+# define static_assert(expr, msg) typedef char static_assert_id[(expr)?1:-1]
+# ifdef __COUNTER__
+# define static_assert_id static_assert_paste(static_assert_, __COUNTER__)
+# else
+# define static_assert_id static_assert_paste(static_assert_, __LINE__)
+# endif
+# define static_assert_paste(a,b) static_assert_paste_(a,b)
+# define static_assert_paste_(a,b) a##b
+#endif])
+])
diff --git a/config-aux/cxxflags_stdcxx_11.m4 b/config-aux/cxxflags_stdcxx_11.m4
new file mode 100644
index 0000000..7f06ed2
--- /dev/null
+++ b/config-aux/cxxflags_stdcxx_11.m4
@@ -0,0 +1,102 @@
+# ============================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_cxxflags_stdcxx_11.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+# AX_CXXFLAGS_STDCXX_11([ext|noext])
+#
+# DESCRIPTION
+#
+# Check for baseline language coverage in the compiler for the C++11
+# standard; if necessary, add switches to CXXFLAGS to enable support.
+# The argument, if specified, indicates whether you insist on an extended
+# mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. -std=c++11).
+# If neither is specified, you get whatever works, with preference for an
+# extended mode.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Benjamin Kosnik <bkoz(a)redhat.com>
+# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 8
+
+m4_define([_AX_CXXFLAGS_STDCXX_11_testbody], [
+ template <typename T>
+ struct check
+ {
+ static_assert(sizeof(int) <= sizeof(T), "not big enough");
+ };
+
+ typedef check<check<bool>> right_angle_brackets;
+
+ int a;
+ decltype(a) b;
+
+ typedef check<int> check_type;
+ check_type c;
+ check_type&& cr = static_cast<check_type&&>(c);
+])
+
+AC_DEFUN([AX_CXXFLAGS_STDCXX_11], [dnl
+ m4_if([$1], [], [],
+ [$1], [ext], [],
+ [$1], [noext], [],
+ [m4_fatal([invalid argument `$1' to AX_CXXFLAGS_STDCXX_11])])dnl
+ AC_LANG_ASSERT([C++])dnl
+ ac_success=no
+ AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
+ ax_cv_cxx_compile_cxx11,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
+ [ax_cv_cxx_compile_cxx11=yes],
+ [ax_cv_cxx_compile_cxx11=no])])
+ if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+ ac_success=yes
+ fi
+
+ m4_if([$1], [noext], [], [dnl
+ if test x$ac_success = xno; then
+ for switch in -std=gnu++11 -std=gnu++0x; do
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+ $cachevar,
+ [ac_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXXFLAGS="$ac_save_CXXFLAGS"])
+ if eval test x\$$cachevar = xyes; then
+ CXXFLAGS="$CXXFLAGS $switch"
+ ac_success=yes
+ break
+ fi
+ done
+ fi])
+
+ m4_if([$1], [ext], [], [dnl
+ if test x$ac_success = xno; then
+ for switch in -std=c++11 -std=c++0x; do
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+ $cachevar,
+ [ac_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXXFLAGS="$ac_save_CXXFLAGS"])
+ if eval test x\$$cachevar = xyes; then
+ CXXFLAGS="$CXXFLAGS $switch"
+ ac_success=yes
+ break
+ fi
+ done
+ fi])
+])
diff --git a/config-aux/maintainer.m4 b/config-aux/maintainer.m4
new file mode 100644
index 0000000..07948a7
--- /dev/null
+++ b/config-aux/maintainer.m4
@@ -0,0 +1,39 @@
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2011
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless `enable' is passed literally.
+# For symmetry, `disable' may be passed as well. Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+ [enable], [m4_define([am_maintainer_other], [disable])],
+ [disable], [m4_define([am_maintainer_other], [enable])],
+ [m4_define([am_maintainer_other], [enable])
+ m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+ AC_ARG_ENABLE([maintainer-mode],
+[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ [USE_MAINTAINER_MODE=$enableval],
+ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST([MAINT])dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
diff --git a/config-aux/pkg.m4 b/config-aux/pkg.m4
new file mode 100644
index 0000000..9a71878
--- /dev/null
+++ b/config-aux/pkg.m4
@@ -0,0 +1,159 @@
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+# serial 1 (pkg-config-0.24)
+#
+# Copyright © 2004 Scott James Remnant <scott(a)netsplit.com>.
+#
+# 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.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+# only at the first occurence in configure.ac, so if the first place
+# it's called might be skipped (such as if it is within an "if", you
+# have to call PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_default([$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes ],
+ [pkg_failed=yes])
+ else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ AC_MSG_RESULT([no])
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+ ])
+elif test $pkg_failed = untried; then
+ AC_MSG_RESULT([no])
+ m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+ ])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ $3
+fi[]dnl
+])# PKG_CHECK_MODULES
diff --git a/config-aux/ranlib.m4 b/config-aux/ranlib.m4
new file mode 100644
index 0000000..ce4fe33
--- /dev/null
+++ b/config-aux/ranlib.m4
@@ -0,0 +1,69 @@
+# SYNOPSIS
+#
+# AX_PROG_RANLIB
+#
+# DESCRIPTION
+#
+# In addition to everything AC_PROG_RANLIB does, determine whether it is
+# _necessary_ to run 'ranlib' after 'ar'. If it is unnecessary (which is
+# the case on most modern systems), reset the RANLIB variable to ':'.
+#
+# LICENSE
+#
+# Same as Autoconf proper.
+
+# serial 1
+
+# 'ranlib' may be needed to make it possible for objects that occur
+# later in an archive library to refer to symbols defined by objects
+# earlier in the archive. Therefore, the testing strategy is to
+# compile three small files where A refers to B refers to C, put C and
+# B in an archive *in that order*, and then see if we can link A
+# against the archive.
+
+AC_DEFUN([AX_PROG_RANLIB],
+[AC_CHECK_TOOL([AR], [ar])
+AC_CHECK_TOOL([RANLIB], [ranlib], [:])
+if test x$RANLIB != x:; then
+ AC_CACHE_CHECK([whether ranlib is necessary], [ac_cv_prog_RANLIB_necessary],
+ [AC_LANG_PUSH([C])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ extern int B(void);
+ int main(void) { return B(); }
+ ]])],
+ [cp conftest.$ac_objext conftA.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file A])])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ extern int C(void);
+ int B(void) { return C(); }
+ ]])],
+ [cp conftest.$ac_objext conftB.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file B])])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ int C(void) { return 0; }
+ ]])],
+ [cp conftest.$ac_objext conftC.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file C])])
+
+ dnl There is no standard macro for creating an archive.
+ _AC_DO([$AR cru conftest.a conftC.$ac_objext conftB.$ac_objext]) ||
+ AC_MSG_ERROR([failed to create test archive])
+
+ dnl There's no good way to make AC_LINK_IFELSE do what we need.
+ AS_IF([_AC_DO([$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
+ [ac_cv_prog_RANLIB_necessary=no],
+ [AS_IF([_AC_DO([$RANLIB conftest.a && $CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
+ [ac_cv_prog_RANLIB_necessary=yes],
+ [AC_MSG_ERROR([test link failed with and without ranlib])])])
+
+ rm -f conftest$ac_exeext conft[ABC].$ac_objext conftest.a
+ AC_LANG_POP([C])
+ ])
+ if test $ac_cv_prog_RANLIB_necessary = no; then
+ RANLIB=:
+ fi
+fi
+])
diff --git a/config-aux/system_extensions.m4 b/config-aux/system_extensions.m4
new file mode 100644
index 0000000..46b2f9e
--- /dev/null
+++ b/config-aux/system_extensions.m4
@@ -0,0 +1,81 @@
+# SYNOPSIS
+#
+# AX_SYS_EXTENSIONS
+#
+# DESCRIPTION
+#
+# Functionally equivalent to the stock AC_USE_SYSTEM_EXTENSIONS, but:
+# does not trigger AC_CHECK_HEADER's backward compatibility mode;
+# does not make use of AC_INCLUDES_DEFAULT;
+# does not define _MINIX.
+#
+# LICENSE
+#
+# Same as Autoconf proper.
+
+# serial 1
+
+# Enable extensions on systems that normally disable them,
+# typically due to standards-conformance issues.
+#
+# Remember that #undef in AH_VERBATIM gets replaced with #define by
+# AC_DEFINE. The goal here is to define all known feature-enabling
+# macros, then, if reports of conflicts are made, disable macros that
+# cause problems on some platforms (such as __EXTENSIONS__).
+AC_DEFUN_ONCE([AX_SYS_EXTENSIONS],
+[AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
+AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
+AC_PROVIDE([AC_USE_SYSTEM_EXTENSIONS])dnl Suppress the stock macro if used.
+
+ AC_CHECK_HEADER([minix/config.h], [MINIX=yes], [MINIX=], [/**/])
+ if test "$MINIX" = yes; then
+ AC_DEFINE([_POSIX_SOURCE], [1],
+ [Define to 1 if you need to in order for `stat' and other
+ things to work.])
+ AC_DEFINE([_POSIX_1_SOURCE], [2],
+ [Define to 2 if the system does not provide POSIX.1 features
+ except with this defined.])
+ fi
+
+dnl Use a different key than __EXTENSIONS__, as that name broke existing
+dnl configure.ac when using autoheader 2.62.
+ AH_VERBATIM([USE_SYSTEM_EXTENSIONS],
+[/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+])
+ AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
+ [ac_cv_safe_to_define___extensions__],
+ [AC_COMPILE_IFELSE(
+ dnl http://lists.gnu.org/archive/html/bug-gnulib/2006-02/msg00002.html
+ dnl implies that testing <stdlib.h> is adequate.
+ [AC_LANG_PROGRAM([[
+# define __EXTENSIONS__ 1
+# include <stdlib.h>
+ ]])],
+ [ac_cv_safe_to_define___extensions__=yes],
+ [ac_cv_safe_to_define___extensions__=no])])
+ test $ac_cv_safe_to_define___extensions__ = yes &&
+ AC_DEFINE([__EXTENSIONS__])
+ AC_DEFINE([_ALL_SOURCE])
+ AC_DEFINE([_GNU_SOURCE])
+ AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
+ AC_DEFINE([_TANDEM_SOURCE])
+])# AX_SYS_EXTENSIONS
diff --git a/config-aux/winsock.m4 b/config-aux/winsock.m4
new file mode 100644
index 0000000..fd3d8b5
--- /dev/null
+++ b/config-aux/winsock.m4
@@ -0,0 +1,56 @@
+# Copyright © 2011 Zack Weinberg <zackw(a)panix.com>
+#
+# Copying and distribution of this software, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved. This software is offered as-is,
+# without any warranty.
+
+# The socket API requires a special library on Windows, but
+# AC_SEARCH_LIBS cannot be used to find it, because it will
+# mis-declare 'ntohl' on windows and cause the link to fail.
+#
+# This macro sets the substitution @ws2_LIBS@ to "-lws2_32"
+# if you need that, and "" otherwise. It does not provide
+# any #defines for the differences in socket headers between
+# Windows and Unix -- just use #ifdef _WIN32.
+#
+# Implementation note: we use the same _cv_ variable that
+# AC_SEARCH_LIBS would, because the test is what AC_SEARCH_LIBS
+# *should* have done in this situation.
+AC_DEFUN([AX_LIB_WINSOCK2],
+ [AC_CACHE_CHECK([for library containing ntohl], [ac_cv_search_ntohl],
+ [AC_LANG_CONFTEST([AC_LANG_PROGRAM([
+ #ifdef _WIN32
+ #include <winsock2.h>
+ #else
+ #include <arpa/inet.h>
+ #endif
+ ], [
+ return (int)ntohl(42);])
+ ])
+
+ ax_lib_winsock2_save_LIBS="$LIBS"
+ for ac_lib in '' -lws2_32; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=$ac_lib
+ fi
+ LIBS="$ac_lib $ax_lib_winsock2_save_LIBS"
+ AC_LINK_IFELSE([], [AS_VAR_SET([ac_cv_search_ntohl], [$ac_res])])
+ AS_VAR_SET_IF([ac_cv_search_ntohl], [break])
+ done
+ AS_VAR_SET_IF([ac_cv_search_ntohl], ,
+ [AS_VAR_SET([ac_cv_search_ntohl], [no])])
+ rm conftest.$ac_ext
+ LIBS="$ax_lib_winsock2_save_LIBS"
+ ])
+
+ ws32_LIBS=
+ case "$ac_cv_search_ntohl" in
+ no) AC_MSG_ERROR([could not find ntohl]) ;;
+ "none required") ;;
+ *) ws32_LIBS="$ac_cv_search_ntohl"
+ esac
+ AC_SUBST(ws32_LIBS)
+])
diff --git a/configure.ac b/configure.ac
index 4c23af6..0c858dc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5,6 +5,7 @@ dnl
AC_PREREQ([2.61])dnl Possibly earlier will do, but this is what I have
AC_INIT([stegotorus], [0.0])
AC_CONFIG_SRCDIR([src/main.cc])
+AC_CONFIG_AUX_DIR([config-aux])
AC_LANG([C++])
AM_INIT_AUTOMAKE([foreign nostdinc silent-rules subdir-objects])
AM_MAINTAINER_MODE([enable])
diff --git a/doc/README.Linda b/doc/README.Linda
new file mode 100644
index 0000000..3cb4d2e
--- /dev/null
+++ b/doc/README.Linda
@@ -0,0 +1,117 @@
+compiling stegotorus on Mac OS X 10.6
+=====================================
+
+0) prelims
+
+Install Mac Ports from http://www.macports.org (here v2.0.3).
+$> sudo port selfupdate [for good measure]
+
+ a) autoconf 2.68
+
+$> sudo port install autoconf
+$> autoconf --version
+autoconf (GNU Autoconf) 2.68
+
+ b) automake 1.11
+
+$> sudo port install automake
+$> automake --version
+automake (GNU automake) 1.11.1
+
+ c) pkgconfig
+
+$> sudo port install pkgconfig
+
+ d) openssl >= 1.0.1, libevent-2
+
+$> sudo port install openssl
+$> sudo port install libevent
+
+ e) tor
+
+$> sudo port install tor
+$> tor --version
+[...]
+Tor version 0.2.2.34 (git-c4eae752f0d157ce).
+
+
+1) StegoTorus
+
+$> cd ~/src/DEFIANCE/stegotorus/sri
+$> autoreconf -i
+$> ./configure --disable-integration-tests --enable-silent-rules
+[...]
+configure: error: Package requirements (libcrypto++ >= 5.6.0) were not met:
+
+No package 'libcrypto++' found
+[...]
+$> sudo cp Desktop/libcrypto++.pc /usr/lib/pkgconfig/
+$> ./configure --disable-integration-tests --enable-silent-rules
+$> make
+
+
+compiling stegotorus under Ubuntu 11.10
+=======================================
+
+$> sudo apt-get install pkg-config libevent-2.0-5 libevent-dev
+
+Tor:
+----
+
+$> sudo cat >> /etc/apt/sources.list <<EOF
+> deb http://deb.torproject.org/torproject.org oneiric main
+> EOF
+$> gpg --keyserver keys.gnupg.net --recv 886DDD89
+$> gpg --export A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89 | sudo apt-key add -
+$> sudo apt-get install tor tor-geoipdb
+$> tor --version
+[É]
+Tor version 0.2.2.35 (git-73ff13ab3cc9570d).
+
+StegoTorus:
+-----------
+
+$> autoreconf -i
+$> ./configure --disable-integration-tests --enable-silent-rules
+[...]
+configure: error: Package requirements (libcrypto++ >= 5.6.0) were not met:
+
+No package 'libcrypto++' found
+[...]
+$> sudo apt-get install libcrypto++9 libcrypto++9-dbg libcrypto++-dev
+$> ./configure --disable-integration-tests --enable-silent-rules
+[...]
+configure: error: Package requirements (zlib >= 1.2.3.4) were not met:
+
+No package 'zlib' found
+[...]
+$> sudo apt-get install zlib1g-dbg zlib1g-dev
+$> ./configure --disable-integration-tests --enable-silent-rules
+[...]
+configure: error: Package requirements (zlib >= 1.2.3.4) were not met:
+
+No package 'zlib' found
+[...]
+$> sudo find /usr -name zlib.pc
+/usr/lib/i386-linux-gnu/pkgconfig/zlib.pc
+$> echo $PKG_CONFIG_PATH
+
+$> export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig
+$> ./configure --disable-integration-tests --enable-silent-rules
+$> make
+
+
+compiling obfsproxy under Ubuntu 10.04 (DETERlab)
+=================================================
+
+create local disk space:
+
+$> sudo /usr/local/etc/emulab/mkextrafs.pl /mnt
+
+copy source code there to compile:
+
+$> sudo mkdir /mnt/local/alice
+$> sudo chown linda:SAF-DEFIANCE /mnt/local/alice
+$> cd /mnt/local/alice
+$> tar -xzvf ~/src/stegotorus.tar.gz
+etc.
diff --git a/m4/cxx_delete_method.m4 b/m4/cxx_delete_method.m4
deleted file mode 100644
index 2d467e7..0000000
--- a/m4/cxx_delete_method.m4
+++ /dev/null
@@ -1,78 +0,0 @@
-# ============================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_cxx_delete_method.m4
-# ============================================================================
-#
-# SYNOPSIS
-#
-# AX_CXX_DELETE_METHOD
-#
-# DESCRIPTION
-#
-# Check whether the C++11 '= delete' syntax, for suppressing undesired
-# implicit methods, is supported. If it is, the macro DELETE_METHOD is
-# defined to '= delete'; otherwise it is defined to nothing. Thus, you
-# can write
-#
-# class foo {
-# ...
-# private:
-# foo(foo const&) DELETE_METHOD;
-# };
-#
-# to delete the 'foo' copy constructor or fall back to the idiom of
-# a private undefined method if the compiler doesn't support this.
-#
-# Does not test '= delete' on a template specialization.
-# Does not ensure that the compiler is in C++11 mode.
-#
-# LICENSE
-#
-# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-AC_DEFUN([AX_CXX_DELETE_METHOD], [dnl
- AC_LANG_ASSERT([C++])
- # This compilation should succeed...
- AC_CACHE_CHECK(whether $CXX accepts method deletion,
- ax_cv_cxx_delete_method_syntax, [
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
- struct foo {
- foo(double);
- foo(int) = delete;
- };
- extern void t(foo const&);
- void tt(double n) { t(n); }
- ]])],
- [ax_cv_cxx_delete_method_syntax=yes],
- [ax_cv_cxx_delete_method_syntax=no])])
- # ... and this one should fail.
- if test x$ax_cv_cxx_delete_method_syntax = xyes; then
- AC_CACHE_CHECK(whether $CXX enforces method deletion,
- ax_cv_cxx_delete_method_enforced, [
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
- struct foo {
- foo(double);
- foo(int) = delete;
- };
- extern void t(foo const&);
- void tt(int n) { t(n); }
- ]])],
- [ax_cv_cxx_delete_method_enforced=no],
- [ax_cv_cxx_delete_method_enforced=yes])])
- fi
- if test x$ax_cv_cxx_delete_method_syntax = xyes &&
- test x$ax_cv_cxx_delete_method_enforced = xyes
- then
- AC_DEFINE([DELETE_METHOD], [= delete],
- [Define as `= delete' if your compiler supports C++11 method
- deletion, as nothing otherwise.])
- else
- AC_DEFINE([DELETE_METHOD], [],
- [Define as `= delete' if your compiler supports C++11 method
- deletion, as nothing otherwise.])
- fi
-])
diff --git a/m4/cxx_static_assert.m4 b/m4/cxx_static_assert.m4
deleted file mode 100644
index 7bf69f8..0000000
--- a/m4/cxx_static_assert.m4
+++ /dev/null
@@ -1,57 +0,0 @@
-# SYNOPSIS
-#
-# AX_CXX_STATIC_ASSERT
-#
-# DESCRIPTION
-#
-# Detect whether the C++ compiler, in its present operating mode,
-# supports the C++11 'static_assert' construct. If it doesn't,
-# define 'static_assert' as a preprocessor macro which provides
-# more-or-less the same functionality.
-#
-# LICENSE
-#
-# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 1
-
-AC_DEFUN([AX_CXX_STATIC_ASSERT], [dnl
- AC_LANG_ASSERT([C++])dnl
- AC_CACHE_CHECK(whether $CXX accepts static_assert, ax_cv_cxx_static_assert,
- [AC_COMPILE_IFELSE([AC_LANG_SOURCE([dnl
- template <typename T>
- struct check
- { static_assert(sizeof(int) <= sizeof(T), "not big enough"); };
- check<int> ok;])],
- [ax_cv_cxx_static_assert=yes], [ax_cv_cxx_static_assert=no])])
- if test x$ax_cv_cxx_static_assert = xyes; then
- AC_CACHE_CHECK(whether $CXX enforces static_assert, ax_cv_cxx_static_assert_e,
- [AC_COMPILE_IFELSE([AC_LANG_SOURCE([dnl
- template <typename T>
- struct check
- { static_assert(sizeof(char[2]) <= sizeof(T), "not big enough"); };
- check<char> bad;])],
- [ax_cv_cxx_static_assert_e=no], [ax_cv_cxx_static_assert_e=yes])])
- fi
- if test x$ax_cv_cxx_static_assert = xyes &&
- test x$ax_cv_cxx_static_assert_e = xyes; then
- AC_DEFINE(HAVE_STATIC_ASSERT, 1,
- [Define to 1 if the C++ compiler supports static_assert.])
- fi
- AH_VERBATIM([HAVE_STATIC_ASSERT_],
-[#ifndef HAVE_STATIC_ASSERT
-# define static_assert(expr, msg) typedef char static_assert_id[(expr)?1:-1]
-# ifdef __COUNTER__
-# define static_assert_id static_assert_paste(static_assert_, __COUNTER__)
-# else
-# define static_assert_id static_assert_paste(static_assert_, __LINE__)
-# endif
-# define static_assert_paste(a,b) static_assert_paste_(a,b)
-# define static_assert_paste_(a,b) a##b
-#endif])
-])
diff --git a/m4/cxxflags_stdcxx_11.m4 b/m4/cxxflags_stdcxx_11.m4
deleted file mode 100644
index 7f06ed2..0000000
--- a/m4/cxxflags_stdcxx_11.m4
+++ /dev/null
@@ -1,102 +0,0 @@
-# ============================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_cxxflags_stdcxx_11.html
-# ============================================================================
-#
-# SYNOPSIS
-#
-# AX_CXXFLAGS_STDCXX_11([ext|noext])
-#
-# DESCRIPTION
-#
-# Check for baseline language coverage in the compiler for the C++11
-# standard; if necessary, add switches to CXXFLAGS to enable support.
-# The argument, if specified, indicates whether you insist on an extended
-# mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. -std=c++11).
-# If neither is specified, you get whatever works, with preference for an
-# extended mode.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Benjamin Kosnik <bkoz(a)redhat.com>
-# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 8
-
-m4_define([_AX_CXXFLAGS_STDCXX_11_testbody], [
- template <typename T>
- struct check
- {
- static_assert(sizeof(int) <= sizeof(T), "not big enough");
- };
-
- typedef check<check<bool>> right_angle_brackets;
-
- int a;
- decltype(a) b;
-
- typedef check<int> check_type;
- check_type c;
- check_type&& cr = static_cast<check_type&&>(c);
-])
-
-AC_DEFUN([AX_CXXFLAGS_STDCXX_11], [dnl
- m4_if([$1], [], [],
- [$1], [ext], [],
- [$1], [noext], [],
- [m4_fatal([invalid argument `$1' to AX_CXXFLAGS_STDCXX_11])])dnl
- AC_LANG_ASSERT([C++])dnl
- ac_success=no
- AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
- ax_cv_cxx_compile_cxx11,
- [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
- [ax_cv_cxx_compile_cxx11=yes],
- [ax_cv_cxx_compile_cxx11=no])])
- if test x$ax_cv_cxx_compile_cxx11 = xyes; then
- ac_success=yes
- fi
-
- m4_if([$1], [noext], [], [dnl
- if test x$ac_success = xno; then
- for switch in -std=gnu++11 -std=gnu++0x; do
- cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
- AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
- $cachevar,
- [ac_save_CXXFLAGS="$CXXFLAGS"
- CXXFLAGS="$CXXFLAGS $switch"
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
- [eval $cachevar=yes],
- [eval $cachevar=no])
- CXXFLAGS="$ac_save_CXXFLAGS"])
- if eval test x\$$cachevar = xyes; then
- CXXFLAGS="$CXXFLAGS $switch"
- ac_success=yes
- break
- fi
- done
- fi])
-
- m4_if([$1], [ext], [], [dnl
- if test x$ac_success = xno; then
- for switch in -std=c++11 -std=c++0x; do
- cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
- AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
- $cachevar,
- [ac_save_CXXFLAGS="$CXXFLAGS"
- CXXFLAGS="$CXXFLAGS $switch"
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
- [eval $cachevar=yes],
- [eval $cachevar=no])
- CXXFLAGS="$ac_save_CXXFLAGS"])
- if eval test x\$$cachevar = xyes; then
- CXXFLAGS="$CXXFLAGS $switch"
- ac_success=yes
- break
- fi
- done
- fi])
-])
diff --git a/m4/maintainer.m4 b/m4/maintainer.m4
deleted file mode 100644
index 07948a7..0000000
--- a/m4/maintainer.m4
+++ /dev/null
@@ -1,39 +0,0 @@
-# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
-# From Jim Meyering
-
-# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2011
-# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# serial 5
-
-# AM_MAINTAINER_MODE([DEFAULT-MODE])
-# ----------------------------------
-# Control maintainer-specific portions of Makefiles.
-# Default is to disable them, unless `enable' is passed literally.
-# For symmetry, `disable' may be passed as well. Anyway, the user
-# can override the default with the --enable/--disable switch.
-AC_DEFUN([AM_MAINTAINER_MODE],
-[m4_case(m4_default([$1], [disable]),
- [enable], [m4_define([am_maintainer_other], [disable])],
- [disable], [m4_define([am_maintainer_other], [enable])],
- [m4_define([am_maintainer_other], [enable])
- m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
-AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
- dnl maintainer-mode's default is 'disable' unless 'enable' is passed
- AC_ARG_ENABLE([maintainer-mode],
-[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
- (and sometimes confusing) to the casual installer],
- [USE_MAINTAINER_MODE=$enableval],
- [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
- AC_MSG_RESULT([$USE_MAINTAINER_MODE])
- AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
- MAINT=$MAINTAINER_MODE_TRUE
- AC_SUBST([MAINT])dnl
-]
-)
-
-AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
diff --git a/m4/pkg.m4 b/m4/pkg.m4
deleted file mode 100644
index 9a71878..0000000
--- a/m4/pkg.m4
+++ /dev/null
@@ -1,159 +0,0 @@
-# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
-# serial 1 (pkg-config-0.24)
-#
-# Copyright © 2004 Scott James Remnant <scott(a)netsplit.com>.
-#
-# 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.
-#
-# 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.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# PKG_PROG_PKG_CONFIG([MIN-VERSION])
-# ----------------------------------
-AC_DEFUN([PKG_PROG_PKG_CONFIG],
-[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
-m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
-m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
-AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
-AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
-AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
-
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
- AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
-fi
-if test -n "$PKG_CONFIG"; then
- _pkg_min_version=m4_default([$1], [0.9.0])
- AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
- if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- PKG_CONFIG=""
- fi
-fi[]dnl
-])# PKG_PROG_PKG_CONFIG
-
-# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-#
-# Check to see whether a particular set of modules exists. Similar
-# to PKG_CHECK_MODULES(), but does not set variables or print errors.
-#
-# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-# only at the first occurence in configure.ac, so if the first place
-# it's called might be skipped (such as if it is within an "if", you
-# have to call PKG_CHECK_EXISTS manually
-# --------------------------------------------------------------
-AC_DEFUN([PKG_CHECK_EXISTS],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-if test -n "$PKG_CONFIG" && \
- AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
- m4_default([$2], [:])
-m4_ifvaln([$3], [else
- $3])dnl
-fi])
-
-# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
-# ---------------------------------------------
-m4_define([_PKG_CONFIG],
-[if test -n "$$1"; then
- pkg_cv_[]$1="$$1"
- elif test -n "$PKG_CONFIG"; then
- PKG_CHECK_EXISTS([$3],
- [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes ],
- [pkg_failed=yes])
- else
- pkg_failed=untried
-fi[]dnl
-])# _PKG_CONFIG
-
-# _PKG_SHORT_ERRORS_SUPPORTED
-# -----------------------------
-AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
- _pkg_short_errors_supported=yes
-else
- _pkg_short_errors_supported=no
-fi[]dnl
-])# _PKG_SHORT_ERRORS_SUPPORTED
-
-
-# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
-# [ACTION-IF-NOT-FOUND])
-#
-#
-# Note that if there is a possibility the first call to
-# PKG_CHECK_MODULES might not happen, you should be sure to include an
-# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
-#
-#
-# --------------------------------------------------------------
-AC_DEFUN([PKG_CHECK_MODULES],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
-AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
-
-pkg_failed=no
-AC_MSG_CHECKING([for $1])
-
-_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
-_PKG_CONFIG([$1][_LIBS], [libs], [$2])
-
-m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
-and $1[]_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.])
-
-if test $pkg_failed = yes; then
- AC_MSG_RESULT([no])
- _PKG_SHORT_ERRORS_SUPPORTED
- if test $_pkg_short_errors_supported = yes; then
- $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
- else
- $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
- fi
- # Put the nasty error message in config.log where it belongs
- echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
-
- m4_default([$4], [AC_MSG_ERROR(
-[Package requirements ($2) were not met:
-
-$$1_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-_PKG_TEXT])[]dnl
- ])
-elif test $pkg_failed = untried; then
- AC_MSG_RESULT([no])
- m4_default([$4], [AC_MSG_FAILURE(
-[The pkg-config script could not be found or is too old. Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-_PKG_TEXT
-
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
- ])
-else
- $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
- $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
- AC_MSG_RESULT([yes])
- $3
-fi[]dnl
-])# PKG_CHECK_MODULES
diff --git a/m4/ranlib.m4 b/m4/ranlib.m4
deleted file mode 100644
index ce4fe33..0000000
--- a/m4/ranlib.m4
+++ /dev/null
@@ -1,69 +0,0 @@
-# SYNOPSIS
-#
-# AX_PROG_RANLIB
-#
-# DESCRIPTION
-#
-# In addition to everything AC_PROG_RANLIB does, determine whether it is
-# _necessary_ to run 'ranlib' after 'ar'. If it is unnecessary (which is
-# the case on most modern systems), reset the RANLIB variable to ':'.
-#
-# LICENSE
-#
-# Same as Autoconf proper.
-
-# serial 1
-
-# 'ranlib' may be needed to make it possible for objects that occur
-# later in an archive library to refer to symbols defined by objects
-# earlier in the archive. Therefore, the testing strategy is to
-# compile three small files where A refers to B refers to C, put C and
-# B in an archive *in that order*, and then see if we can link A
-# against the archive.
-
-AC_DEFUN([AX_PROG_RANLIB],
-[AC_CHECK_TOOL([AR], [ar])
-AC_CHECK_TOOL([RANLIB], [ranlib], [:])
-if test x$RANLIB != x:; then
- AC_CACHE_CHECK([whether ranlib is necessary], [ac_cv_prog_RANLIB_necessary],
- [AC_LANG_PUSH([C])
-
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
- extern int B(void);
- int main(void) { return B(); }
- ]])],
- [cp conftest.$ac_objext conftA.$ac_objext],
- [AC_MSG_ERROR([failed to compile test file A])])
-
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
- extern int C(void);
- int B(void) { return C(); }
- ]])],
- [cp conftest.$ac_objext conftB.$ac_objext],
- [AC_MSG_ERROR([failed to compile test file B])])
-
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
- int C(void) { return 0; }
- ]])],
- [cp conftest.$ac_objext conftC.$ac_objext],
- [AC_MSG_ERROR([failed to compile test file C])])
-
- dnl There is no standard macro for creating an archive.
- _AC_DO([$AR cru conftest.a conftC.$ac_objext conftB.$ac_objext]) ||
- AC_MSG_ERROR([failed to create test archive])
-
- dnl There's no good way to make AC_LINK_IFELSE do what we need.
- AS_IF([_AC_DO([$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
- [ac_cv_prog_RANLIB_necessary=no],
- [AS_IF([_AC_DO([$RANLIB conftest.a && $CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
- [ac_cv_prog_RANLIB_necessary=yes],
- [AC_MSG_ERROR([test link failed with and without ranlib])])])
-
- rm -f conftest$ac_exeext conft[ABC].$ac_objext conftest.a
- AC_LANG_POP([C])
- ])
- if test $ac_cv_prog_RANLIB_necessary = no; then
- RANLIB=:
- fi
-fi
-])
diff --git a/m4/system_extensions.m4 b/m4/system_extensions.m4
deleted file mode 100644
index 46b2f9e..0000000
--- a/m4/system_extensions.m4
+++ /dev/null
@@ -1,81 +0,0 @@
-# SYNOPSIS
-#
-# AX_SYS_EXTENSIONS
-#
-# DESCRIPTION
-#
-# Functionally equivalent to the stock AC_USE_SYSTEM_EXTENSIONS, but:
-# does not trigger AC_CHECK_HEADER's backward compatibility mode;
-# does not make use of AC_INCLUDES_DEFAULT;
-# does not define _MINIX.
-#
-# LICENSE
-#
-# Same as Autoconf proper.
-
-# serial 1
-
-# Enable extensions on systems that normally disable them,
-# typically due to standards-conformance issues.
-#
-# Remember that #undef in AH_VERBATIM gets replaced with #define by
-# AC_DEFINE. The goal here is to define all known feature-enabling
-# macros, then, if reports of conflicts are made, disable macros that
-# cause problems on some platforms (such as __EXTENSIONS__).
-AC_DEFUN_ONCE([AX_SYS_EXTENSIONS],
-[AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
-AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
-AC_PROVIDE([AC_USE_SYSTEM_EXTENSIONS])dnl Suppress the stock macro if used.
-
- AC_CHECK_HEADER([minix/config.h], [MINIX=yes], [MINIX=], [/**/])
- if test "$MINIX" = yes; then
- AC_DEFINE([_POSIX_SOURCE], [1],
- [Define to 1 if you need to in order for `stat' and other
- things to work.])
- AC_DEFINE([_POSIX_1_SOURCE], [2],
- [Define to 2 if the system does not provide POSIX.1 features
- except with this defined.])
- fi
-
-dnl Use a different key than __EXTENSIONS__, as that name broke existing
-dnl configure.ac when using autoheader 2.62.
- AH_VERBATIM([USE_SYSTEM_EXTENSIONS],
-[/* Enable extensions on AIX 3, Interix. */
-#ifndef _ALL_SOURCE
-# undef _ALL_SOURCE
-#endif
-/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# undef _GNU_SOURCE
-#endif
-/* Enable threading extensions on Solaris. */
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# undef _POSIX_PTHREAD_SEMANTICS
-#endif
-/* Enable extensions on HP NonStop. */
-#ifndef _TANDEM_SOURCE
-# undef _TANDEM_SOURCE
-#endif
-/* Enable general extensions on Solaris. */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
-])
- AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
- [ac_cv_safe_to_define___extensions__],
- [AC_COMPILE_IFELSE(
- dnl http://lists.gnu.org/archive/html/bug-gnulib/2006-02/msg00002.html
- dnl implies that testing <stdlib.h> is adequate.
- [AC_LANG_PROGRAM([[
-# define __EXTENSIONS__ 1
-# include <stdlib.h>
- ]])],
- [ac_cv_safe_to_define___extensions__=yes],
- [ac_cv_safe_to_define___extensions__=no])])
- test $ac_cv_safe_to_define___extensions__ = yes &&
- AC_DEFINE([__EXTENSIONS__])
- AC_DEFINE([_ALL_SOURCE])
- AC_DEFINE([_GNU_SOURCE])
- AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
- AC_DEFINE([_TANDEM_SOURCE])
-])# AX_SYS_EXTENSIONS
diff --git a/m4/winsock.m4 b/m4/winsock.m4
deleted file mode 100644
index fd3d8b5..0000000
--- a/m4/winsock.m4
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright © 2011 Zack Weinberg <zackw(a)panix.com>
-#
-# Copying and distribution of this software, with or without modification,
-# are permitted in any medium without royalty provided the copyright
-# notice and this notice are preserved. This software is offered as-is,
-# without any warranty.
-
-# The socket API requires a special library on Windows, but
-# AC_SEARCH_LIBS cannot be used to find it, because it will
-# mis-declare 'ntohl' on windows and cause the link to fail.
-#
-# This macro sets the substitution @ws2_LIBS@ to "-lws2_32"
-# if you need that, and "" otherwise. It does not provide
-# any #defines for the differences in socket headers between
-# Windows and Unix -- just use #ifdef _WIN32.
-#
-# Implementation note: we use the same _cv_ variable that
-# AC_SEARCH_LIBS would, because the test is what AC_SEARCH_LIBS
-# *should* have done in this situation.
-AC_DEFUN([AX_LIB_WINSOCK2],
- [AC_CACHE_CHECK([for library containing ntohl], [ac_cv_search_ntohl],
- [AC_LANG_CONFTEST([AC_LANG_PROGRAM([
- #ifdef _WIN32
- #include <winsock2.h>
- #else
- #include <arpa/inet.h>
- #endif
- ], [
- return (int)ntohl(42);])
- ])
-
- ax_lib_winsock2_save_LIBS="$LIBS"
- for ac_lib in '' -lws2_32; do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=$ac_lib
- fi
- LIBS="$ac_lib $ax_lib_winsock2_save_LIBS"
- AC_LINK_IFELSE([], [AS_VAR_SET([ac_cv_search_ntohl], [$ac_res])])
- AS_VAR_SET_IF([ac_cv_search_ntohl], [break])
- done
- AS_VAR_SET_IF([ac_cv_search_ntohl], ,
- [AS_VAR_SET([ac_cv_search_ntohl], [no])])
- rm conftest.$ac_ext
- LIBS="$ax_lib_winsock2_save_LIBS"
- ])
-
- ws32_LIBS=
- case "$ac_cv_search_ntohl" in
- no) AC_MSG_ERROR([could not find ntohl]) ;;
- "none required") ;;
- *) ws32_LIBS="$ac_cv_search_ntohl"
- esac
- AC_SUBST(ws32_LIBS)
-])
1
0
[stegotorus/master] Add ECDH implementation to crypt.cc/h (no tests yet)
by zwol@torproject.org 20 Jul '12
by zwol@torproject.org 20 Jul '12
20 Jul '12
commit 0775073adf3b2b13748af23516080cdfc3a30ee2
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Tue Jun 5 16:22:10 2012 -0700
Add ECDH implementation to crypt.cc/h (no tests yet)
---
src/crypt.cc | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/crypt.h | 34 +++++++++++++++++
2 files changed, 149 insertions(+), 0 deletions(-)
diff --git a/src/crypt.cc b/src/crypt.cc
index d4af5e0..8c7a6b9 100644
--- a/src/crypt.cc
+++ b/src/crypt.cc
@@ -8,8 +8,10 @@
#include <openssl/engine.h>
#include <openssl/err.h>
+#include <openssl/ecdh.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#include <openssl/objects.h>
static bool crypto_initialized = false;
static bool crypto_errs_initialized = false;
@@ -410,6 +412,107 @@ gcm_decryptor_impl::decrypt(uint8_t *out, const uint8_t *in, size_t inlen,
return 0;
}
+// We use the slightly lower-level EC_* / ECDH_* routines for
+// ecdh_message, instead of the EVP_PKEY_* routines, because we don't
+// need algorithmic agility, and it means we only have to puzzle out
+// one layer of completely undocumented APIs instead of two.
+namespace {
+ struct ecdh_message_impl : ecdh_message
+ {
+ EC_KEY *priv;
+ BN_CTX *ctx;
+ ecdh_message_impl(); // generate keypair from randomness
+
+ virtual ~ecdh_message_impl();
+ virtual void encode(uint8_t *xcoord_out) const;
+ virtual int combine(const uint8_t *other, uint8_t *secret_out) const;
+ };
+}
+
+ecdh_message_impl::ecdh_message_impl()
+ : priv(EC_KEY_new_by_curve_name(NID_secp224r1)),
+ ctx(BN_CTX_new())
+{
+ if (!priv || !ctx)
+ log_crypto_abort("ecdh_message::allocate data");
+ if (!EC_KEY_generate_key(priv))
+ log_crypto_abort("ecdh_message::generate priv");
+}
+
+/* static */ ecdh_message *
+ecdh_message::generate()
+{
+ REQUIRE_INIT_CRYPTO();
+ return new ecdh_message_impl();
+}
+
+ecdh_message::~ecdh_message() {}
+ecdh_message_impl::~ecdh_message_impl()
+{
+ EC_KEY_free(priv);
+ BN_CTX_free(ctx);
+}
+
+void
+ecdh_message_impl::encode(uint8_t *xcoord_out) const
+{
+ const EC_POINT *pub = EC_KEY_get0_public_key(priv);
+ const EC_GROUP *grp = EC_KEY_get0_group(priv);
+ if (!pub || !grp)
+ log_crypto_abort("ecdh_message_encode::extract pubkey");
+
+ BIGNUM *x = BN_new();
+ if (!x)
+ log_crypto_abort("ecdh_message_encode::allocate data");
+
+ if (!EC_POINT_get_affine_coordinates_GFp(grp, pub, x, 0, ctx))
+ log_crypto_abort("ecdh_message_encode::extract x-coordinate");
+
+ size_t sbytes = BN_num_bytes(x);
+ log_assert(sbytes <= EC_P224_LEN);
+ if (sbytes < EC_P224_LEN) {
+ memset(xcoord_out, 0, EC_P224_LEN - sbytes);
+ sbytes += EC_P224_LEN - sbytes;
+ }
+ size_t wbytes = BN_bn2bin(x, xcoord_out);
+ log_assert(sbytes == wbytes);
+
+ BN_free(x);
+}
+
+int
+ecdh_message_impl::combine(const uint8_t *xcoord_other,
+ uint8_t *secret_out) const
+{
+ const EC_GROUP *grp = EC_KEY_get0_group(priv);
+ EC_POINT *pub = EC_POINT_new(grp);
+ if (!grp || !pub)
+ log_crypto_abort("ecdh_message_combine::allocate data");
+
+ int rv = -1;
+ BIGNUM *x = BN_bin2bn(xcoord_other, EC_P224_LEN, 0);
+ if (!x) {
+ log_crypto_warn("ecdh_message_combine::decode their x-coordinate");
+ goto done;
+ }
+
+ if (!EC_POINT_set_compressed_coordinates_GFp(grp, pub, x, 0, ctx)) {
+ log_crypto_warn("ecdh_message_combine::recover their point");
+ goto done;
+ }
+
+ if (!ECDH_compute_key(secret_out, EC_P224_LEN, pub, priv, 0)) {
+ log_crypto_warn("ecdh_message_combine::compute shared secret");
+ goto done;
+ }
+
+ rv = 0;
+ done:
+ BN_free(x);
+ EC_POINT_free(pub);
+ return rv;
+}
+
namespace {
struct key_generator_impl : key_generator
{
@@ -462,6 +565,18 @@ key_generator::from_random_secret(const uint8_t *key, size_t klen,
}
key_generator *
+key_generator::from_ecdh(const ecdh_message *mine, const uint8_t *theirs,
+ const uint8_t *salt, size_t slen,
+ const uint8_t *ctxt, size_t clen)
+{
+ MemBlock ss(EC_P224_LEN);
+ if (mine->combine(theirs, ss))
+ return 0;
+
+ return from_random_secret(ss, EC_P224_LEN, salt, slen, ctxt, clen);
+}
+
+key_generator *
key_generator::from_passphrase(const uint8_t *phra, size_t plen,
const uint8_t *salt, size_t slen,
const uint8_t *ctxt, size_t clen)
diff --git a/src/crypt.h b/src/crypt.h
index 4da3309..35e3e37 100644
--- a/src/crypt.h
+++ b/src/crypt.h
@@ -8,6 +8,7 @@
const size_t AES_BLOCK_LEN = 16;
const size_t GCM_TAG_LEN = 16;
const size_t SHA256_LEN = 32;
+const size_t EC_P224_LEN = 28;
/**
* Initialize cryptography library. Must be called before anything that
@@ -140,6 +141,31 @@ private:
gcm_decryptor& operator=(const gcm_decryptor&) DELETE_METHOD;
};
+/** Encapsulation of an elliptic curve Diffie-Hellman message
+ (we use NIST P-224). */
+struct ecdh_message
+{
+ ecdh_message() {}
+ virtual ~ecdh_message();
+
+ /** Generate a new Diffie-Hellman message from randomness. */
+ static ecdh_message *generate();
+
+ /** Encode a Diffie-Hellman message to the wire format. This
+ produces only the x-coordinate of the chosen curve point.
+ The argument must point to EC_P224_LEN bytes of buffer space. */
+ virtual void encode(uint8_t *xcoord_out) const = 0;
+
+ /** Combine our message with the wire-format message sent by our
+ peer, and produce the raw ECDH shared secret. |xcoord_other|
+ must point to EC_P224_LEN bytes of data, and |secret_out| must
+ point to the same quantity of buffer space. Normally you should
+ use key_generator::from_ecdh instead of calling this
+ directly. */
+ virtual int combine(const uint8_t *xcoord_other, uint8_t *secret_out)
+ const = 0;
+};
+
/** Generate keying material from an initial key of some kind, a salt
value, and a context value, all of which are formally bitstrings.
See http://tools.ietf.org/html/rfc5869 for the requirements on the
@@ -166,6 +192,14 @@ struct key_generator
const uint8_t *salt, size_t slen,
const uint8_t *ctxt, size_t clen);
+ /** Construct a key generator from two (elliptic curve) Diffie-Hellman
+ messages. The salt and context arguments are the same as for
+ from_random_secret. */
+ static key_generator *from_ecdh(const ecdh_message *mine,
+ const uint8_t *theirs,
+ const uint8_t *salt, size_t slen,
+ const uint8_t *ctxt, size_t clen);
+
/** Write LEN bytes of key material to BUF. May be called
repeatedly. Note that HKDF has a hard upper limit on the total
amount of key material it can generate. The return value is
1
0
[stegotorus/master] Use one global BN_CTX rather than allocating one per ECDH object.
by zwol@torproject.org 20 Jul '12
by zwol@torproject.org 20 Jul '12
20 Jul '12
commit 379b9bae47b7671e90cdf9f8cd769630a4e4c4ca
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Thu Jun 7 14:51:22 2012 -0700
Use one global BN_CTX rather than allocating one per ECDH object.
---
src/audit-globals.sh | 1 +
src/crypt.cc | 33 +++++++++++++++++----------------
2 files changed, 18 insertions(+), 16 deletions(-)
diff --git a/src/audit-globals.sh b/src/audit-globals.sh
index 025549f..27cab3a 100644
--- a/src/audit-globals.sh
+++ b/src/audit-globals.sh
@@ -35,6 +35,7 @@ sed '
/^connections last_ckt_serial$/d
/^connections last_conn_serial$/d
/^connections shutting_down$/d
+ /^crypt bctx$/d
/^crypt crypto_initialized$/d
/^crypt crypto_errs_initialized$/d
/^main allow_kq$/d
diff --git a/src/crypt.cc b/src/crypt.cc
index ec59511..1110d0b 100644
--- a/src/crypt.cc
+++ b/src/crypt.cc
@@ -15,6 +15,7 @@
static bool crypto_initialized = false;
static bool crypto_errs_initialized = false;
+static BN_CTX *bctx = 0;
#define REQUIRE_INIT_CRYPTO() \
log_assert(crypto_initialized)
@@ -28,19 +29,23 @@ init_crypto()
CRYPTO_set_mem_functions(xmalloc, xrealloc, free);
ENGINE_load_builtin_engines();
ENGINE_register_all_complete();
+ bctx = BN_CTX_new();
+ if (!bctx)
+ log_crypto_abort("initialization");
- // we don't need to call OpenSSL_add_all_algorithms, since we never
+ // We don't need to call OpenSSL_add_all_algorithms, since we never
// look up ciphers by textual name.
}
void
free_crypto()
{
- // we don't need to call EVP_cleanup, since we never called
- // OpenSSL_add_all_algorithms.
-
- if (crypto_initialized)
+ if (crypto_initialized) {
+ // We don't need to call EVP_cleanup, since we never called
+ // OpenSSL_add_all_algorithms.
+ BN_CTX_free(bctx);
ENGINE_cleanup();
+ }
if (crypto_errs_initialized)
ERR_free_strings();
}
@@ -420,7 +425,6 @@ namespace {
struct ecdh_message_impl : ecdh_message
{
EC_KEY *key;
- BN_CTX *ctx;
ecdh_message_impl();
ecdh_message_impl(const uint8_t *secret);
@@ -433,21 +437,19 @@ namespace {
}
ecdh_message_impl::ecdh_message_impl()
- : key(EC_KEY_new_by_curve_name(NID_secp224r1)),
- ctx(BN_CTX_new())
+ : key(EC_KEY_new_by_curve_name(NID_secp224r1))
{
- if (!key || !ctx)
+ if (!key)
log_crypto_abort("ecdh_message::allocate data");
if (!EC_KEY_generate_key(key))
log_crypto_abort("ecdh_message::generate key");
}
ecdh_message_impl::ecdh_message_impl(const uint8_t *secret)
- : key(EC_KEY_new_by_curve_name(NID_secp224r1)),
- ctx(BN_CTX_new())
+ : key(EC_KEY_new_by_curve_name(NID_secp224r1))
{
BIGNUM *sb = BN_bin2bn(secret, EC_P224_LEN, 0);
- if (!key || !ctx || !sb)
+ if (!key || !sb)
log_crypto_abort("ecdh_message::allocate data");
if (!EC_KEY_set_private_key(key, sb))
@@ -476,7 +478,7 @@ ecdh_message_impl::regen_pubkey()
if (!pub)
return -1;
- if (!EC_POINT_mul(grp, pub, priv, 0, 0, ctx))
+ if (!EC_POINT_mul(grp, pub, priv, 0, 0, bctx))
return -1;
EC_KEY_set_public_key(key, pub);
@@ -510,7 +512,6 @@ ecdh_message::~ecdh_message() {}
ecdh_message_impl::~ecdh_message_impl()
{
EC_KEY_free(key);
- BN_CTX_free(ctx);
}
void
@@ -525,7 +526,7 @@ ecdh_message_impl::encode(uint8_t *xcoord_out) const
if (!x)
log_crypto_abort("ecdh_message_encode::allocate data");
- if (!EC_POINT_get_affine_coordinates_GFp(grp, pub, x, 0, ctx))
+ if (!EC_POINT_get_affine_coordinates_GFp(grp, pub, x, 0, bctx))
log_crypto_abort("ecdh_message_encode::extract x-coordinate");
size_t sbytes = BN_num_bytes(x);
@@ -559,7 +560,7 @@ ecdh_message_impl::combine(const uint8_t *xcoord_other,
goto done;
}
- if (!EC_POINT_set_compressed_coordinates_GFp(grp, pub, x, 0, ctx)) {
+ if (!EC_POINT_set_compressed_coordinates_GFp(grp, pub, x, 0, bctx)) {
log_crypto_warn("ecdh_message_combine::recover their point");
goto done;
}
1
0
[stegotorus/master] Document deliberate non-checks in configure.ac. Add a stub subprocess-windows.c and related build goo.
by zwol@torproject.org 20 Jul '12
by zwol@torproject.org 20 Jul '12
20 Jul '12
commit 0f5123a7c19257e70569dc02534cbc1d9be7bd90
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Tue Jun 5 11:11:20 2012 -0700
Document deliberate non-checks in configure.ac. Add a stub subprocess-windows.c and related build goo.
---
Makefile.am | 7 ++++-
configure.ac | 63 +++++++++++++++++++++++++++++++++++++++++++++
src/subprocess-unix.cc | 5 +--
src/subprocess-windows.cc | 5 +++
4 files changed, 76 insertions(+), 4 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 64d1d33..d01d4f9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -37,11 +37,16 @@ libstegotorus_a_SOURCES = \
src/protocol.cc \
src/rng.cc \
src/socks.cc \
- src/subprocess-unix.cc \
src/steg.cc \
src/util.cc \
$(PROTOCOLS) $(STEGANOGRAPHERS)
+if WINDOWS
+libstegotorus_a_SOURCES += src/subprocess-windows.cc
+else
+libstegotorus_a_SOURCES += src/subprocess-unix.cc
+endif
+
nodist_libstegotorus_a_SOURCES = protolist.cc steglist.cc
stegotorus_SOURCES = \
diff --git a/configure.ac b/configure.ac
index 0c858dc..ab56311 100644
--- a/configure.ac
+++ b/configure.ac
@@ -10,12 +10,75 @@ AC_LANG([C++])
AM_INIT_AUTOMAKE([foreign nostdinc silent-rules subdir-objects])
AM_MAINTAINER_MODE([enable])
+dnl This script deliberately does not check for a bunch of things
+dnl that 'autoscan' thinks we ought to check for. Here is the list,
+dnl with a rationale for each:
+dnl
+dnl Defined by C89, therefore unnecessary to check for nowadays:
+dnl
+dnl AC_CHECK_FUNCS([atexit floor memset strcasecmp strchr strerror
+dnl strrchr strstr strtoul])
+dnl AC_CHECK_HEADERS([limits.h stddef.h stdlib.h string.h])
+dnl AC_CHECK_TYPES([ptrdiff_t])
+dnl AC_TYPE_SIZE_T
+dnl
+dnl We don't make use of the unspecified-behavior corner cases that
+dnl these pin down:
+dnl
+dnl AC_FUNC_MALLOC
+dnl AC_FUNC_REALLOC
+dnl
+dnl Defined by C++ since cfront, therefore unnecessary to check for
+dnl in a C++ program:
+dnl
+dnl AC_C_INLINE
+dnl AC_HEADER_STDBOOL # 'bool', 'true', and 'false', not the header
+dnl
+dnl Defined by Unix98, therefore adequately handled by #ifdef _WIN32
+dnl (FIXME: Windows has not been tested in some time and is likely to
+dnl be broken):
+dnl
+dnl AC_CHECK_HEADERS([fcntl.h unistd.h arpa/inet.h netinet/in.h
+dnl sys/types.h sys/stat.h sys/un.h sys/wait.h])
+dnl AC_CHECK_FUNCS([gettimeofday])
+dnl AC_FUNC_FORK
+dnl AC_TYPE_PID_T
+dnl
+dnl libevent handles for us (FIXME: we probably shouldn't rely on this):
+dnl
+dnl AC_CHECK_HEADERS([stdint.h])
+dnl AC_CHECK_FUNCS([socket])
+dnl AC_TYPE_SSIZE_T
+dnl AC_TYPE_UINT8_T
+dnl AC_TYPE_UINT16_T
+dnl AC_TYPE_UINT32_T
+dnl AC_TYPE_UINT64_T
+dnl
+dnl The fallback is inappropriate for our use case (it would copy
+dnl several enormous files), it is only required for 'make check'
+dnl in an out-of-tree build, and it's slated to go away RSN anyway:
+dnl
+dnl AC_PROG_LN_S
+
### Compiler and language features ###
AC_PROG_CC
AC_PROG_CXX
AC_PROG_CXXCPP
+# Make a conditional for whether we're on Windows or not, so we can
+# select the right version of certain files.
+AC_CACHE_CHECK([for Windows], ac_cv_system_windows,
+ [AC_PREPROC_IFELSE([AC_LANG_SOURCE([[
+ /* _WIN32 is defined for both Win32 and Win64 */
+ #ifndef _WIN32
+ #error "this is not Windows"
+ #endif
+ ]])],
+ [ac_cv_system_windows=yes],
+ [ac_cv_system_windows=no])])
+AM_CONDITIONAL(WINDOWS, test $ac_cv_system_windows = yes)
+
AX_SYS_EXTENSIONS
AC_SYS_LARGEFILE
diff --git a/src/subprocess-unix.cc b/src/subprocess-unix.cc
index 7e4b8a2..7e075d9 100644
--- a/src/subprocess-unix.cc
+++ b/src/subprocess-unix.cc
@@ -6,9 +6,8 @@
* See LICENSE for other credits and copying information.
*/
-// N.B. This file will have to be rewritten more-or-less from scratch
-// for the Windows port. It should be acceptably portable to all Unix
-// implementations still in wide use.
+// This file should be acceptably portable to all Unix implementations
+// still in wide use.
#include "util.h"
#include "subprocess.h"
diff --git a/src/subprocess-windows.cc b/src/subprocess-windows.cc
new file mode 100644
index 0000000..ec21296
--- /dev/null
+++ b/src/subprocess-windows.cc
@@ -0,0 +1,5 @@
+/* Copyright 2012 SRI International
+ * See LICENSE for other credits and copying information.
+ */
+
+#error "Subprocess creation for Windows not yet implemented."
1
0
[stegotorus/master] Import MKEM implementation from moeller-ref and write out the crypt.h interface for it. (Significant pieces of implementation still to do.)
by zwol@torproject.org 20 Jul '12
by zwol@torproject.org 20 Jul '12
20 Jul '12
commit 818813ea2049df733f5e9a9015a1b82dc8ee2dda
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Thu Jun 7 17:17:54 2012 -0700
Import MKEM implementation from moeller-ref and write out the crypt.h interface for it. (Significant pieces of implementation still to do.)
---
Makefile.am | 1 +
src/crypt.h | 144 ++++++++++++++++--
src/mkem.cc | 492 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/mkem.h | 117 ++++++++++++++
4 files changed, 739 insertions(+), 15 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index d01d4f9..d21fdde 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -33,6 +33,7 @@ libstegotorus_a_SOURCES = \
src/compression.cc \
src/connections.cc \
src/crypt.cc \
+ src/mkem.cc \
src/network.cc \
src/protocol.cc \
src/rng.cc \
diff --git a/src/crypt.h b/src/crypt.h
index cc9309a..869107a 100644
--- a/src/crypt.h
+++ b/src/crypt.h
@@ -9,6 +9,7 @@ const size_t AES_BLOCK_LEN = 16;
const size_t GCM_TAG_LEN = 16;
const size_t SHA256_LEN = 32;
const size_t EC_P224_LEN = 28;
+const size_t MKE_MSG_LEN = 21;
/**
* Initialize cryptography library. Must be called before anything that
@@ -41,9 +42,6 @@ struct key_generator;
struct ecb_encryptor
{
- ecb_encryptor() {}
- virtual ~ecb_encryptor();
-
/** Return a new AES/ECB encryption state using 'key' (of length 'keylen')
as the symmetric key. 'keylen' must be 16, 24, or 32 bytes. */
static ecb_encryptor *create(const uint8_t *key, size_t keylen);
@@ -57,6 +55,9 @@ struct ecb_encryptor
write the result to 'out'. */
virtual void encrypt(uint8_t *out, const uint8_t *in) = 0;
+ virtual ~ecb_encryptor();
+protected:
+ ecb_encryptor() {}
private:
ecb_encryptor(const ecb_encryptor&);
ecb_encryptor& operator=(const ecb_encryptor&);
@@ -64,9 +65,6 @@ private:
struct ecb_decryptor
{
- ecb_decryptor() {}
- virtual ~ecb_decryptor();
-
/** Return a new AES/ECB decryption state using 'key' (of length 'keylen')
as the symmetric key. 'keylen' must be 16, 24, or 32 bytes. */
static ecb_decryptor *create(const uint8_t *key, size_t keylen);
@@ -80,6 +78,9 @@ struct ecb_decryptor
write the result to 'out'. */
virtual void decrypt(uint8_t *out, const uint8_t *in) = 0;
+ virtual ~ecb_decryptor();
+protected:
+ ecb_decryptor() {}
private:
ecb_decryptor(const ecb_decryptor&) DELETE_METHOD;
ecb_decryptor& operator=(const ecb_decryptor&) DELETE_METHOD;
@@ -88,9 +89,6 @@ private:
struct gcm_encryptor
{
- gcm_encryptor() {}
- virtual ~gcm_encryptor();
-
/** Return a new AES/GCM encryption state using 'key' (of length 'keylen')
as the symmetric key. 'keylen' must be 16, 24, or 32 bytes. */
static gcm_encryptor *create(const uint8_t *key, size_t keylen);
@@ -108,6 +106,9 @@ struct gcm_encryptor
virtual void encrypt(uint8_t *out, const uint8_t *in, size_t inlen,
const uint8_t *nonce, size_t nlen) = 0;
+ virtual ~gcm_encryptor();
+protected:
+ gcm_encryptor() {}
private:
gcm_encryptor(const gcm_encryptor&);
gcm_encryptor& operator=(const gcm_encryptor&);
@@ -115,9 +116,6 @@ private:
struct gcm_decryptor
{
- gcm_decryptor() {}
- virtual ~gcm_decryptor();
-
/** Return a new AES/GCM decryption state using 'key' (of length 'keylen')
as the symmetric key. 'keylen' must be 16, 24, or 32 bytes. */
static gcm_decryptor *create(const uint8_t *key, size_t keylen);
@@ -136,6 +134,9 @@ struct gcm_decryptor
virtual int decrypt(uint8_t *out, const uint8_t *in, size_t inlen,
const uint8_t *nonce, size_t nlen) = 0;
+ virtual ~gcm_decryptor();
+protected:
+ gcm_decryptor() {}
private:
gcm_decryptor(const gcm_decryptor&) DELETE_METHOD;
gcm_decryptor& operator=(const gcm_decryptor&) DELETE_METHOD;
@@ -145,9 +146,6 @@ private:
(we use NIST P-224). */
struct ecdh_message
{
- ecdh_message() {}
- virtual ~ecdh_message();
-
/** Generate a new Diffie-Hellman message from randomness. */
static ecdh_message *generate();
@@ -170,8 +168,99 @@ struct ecdh_message
directly. */
virtual int combine(const uint8_t *xcoord_other, uint8_t *secret_out)
const = 0;
+
+ virtual ~ecdh_message();
+protected:
+ ecdh_message() {}
+private:
+ ecdh_message(const ecdh_message&) DELETE_METHOD;
+ ecdh_message& operator=(const ecdh_message&) DELETE_METHOD;
+};
+
+/** Moeller key encapsulation generator: takes a public key and a source
+ of weak entropy, produces temporary key material and key encapsulation
+ messages. */
+struct mke_generator
+{
+ /** Return a new encapsulation generator based on the public key
+ 'key', which should be a C string of the form produced by
+ 'mke_decoder::pubkey()', and a key_generator. The object
+ retains references to both arguments, so make sure their
+ lifetimes exceed that of this object. You are encouraged
+ to use key_generator::from_rng() for this. */
+ static mke_generator *create(const char *pubkey, key_generator *gen);
+
+ /** Retrieve the public key. This will be the same pointer as was
+ passed to create(). */
+ virtual const char *pubkey() const;
+
+ /** Retrieve the length of the public key (you could call strlen(),
+ but this may be more efficient). */
+ virtual size_t pklen() const;
+
+ /** Generate temporary key material and an encapsulated key message.
+ This does NOT carry out key derivation; you probably want to use
+ key_generator::from_mke() instead. The 'message' argument must
+ point to at least MKE_MSG_LEN bytes of storage, and the 'secret'
+ argument must point to at least twice that much storage. */
+ virtual int generate(uint8_t *secret, uint8_t *message) const;
+
+ /** Extract the padding from a previously-generated encapsulated key
+ message. Cannot fail. Do not attempt to interpret the byte
+ returned; just pack it somewhere in the data encrypted with the
+ derived key material, so that the receiver can verify it. */
+ virtual uint8_t extract_padding(uint8_t *message) const;
+
+ virtual ~mke_generator();
+protected:
+ mke_generator() {}
+private:
+ mke_generator(const mke_generator&) DELETE_METHOD;
+ mke_generator& operator=(const mke_generator&) DELETE_METHOD;
};
+/** Moeller key encapsulation decoder: creates a keypair when
+ instantiated, can be asked to emit the public key, can decode the
+ counterpart's key encapsulation messages into temporary key material. */
+struct mke_decoder
+{
+ /** Return a new encapsulation decoder. Generates a new keypair
+ from a source of strong entropy. */
+ static mke_decoder *create();
+
+ /** Emit the public key. The return value is a C-string.
+ The storage for this string belongs to the mke_decoder object.
+ Its contents are unspecified, but it uses only the characters
+ ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=,
+ */
+ virtual const char *pubkey() const;
+
+ /** Retrieve the length of the public key (you could call strlen(),
+ but this may be more efficient). */
+ virtual size_t pklen() const;
+
+ /** Decode an encapsulated key message. This does NOT carry out key
+ derivation; you probably want to use key_generator::from_mke()
+ instead. The 'message' argument must point to at least
+ MKE_MSG_LEN bytes of data, and the 'secret' argument must point
+ to at least twice that much storage. */
+ virtual int decode(uint8_t *secret, uint8_t *message) const;
+
+ /** Extract the padding from an encapsulated key message.
+ Cannot fail. Do not attempt to interpret the byte returned;
+ just verify it by comparing it with a byte somewhere in the
+ data encrypted with the derived key material. */
+ virtual uint8_t extract_padding(uint8_t *message) const;
+
+ virtual ~mke_decoder();
+protected:
+ mke_decoder() {}
+private:
+ mke_decoder(const mke_decoder&) DELETE_METHOD;
+ mke_decoder& operator=(const mke_decoder&) DELETE_METHOD;
+};
+
+
/** Generate keying material from an initial key of some kind, a salt
value, and a context value, all of which are formally bitstrings.
See http://tools.ietf.org/html/rfc5869 for the requirements on the
@@ -206,6 +295,31 @@ struct key_generator
const uint8_t *salt, size_t slen,
const uint8_t *ctxt, size_t clen);
+ /** Construct a key generator from a Moeller key generator, and as a
+ side effect, emit the key encapsulation message. Will use the
+ public key for the salt. The 'message_out' argument must point
+ to at least MKE_MSG_LEN bytes of storage. */
+ static key_generator *from_mke(const mke_generator *gen,
+ uint8_t *message_out,
+ const uint8_t *ctxt, size_t clen);
+
+ /** Construct a key generator from a Moeller key decoder and a
+ received key encapsulation message. Will use the public key for
+ the salt. The 'message' argument must point to at least
+ MKE_MSG_LEN bytes of data. */
+ static key_generator *from_mke(const mke_decoder *gen,
+ uint8_t *message,
+ const uint8_t *ctxt, size_t clen);
+
+ /** Construct a key generator from the global random number
+ generator. This should be used in contexts where a great deal
+ of key material may be required but its strength is not terribly
+ important; it reduces the demand on the entropy source. Key
+ generators created by this factory will automatically reseed
+ themselves when they hit the HKDF upper limit. */
+ static key_generator *from_rng(const uint8_t *salt, size_t slen,
+ const uint8_t *ctxt, size_t clen);
+
/** Write LEN bytes of key material to BUF. May be called
repeatedly. Note that HKDF has a hard upper limit on the total
amount of key material it can generate. The return value is
diff --git a/src/mkem.cc b/src/mkem.cc
new file mode 100644
index 0000000..a17558d
--- /dev/null
+++ b/src/mkem.cc
@@ -0,0 +1,492 @@
+/* Copyright 2012 SRI International
+ * Based on the public-domain reference implementation of Moeller 2004
+ * to be found at http://github.com/zackw/moeller-ref/
+ * See LICENSE for other credits and copying information
+ */
+
+#include "util.h"
+#include "crypt.h"
+#include "mkem.h"
+
+#include <openssl/rand.h>
+
+/* Encapsulation of a set of elliptic curve parameters. */
+
+struct mk_curve_params
+{
+ /* generating polynomial, aka reducing polynomial, aka modulus: bignum */
+ const uint8_t *m;
+ size_t L_m;
+
+ /* elliptic curve coefficient 'b': bignum */
+ const uint8_t *b;
+ size_t L_b;
+
+ /* curve group large primes: bignum */
+ const uint8_t *p0;
+ size_t L_p0;
+ const uint8_t *p1;
+ size_t L_p1;
+
+ /* curve group sizes: bignum */
+ const uint8_t *n0;
+ size_t L_n0;
+ const uint8_t *n1;
+ size_t L_n1;
+
+ /* curve group generators: points (SEC1 compressed format) */
+ const uint8_t *g0;
+ size_t L_g0;
+ const uint8_t *g1;
+ size_t L_g1;
+};
+
+/* MK_CURVE_nbits_index constants correspond to particular curves
+ for which this algorithm is defined. Currently there is only one. */
+
+enum MKEMCurve {
+ MK_CURVE_163_0 /* original 163-bit curve from Moeller 2004 */
+};
+
+
+/* All the known curves that can be used with this algorithm are
+ defined by mk_curve_params objects in this array. */
+
+/* work around lack of compound literals in C89 */
+#define S_(c) #c
+#define S(c) S_(\x##c)
+
+/* 21-byte hexadecimal bignum */
+#define N21(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u) \
+ (const uint8_t *)(S(a) S(b) S(c) S(d) S(e) S(f) S(g) \
+ S(h) S(i) S(j) S(k) S(l) S(m) S(n) \
+ S(o) S(p) S(q) S(r) S(s) S(t) S(u)), 21
+
+/* 21+1-byte compressed hexadecimal curve point */
+#define P21(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u) \
+ (const uint8_t *)(S(02) \
+ S(a) S(b) S(c) S(d) S(e) S(f) S(g) \
+ S(h) S(i) S(j) S(k) S(l) S(m) S(n) \
+ S(o) S(p) S(q) S(r) S(s) S(t) S(u)), 22
+
+const mk_curve_params mk_curves[] = {
+/* MK_CURVE_163_0:
+ p0 = 2923003274661805836407371179614143033958162426611, n0 = p0*4
+ p1 = 5846006549323611672814736302501978089331135490587, n1 = p1*2 */
+{
+ N21(08,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,c9), /* m */
+ N21(05,84,6d,0f,da,25,53,61,60,67,11,bf,7a,99,b0,72,2e,2e,c8,f7,6b), /* b */
+
+ N21(02,00,00,00,00,00,00,00,00,00,01,40,a3,f2,a0,c6,ce,d9,ce,ea,f3), /* p0 */
+ N21(03,ff,ff,ff,ff,ff,ff,ff,ff,ff,fd,7e,b8,1a,be,72,62,4c,62,2a,1b), /* p1 */
+
+ N21(08,00,00,00,00,00,00,00,00,00,05,02,8f,ca,83,1b,3b,67,3b,ab,cc), /* n0 */
+ N21(07,ff,ff,ff,ff,ff,ff,ff,ff,ff,fa,fd,70,35,7c,e4,c4,98,c4,54,36), /* n1 */
+
+ P21(00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,01), /* g0 */
+ P21(00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,02) /* g1 */
+},
+
+};
+
+#undef S_
+#undef S
+#undef N21
+#undef P21
+
+#define FAILZ(expr) if ((expr) == 0) goto fail;
+
+MKEMParams::MKEMParams(BN_CTX *ctx)
+ : ctx(ctx),
+ m(0), b(0), a0(0), a1(0), p0(0), p1(0), n0(0), n1(0), maxu(0),
+ c0(0), c1(0), g0(0), g1(0),
+ msgsize(0), pad_bits(0), pad_mask(0), curve_bit(0)
+{
+ const mk_curve_params *p = &mk_curves[MK_CURVE_163_0];
+ size_t bitsize, bytesize, bitcap, k;
+
+ FAILZ(m = BN_bin2bn(p->m, p->L_m, 0));
+ FAILZ(b = BN_bin2bn(p->b, p->L_b, 0));
+ FAILZ(a0 = BN_new()); FAILZ(BN_zero((BIGNUM *)a0));
+ FAILZ(a1 = BN_value_one());
+ FAILZ(p0 = BN_bin2bn(p->p0, p->L_p0, 0));
+ FAILZ(p1 = BN_bin2bn(p->p1, p->L_p1, 0));
+ FAILZ(n0 = BN_bin2bn(p->n0, p->L_n0, 0));
+ FAILZ(n1 = BN_bin2bn(p->n1, p->L_n1, 0));
+
+ FAILZ(c0 = EC_GROUP_new_curve_GF2m(m, a0, b, ctx));
+ FAILZ(c1 = EC_GROUP_new_curve_GF2m(m, a1, b, ctx));
+
+ FAILZ(g0 = EC_POINT_new(c0));
+ FAILZ(EC_POINT_oct2point(c0, (EC_POINT *)g0, p->g0, p->L_g0, ctx));
+ FAILZ(g1 = EC_POINT_new(c1));
+ FAILZ(EC_POINT_oct2point(c1, (EC_POINT *)g1, p->g1, p->L_g1, ctx));
+
+ /* Calculate the upper limit for the random integer U input to
+ MKEM_generate_message_u.
+
+ The paper calls for us to choose between curve 0 and curve 1 with
+ probability proportional to the number of points on that curve, and
+ then choose a random integer in the range 0 < u < n{curve}. The
+ easiest way to do this accurately is to choose a random integer in the
+ range [1, n0 + n1 - 2]. If it is less than n0, MKEM_generate_message_u
+ will use it unmodified with curve 0. If it is greater than or equal
+ to n0, MKEM_generate_message_u will subtract n0-1, leaving a number in
+ the range [1, n1-1], and use that with curve 1. */
+
+ BIGNUM *mu;
+ FAILZ(mu = BN_dup(n0));
+ FAILZ(BN_add(mu, mu, n1));
+ FAILZ(BN_sub(mu, mu, BN_value_one()));
+ FAILZ(BN_sub(mu, mu, BN_value_one()));
+ maxu = mu;
+
+ /* Calculate the maximum size of a message and the padding mask applied
+ to the high byte of each message. See MKEM_generate_message_u for
+ further exposition. */
+ bitsize = EC_GROUP_get_degree(c0);
+ if ((size_t)EC_GROUP_get_degree(c1) != bitsize)
+ goto fail;
+
+ bytesize = (bitsize + 7) / 8;
+ bitcap = bytesize * 8;
+ k = bitcap - bitsize;
+ if (k == 0)
+ goto fail;
+
+ msgsize = bytesize;
+ pad_bits = k - 1;
+ pad_mask = ~((1 << (8 - pad_bits)) - 1);
+ curve_bit = 1 << (8 - k);
+ return;
+
+ fail:
+ log_crypto_abort("MKEMParams constructor");
+}
+
+MKEMParams::~MKEMParams()
+{
+ /* None of the values in an MKEMParams are secret, so don't bother
+ clearing them. */
+
+ /* We do not own 'ctx'. */
+
+ if (m) BN_free((BIGNUM *)m);
+ if (b) BN_free((BIGNUM *)b);
+ if (a0) BN_free((BIGNUM *)a0);
+ /* a1 is the static BN_value_one() constant and should not be freed. */
+ if (p0) BN_free((BIGNUM *)p0);
+ if (p1) BN_free((BIGNUM *)p1);
+ if (n0) BN_free((BIGNUM *)n0);
+ if (n1) BN_free((BIGNUM *)n1);
+ if (maxu) BN_free((BIGNUM *)maxu);
+
+ if (c0) EC_GROUP_free((EC_GROUP *)c1);
+ if (c1) EC_GROUP_free((EC_GROUP *)c1);
+
+ if (g0) EC_POINT_free((EC_POINT *)g0);
+ if (g1) EC_POINT_free((EC_POINT *)g1);
+
+ memset(this, 0, sizeof(*this));
+}
+
+
+MKEM::~MKEM()
+{
+ /* s0 and s1 are secret. p0 and p1 are not secret, but clear them
+ anyway. */
+ if (s0) BN_clear_free((BIGNUM *)s0);
+ if (s1) BN_clear_free((BIGNUM *)s1);
+
+ if (p0) EC_POINT_clear_free((EC_POINT *)p0);
+ if (p1) EC_POINT_clear_free((EC_POINT *)p1);
+
+ memset(this, 0, sizeof(*this));
+}
+
+/* The secret integers s0 and s1 must be in the range 0 < s < n for
+ some n, and must be relatively prime to that n. We know a priori
+ that n is of the form 2**k * p for some small integer k and prime
+ p. Therefore, it suffices to choose a random integer in the range
+ [0, n/2), multiply by two and add one (enforcing oddness), and then
+ reject values which are divisible by p. */
+static BIGNUM *
+random_s(const BIGNUM *n, const BIGNUM *p, BN_CTX *c)
+{
+ BIGNUM h, m, *r;
+
+ BN_init(&h);
+ BN_init(&m);
+ FAILZ(r = BN_new());
+ FAILZ(BN_copy(&h, n));
+ FAILZ(BN_rshift1(&h, &h));
+
+ do {
+ FAILZ(BN_rand_range(r, &h));
+ FAILZ(BN_lshift1(r, r));
+ FAILZ(BN_add(r, r, BN_value_one()));
+ FAILZ(BN_nnmod(&m, r, p, c));
+ } while (BN_is_zero(&m));
+
+ BN_clear(&h);
+ BN_clear(&m);
+ return r;
+
+ fail:
+ BN_clear(&h);
+ BN_clear(&m);
+ if (r) BN_clear_free(r);
+ return 0;
+}
+
+void
+MKEM::load_secret_key()
+{
+ FAILZ(params); FAILZ(s0); FAILZ(s1);
+
+ FAILZ(p0 = EC_POINT_new(params->c0));
+ FAILZ(p1 = EC_POINT_new(params->c1));
+ FAILZ(EC_POINT_mul(params->c0, (EC_POINT *)p0, 0, params->g0, s0,
+ params->ctx));
+ FAILZ(EC_POINT_mul(params->c1, (EC_POINT *)p1, 0, params->g1, s1,
+ params->ctx));
+ return;
+
+ fail:
+ log_crypto_abort("MKEM::MKEM(secret)");
+}
+
+MKEM::MKEM(const MKEMParams *params,
+ const uint8_t *s0v, size_t s0l,
+ const uint8_t *s1v, size_t s1l,
+ const struct MKEMPrivateKeyLoad&)
+ : params(params),
+ s0(BN_bin2bn(s0v, s0l, 0)),
+ s1(BN_bin2bn(s1v, s1l, 0)),
+ p0(0), p1(0)
+{
+ load_secret_key();
+}
+
+MKEM::MKEM(const MKEMParams *params)
+ : params(params),
+ s0(random_s(params->n0, params->p0, params->ctx)),
+ s1(random_s(params->n1, params->p1, params->ctx)),
+ p0(0), p1(0)
+{
+ load_secret_key();
+}
+
+MKEM::MKEM(const MKEMParams *params,
+ const uint8_t *p0v, size_t p0l,
+ const uint8_t *p1v, size_t p1l)
+ : params(params), s0(0), s1(0), p0(0), p1(0)
+{
+ EC_POINT *pp0 = EC_POINT_new(params->c0);
+ EC_POINT *pp1 = EC_POINT_new(params->c1);
+
+ FAILZ(pp0); FAILZ(pp1);
+ FAILZ(EC_POINT_oct2point(params->c0, pp0, p0v, p0l, params->ctx));
+ FAILZ(EC_POINT_oct2point(params->c1, pp1, p1v, p1l, params->ctx));
+
+ p0 = pp0;
+ p1 = pp1;
+ return;
+
+ fail:
+ log_crypto_abort("MKEM::MKEM(public)");
+}
+
+int
+MKEM::export_public_key(uint8_t *p0o, uint8_t *p1o) const
+{
+ size_t vsize = params->msgsize + 1;
+
+ if (EC_POINT_point2oct(params->c0, p0, POINT_CONVERSION_COMPRESSED,
+ p0o, vsize, params->ctx) != vsize ||
+ EC_POINT_point2oct(params->c1, p1, POINT_CONVERSION_COMPRESSED,
+ p1o, vsize, params->ctx) != vsize)
+ return -1;
+ return 0;
+}
+
+/* Write the BIGNUM 'b' to 'to', padded at the high end so that the
+ result occupies _exactly_ 'sz' bytes. If 'b' requires more than
+ 'sz' bytes it is an error. */
+static size_t
+bn2bin_padhi(const BIGNUM *b, uint8_t *to, size_t sz)
+{
+ size_t n = BN_num_bytes(b);
+ if (n > sz)
+ return 0;
+ if (n < sz) {
+ memset(to, 0, sz - n);
+ to += sz - n;
+ }
+ return BN_bn2bin(b, to) + (sz - n);
+}
+
+int
+MKEM::export_secret_key(uint8_t *s0o, uint8_t *s1o) const
+{
+ if (!s0 || !s1) return -1;
+
+ if (bn2bin_padhi(s0, s0o, params->msgsize) != params->msgsize ||
+ bn2bin_padhi(s1, s1o, params->msgsize) != params->msgsize)
+ return -1;
+ return 0;
+}
+
+int
+MKEM::generate(uint8_t *secret, uint8_t *message) const
+{
+ BIGNUM u;
+ uint8_t pad;
+ int rv = -1;
+ BN_init(&u);
+ if (BN_rand_range(&u, params->maxu) &&
+ BN_add(&u, &u, BN_value_one()) &&
+ RAND_bytes(&pad, 1) &&
+ !generate(&u, pad, secret, message))
+ rv = 0;
+
+ BN_clear(&u);
+ return rv;
+}
+
+int
+MKEM::generate(const BIGNUM *uraw, uint8_t pad,
+ uint8_t *secret, uint8_t *message) const
+{
+ BIGNUM u, x, y;
+ int use_curve0 = (BN_cmp(uraw, params->n0) < 0);
+ const EC_GROUP *ca;
+ const EC_POINT *ga;
+ const EC_POINT *pa;
+ EC_POINT *q = 0, *r = 0;
+ size_t mlen = params->msgsize;
+ int rv;
+
+ BN_init(&u);
+ BN_init(&x);
+ BN_init(&y);
+
+ if (use_curve0) {
+ ca = params->c0;
+ ga = params->g0;
+ pa = p0;
+ FAILZ(BN_copy(&u, uraw));
+ } else {
+ ca = params->c1;
+ ga = params->g1;
+ pa = p1;
+ FAILZ(BN_sub(&u, uraw, params->n0));
+ FAILZ(BN_add(&u, &u, BN_value_one()));
+ }
+
+ FAILZ(q = EC_POINT_new(ca));
+ FAILZ(r = EC_POINT_new(ca));
+ FAILZ(EC_POINT_mul(ca, q, 0, ga, &u, params->ctx));
+ FAILZ(EC_POINT_mul(ca, r, 0, pa, &u, params->ctx));
+
+ FAILZ(EC_POINT_get_affine_coordinates_GF2m(ca, q, &x, &y, params->ctx));
+ if (bn2bin_padhi(&x, message, mlen) != mlen)
+ goto fail;
+ if (message[0] & (params->pad_mask|params->curve_bit)) /* see below */
+ goto fail;
+ memcpy(secret, message, mlen);
+
+ FAILZ(EC_POINT_get_affine_coordinates_GF2m(ca, r, &x, &y, params->ctx));
+ if (bn2bin_padhi(&x, secret + mlen, mlen) != mlen)
+ goto fail;
+
+ /* K high bits of the message will be zero. Fill in the high K-1
+ of them with random bits from the pad, and use the lowest bit
+ to identify the curve in use. That bit will have a bias on the
+ order of 2^{-d/2} where d is the bit-degree of the curve; 2^{-81}
+ for the only curve presently implemented. This is acceptably
+ small since an elliptic curve of d bits gives only about d/2 bits
+ of security anyway, and is much better than allowing a timing
+ attack via the recipient having to attempt point decompression
+ twice for curve 1 but only once for curve 0 (or, alternatively,
+ doubling the time required for all decryptions). */
+
+ pad &= params->pad_mask;
+ pad |= (use_curve0 ? 0 : params->curve_bit);
+ message[0] |= pad;
+
+ rv = 0;
+ done:
+ BN_clear(&u);
+ BN_clear(&x);
+ BN_clear(&y);
+ if (q) EC_POINT_clear_free(q);
+ if (r) EC_POINT_clear_free(r);
+ return rv;
+
+ fail:
+ log_crypto_warn("MKEM::generate");
+ memset(message, 0, mlen);
+ memset(secret, 0, mlen * 2);
+ rv = -1;
+ goto done;
+}
+
+int
+MKEM::decode(uint8_t *secret, const uint8_t *message) const
+{
+ int use_curve0 = !(message[0] & params->curve_bit);
+ const EC_GROUP *ca = use_curve0 ? params->c0 : params->c1;
+ const BIGNUM *sa = use_curve0 ? s0 : s1;
+ EC_POINT *q = 0, *r = 0;
+ uint8_t *unpadded = 0;
+ BIGNUM x, y;
+ size_t mlen = params->msgsize;
+ int rv;
+
+ if (!s0 || !s1) /* secret key not available */
+ return -1;
+
+ BN_init(&x);
+ BN_init(&y);
+ FAILZ(q = EC_POINT_new(ca));
+ FAILZ(r = EC_POINT_new(ca));
+ FAILZ(unpadded = (uint8_t *)xmalloc(mlen + 1));
+
+ /* Copy the message, erase the padding bits, and put an 0x02 byte on
+ the front so we can use EC_POINT_oct2point to recover the
+ y-coordinate. */
+ unpadded[0] = 0x02;
+ unpadded[1] = (message[0] & ~(params->pad_mask|params->curve_bit));
+ memcpy(&unpadded[2], &message[1], mlen - 1);
+
+ FAILZ(EC_POINT_oct2point(ca, q, unpadded, mlen + 1,
+ params->ctx));
+ FAILZ(EC_POINT_mul(ca, r, 0, q, sa, params->ctx));
+
+ FAILZ(EC_POINT_get_affine_coordinates_GF2m(ca, q, &x, &y, params->ctx));
+ if (bn2bin_padhi(&x, secret, mlen) != mlen)
+ goto fail;
+
+ FAILZ(EC_POINT_get_affine_coordinates_GF2m(ca, r, &x, &y, params->ctx));
+ if (bn2bin_padhi(&x, secret + mlen, mlen) != mlen)
+ goto fail;
+
+ rv = 0;
+ done:
+ if (unpadded) {
+ memset(unpadded, 0, mlen + 1);
+ free(unpadded);
+ }
+ if (q) EC_POINT_clear_free(q);
+ if (r) EC_POINT_clear_free(r);
+ BN_clear(&x);
+ BN_clear(&y);
+ return rv;
+
+ fail:
+ log_crypto_warn("MKEM::decode");
+ rv = -1;
+ memset(secret, 0, mlen * 2);
+ goto done;
+}
diff --git a/src/mkem.h b/src/mkem.h
new file mode 100644
index 0000000..8e9d6a6
--- /dev/null
+++ b/src/mkem.h
@@ -0,0 +1,117 @@
+/* Copyright 2012 SRI International
+ * Based on the public-domain reference implementation of Moeller 2004
+ * to be found at http://github.com/zackw/moeller-ref/
+ * See LICENSE for other credits and copying information
+ */
+
+#ifndef MKEM_H
+#define MKEM_H
+
+/* NOTE: The APIs defined in this header should not be used directly.
+ Use the crypt.h 'mke_generator' and 'mke_decoder' objects instead. */
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+
+struct MKEMParams
+{
+ BN_CTX *ctx;
+
+ const BIGNUM *m;
+ const BIGNUM *b;
+ const BIGNUM *a0;
+ const BIGNUM *a1;
+ const BIGNUM *p0;
+ const BIGNUM *p1;
+ const BIGNUM *n0;
+ const BIGNUM *n1;
+ const BIGNUM *maxu;
+
+ const EC_GROUP *c0;
+ const EC_GROUP *c1;
+
+ const EC_POINT *g0;
+ const EC_POINT *g1;
+
+ size_t msgsize;
+ unsigned int pad_bits;
+ uint8_t pad_mask;
+ uint8_t curve_bit;
+
+ MKEMParams(BN_CTX *ctx);
+ ~MKEMParams();
+
+private:
+ MKEMParams(const MKEMParams&) DELETE_METHOD;
+ MKEMParams& operator=(const MKEMParams&) DELETE_METHOD;
+};
+
+// needed to distinguish two constructor overloads
+struct MKEMPrivateKeyLoad {};
+const struct MKEMPrivateKeyLoad PRIVATE_KEY = {};
+
+struct MKEM
+{
+ const MKEMParams *params;
+ const BIGNUM *s0;
+ const BIGNUM *s1;
+ const EC_POINT *p0;
+ const EC_POINT *p1;
+
+ ~MKEM();
+
+ /** Generate a brand new keypair from randomness. */
+ MKEM(const MKEMParams *params);
+
+ /** Load a secret key expressed as two integers (s0, s1), and
+ regenerate the public key from it. */
+ MKEM(const MKEMParams *params,
+ const uint8_t *s0, size_t s0l,
+ const uint8_t *s1, size_t s1l,
+ const struct MKEMPrivateKeyLoad&);
+
+ /** Load a public key expressed as two elliptic curve points (p0, p1).
+ Since the secret key is not available, MKEM_export_secret_key and
+ MKEM_decode_message will fail if called on this MKEM. */
+ MKEM(const MKEMParams *params,
+ const uint8_t *p0, size_t p0l,
+ const uint8_t *p1, size_t p1l);
+
+ /** Export the public key as a pair of points. The byte buffers
+ must each point to at least params->msgsize+1 bytes of storage. */
+ int export_public_key(uint8_t *p1, uint8_t *p2) const;
+
+ /** Export the secret key as a pair of integers. The byte buffers
+ must each point to at least params->msgsize bytes of storage. */
+ int export_secret_key(uint8_t *s0, uint8_t *s1) const;
+
+ /** Generate secret material K and encrypted message kk from randomness.
+ This does NOT carry out key derivation; the "secret" output is what
+ the paper describes as $\mathfrak{k} || encode(x_R)$, not KDF of that.
+ The 'message' argument must point to at least params->msgsize
+ bytes of storage, and the 'secret' argument must point to twice
+ that much storage. */
+ int generate(uint8_t *secret, uint8_t *message) const;
+
+ /** Same, but work from a preselected integer 'u', which must be in
+ the closed interval [1, params->maxu], and an extra byte's worth
+ of random bits for padding.
+
+ This is exposed only for the sake of known-answer tests. Use of
+ non-random 'u' or 'pad' invalidates system properties, as does
+ reuse of either value. */
+ int generate(const BIGNUM *u, uint8_t pad,
+ uint8_t *secret, uint8_t *message) const;
+
+ /* Decode an encrypted message. As with MKEM_generate_message, the
+ result is NOT run through a KDF. */
+ int decode(uint8_t *secret, const uint8_t *message) const;
+
+private:
+ void load_secret_key();
+
+ MKEM(const MKEM&) DELETE_METHOD;
+ MKEM& operator=(const MKEM&) DELETE_METHOD;
+};
+
+#endif
1
0
commit 83cd5f99b7e08c064962f985a92e4b47dc2276fd
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Thu Jun 7 13:59:44 2012 -0700
Add unit tests for ECDH.
---
src/crypt.cc | 89 ++++++++--
src/crypt.h | 6 +
src/test/unittest_crypt.cc | 433 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 515 insertions(+), 13 deletions(-)
diff --git a/src/crypt.cc b/src/crypt.cc
index 8c7a6b9..ec59511 100644
--- a/src/crypt.cc
+++ b/src/crypt.cc
@@ -419,45 +419,105 @@ gcm_decryptor_impl::decrypt(uint8_t *out, const uint8_t *in, size_t inlen,
namespace {
struct ecdh_message_impl : ecdh_message
{
- EC_KEY *priv;
+ EC_KEY *key;
BN_CTX *ctx;
- ecdh_message_impl(); // generate keypair from randomness
+ ecdh_message_impl();
+ ecdh_message_impl(const uint8_t *secret);
virtual ~ecdh_message_impl();
virtual void encode(uint8_t *xcoord_out) const;
virtual int combine(const uint8_t *other, uint8_t *secret_out) const;
+
+ int regen_pubkey();
};
}
ecdh_message_impl::ecdh_message_impl()
- : priv(EC_KEY_new_by_curve_name(NID_secp224r1)),
+ : key(EC_KEY_new_by_curve_name(NID_secp224r1)),
ctx(BN_CTX_new())
{
- if (!priv || !ctx)
+ if (!key || !ctx)
log_crypto_abort("ecdh_message::allocate data");
- if (!EC_KEY_generate_key(priv))
- log_crypto_abort("ecdh_message::generate priv");
+ if (!EC_KEY_generate_key(key))
+ log_crypto_abort("ecdh_message::generate key");
}
-/* static */ ecdh_message *
+ecdh_message_impl::ecdh_message_impl(const uint8_t *secret)
+ : key(EC_KEY_new_by_curve_name(NID_secp224r1)),
+ ctx(BN_CTX_new())
+{
+ BIGNUM *sb = BN_bin2bn(secret, EC_P224_LEN, 0);
+ if (!key || !ctx || !sb)
+ log_crypto_abort("ecdh_message::allocate data");
+
+ if (!EC_KEY_set_private_key(key, sb))
+ log_crypto_abort("ecdh_message::set privkey");
+
+ BN_clear_free(sb);
+}
+
+// EC_KEY_set_private_key *does not* regenerate the public key, nor is
+// there any official or unofficial EC_KEY method to do so. So we have
+// to do it by hand. This is separate from the constructor so that it
+// can fail by returning -1 (since we still can't use exceptions).
+// Fortunately this is only for testing.
+int
+ecdh_message_impl::regen_pubkey()
+{
+ const EC_GROUP *grp = EC_KEY_get0_group(key);
+ if (!grp)
+ return -1;
+
+ const BIGNUM *priv = EC_KEY_get0_private_key(key);
+ if (!priv)
+ return -1;
+
+ EC_POINT *pub = EC_POINT_new(grp);
+ if (!pub)
+ return -1;
+
+ if (!EC_POINT_mul(grp, pub, priv, 0, 0, ctx))
+ return -1;
+
+ EC_KEY_set_public_key(key, pub);
+ EC_POINT_clear_free(pub);
+
+ return EC_KEY_check_key(key) ? 0 : -1;
+}
+
+ecdh_message *
ecdh_message::generate()
{
REQUIRE_INIT_CRYPTO();
return new ecdh_message_impl();
}
+ecdh_message *
+ecdh_message::load_secret(const uint8_t *secret)
+{
+ REQUIRE_INIT_CRYPTO();
+ ecdh_message_impl *imp = new ecdh_message_impl(secret);
+
+ if (imp->regen_pubkey()) {
+ log_crypto_warn("regenerate public key");
+ delete imp;
+ return 0;
+ }
+ return imp;
+}
+
ecdh_message::~ecdh_message() {}
ecdh_message_impl::~ecdh_message_impl()
{
- EC_KEY_free(priv);
+ EC_KEY_free(key);
BN_CTX_free(ctx);
}
void
ecdh_message_impl::encode(uint8_t *xcoord_out) const
{
- const EC_POINT *pub = EC_KEY_get0_public_key(priv);
- const EC_GROUP *grp = EC_KEY_get0_group(priv);
+ const EC_POINT *pub = EC_KEY_get0_public_key(key);
+ const EC_GROUP *grp = EC_KEY_get0_group(key);
if (!pub || !grp)
log_crypto_abort("ecdh_message_encode::extract pubkey");
@@ -484,9 +544,12 @@ int
ecdh_message_impl::combine(const uint8_t *xcoord_other,
uint8_t *secret_out) const
{
- const EC_GROUP *grp = EC_KEY_get0_group(priv);
+ const EC_GROUP *grp = EC_KEY_get0_group(key);
+ if (!grp)
+ log_crypto_abort("ecdh_message_combine::retrieve curve group");
+
EC_POINT *pub = EC_POINT_new(grp);
- if (!grp || !pub)
+ if (!pub)
log_crypto_abort("ecdh_message_combine::allocate data");
int rv = -1;
@@ -501,7 +564,7 @@ ecdh_message_impl::combine(const uint8_t *xcoord_other,
goto done;
}
- if (!ECDH_compute_key(secret_out, EC_P224_LEN, pub, priv, 0)) {
+ if (!ECDH_compute_key(secret_out, EC_P224_LEN, pub, key, 0)) {
log_crypto_warn("ecdh_message_combine::compute shared secret");
goto done;
}
diff --git a/src/crypt.h b/src/crypt.h
index 35e3e37..cc9309a 100644
--- a/src/crypt.h
+++ b/src/crypt.h
@@ -151,6 +151,12 @@ struct ecdh_message
/** Generate a new Diffie-Hellman message from randomness. */
static ecdh_message *generate();
+ /** Generate a new Diffie-Hellman message from a specified secret
+ value (in the form of a big-endian byte string, EC_P224_LEN
+ bytes long). This is provided for testing purposes only; it
+ should not be used in normal operation. */
+ static ecdh_message *load_secret(const uint8_t *secret);
+
/** Encode a Diffie-Hellman message to the wire format. This
produces only the x-coordinate of the chosen curve point.
The argument must point to EC_P224_LEN bytes of buffer space. */
diff --git a/src/test/unittest_crypt.cc b/src/test/unittest_crypt.cc
index c411386..f1fed0f 100644
--- a/src/test/unittest_crypt.cc
+++ b/src/test/unittest_crypt.cc
@@ -834,6 +834,437 @@ test_crypt_aesgcm_bad_dec(void *)
end:;
}
+/* ECDH/P224 test vectors from
+ http://csrc.nist.gov/groups/STM/cavp/documents/keymgmt/kastestvectors.zip
+ specifically, the P224 vectors in
+ KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_init.fax */
+
+static void
+test_crypt_ecdh_p224_good(void *)
+{
+ struct testvec
+ {
+ const char *dA;
+ const char *xA;
+ const char *dB;
+ const char *xB;
+ const char *z;
+ };
+ const struct testvec testvecs[] = {
+ { "\x05\x82\x59\xe4\x16\x0b\x78\x3b\x90\xec\x2e\xe9\x3a\xa1"
+ "\xd8\x51\x49\x60\xbe\x5c\x99\x59\xf5\x01\xa1\xe0\xc4\x76",
+ "\xae\x04\xaa\x96\x54\x89\xc3\x21\x29\xed\x86\x70\xa6\x3c"
+ "\xf6\x57\x01\xda\x2f\x4d\xa3\xe7\xb9\x0f\x4d\x08\x70\x55",
+ "\xa4\x08\x18\x43\x0a\x49\x72\xb5\x02\xd2\x3c\xdd\x62\x2a"
+ "\xd7\x3e\xdb\x75\x7f\x52\xa0\xc0\x7c\x85\xdd\x2a\x0d\x48",
+ "\x26\xde\xf8\xd1\x5e\x96\xde\x9a\x19\x50\x26\x01\x85\xce"
+ "\x3e\xe1\x47\x8c\xb5\xb4\xb1\x4a\x42\x37\x90\xf4\x24\xcc",
+ "\xf8\xbe\x1b\x1f\xd0\xa1\x8b\xa5\x52\x19\x10\x39\x58\x77"
+ "\xa5\xf9\x56\xbc\x80\x3a\x56\x8e\x16\xb0\xd6\xac\x13\x11" },
+
+ { "\xd6\x74\xf9\x1b\xf9\xdd\x9b\x99\x8c\x70\xa3\x04\x02\xc2"
+ "\x18\x9b\x04\xfe\xad\xd3\x05\xee\xb3\x4d\x25\x74\x31\xa9",
+ "\xab\x4a\xb8\xee\x1c\x20\x7a\xfe\x55\xbf\x5b\xf8\xc1\xb3"
+ "\x20\x7d\x6e\x6d\xcb\xad\x5b\x67\x83\xb3\x3d\xc1\x42\x6c",
+ "\x84\xf5\x5f\x59\xe4\xe0\xd8\x24\xfa\xda\x3c\x65\xd6\xc6"
+ "\xb4\x13\xa2\x98\x80\x09\x71\x2b\x0e\x05\xdf\x1f\x4a\x76",
+ "\x96\xf6\xd4\xfe\x22\x90\x0c\x0d\xf6\x09\x9c\x19\xa7\x4f"
+ "\x66\xf3\xf1\x56\x16\xeb\x3c\xaf\xb4\x79\xea\x2c\x81\xee",
+ "\xd6\xee\x73\xac\x1d\x8f\x6c\x45\x25\xc3\x55\x96\x44\x53"
+ "\xd6\x1d\xe9\x6b\xdb\x7a\x20\xb0\x62\xfd\x61\xc7\xde\x84" },
+
+ { "\xd1\x99\x4e\xf8\xc1\xab\x97\x77\xc6\x25\x1d\xc0\x3f\xf5"
+ "\xbe\xc8\xf3\xbf\x62\x3e\x06\xd2\x29\xc5\xd6\x15\xc3\x96",
+ "\x5c\x9e\x74\x34\x5b\xd7\xe3\x02\xe1\xf2\xf7\xba\x48\x78"
+ "\xb7\x0c\x05\xf7\x40\x3d\x44\xf2\x6c\xef\x16\xe4\xb1\x21",
+ "\x8e\x17\x32\xa5\x68\xf3\xe1\xb9\x75\x06\x56\x90\x7a\x1d"
+ "\x77\x0b\x83\x2f\xc9\x3c\x42\xfe\xfb\xb5\x69\x6b\x50\x14",
+ "\x5e\x5d\x65\x39\x48\x7a\x45\x0e\x5a\xa0\x67\x98\x68\x6b"
+ "\x81\x6b\x36\xe4\x73\x73\xc9\x3c\xea\x68\xaa\xa4\x6b\x56",
+ "\x0c\x2b\xa0\x69\x10\xa1\xe6\x34\x60\x49\xfd\x6c\x82\x64"
+ "\x5a\xa6\xbe\x55\x71\x41\x09\x04\x8e\x3e\x77\x3c\xbb\x76" },
+
+ { "\xae\x94\x56\x83\x48\x85\xf7\xb3\xc1\x32\xa9\x05\x97\xb5"
+ "\xb1\x5f\x00\x75\x7a\x6b\x01\x08\xc5\x23\x05\x69\x8a\xff",
+ "\x32\xfa\x65\x28\x51\x48\xde\xb2\x25\xef\x7a\x8e\xbb\x59"
+ "\x19\x24\xf4\x21\x12\x66\xc9\x23\x2e\x5e\x56\xfc\x0f\xa7",
+ "\xdc\x56\x0c\x5d\x5a\x65\xd0\x7c\xad\xec\x18\xd0\xfa\xe4"
+ "\xd0\x0a\x27\xb9\x9b\xe6\x25\xf9\xcd\x24\xce\x09\x6f\x60",
+ "\x29\x9f\x28\xfb\xab\xcf\x4a\x4f\x99\x12\x53\x5c\x81\x08"
+ "\xe4\x18\xf0\x36\xf1\xd3\x75\x11\x7e\x87\xe8\x59\x5f\x79",
+ "\x15\x52\x19\xe1\x51\x7d\xa8\x85\x68\xa1\x03\x44\xd8\xa9"
+ "\x27\xdd\x9a\x45\x94\xe6\x4a\x68\x52\xcb\x6d\xa8\x33\x45" },
+
+ { "\x73\x02\x93\xbb\x30\x87\xfb\x88\x2a\xb8\xf2\xf4\x6c\xb1"
+ "\x4a\x51\x2b\x55\x29\xd8\x30\x24\x67\xb5\x92\xb1\xa5\x4b",
+ "\xa7\x40\xfa\x8a\x31\xcc\xd7\xbf\x77\x85\x7f\x24\xed\x2b"
+ "\xfd\x17\xb5\x65\x49\x5e\x75\xbd\x1e\x55\x4b\x6b\xa9\xa5",
+ "\xdb\x37\xa8\x7d\x80\x12\xa0\xcb\xf2\x55\x82\x69\x17\xb3"
+ "\xb9\xa2\x8f\x4a\x51\xdf\x58\x96\x3c\xde\x03\xf4\xa4\x46",
+ "\x3c\xc2\xe8\xbf\xcc\xac\x84\x59\xbd\x4f\x44\xfe\x58\x48"
+ "\xdd\x97\xb6\x7e\xa7\xf3\x78\x72\x2c\xb0\x81\xf9\x9d\x2f",
+ "\xb9\xbd\x07\xcd\x07\x0d\x9f\xcb\x90\x85\xa6\x36\x07\xf8"
+ "\x4a\xa7\x3a\x82\x32\xaf\x33\x28\x34\xd0\x4f\x00\xe3\xd2" },
+
+ { "\x31\x4e\x8e\xb8\xf2\x97\x6f\x2d\xfd\x1b\x3c\xfb\xd6\x9c"
+ "\xf4\xbd\xce\x9f\x1e\x9a\x6e\xe5\x40\x15\x3a\xca\x3c\x2e",
+ "\x24\x03\x1c\x12\xca\xea\xcf\x66\x29\xc8\x78\x36\x61\x65"
+ "\xca\x4f\x76\xf2\x1a\x40\x85\xc0\xbe\x1a\x83\x58\x76\xd7",
+ "\x54\x22\x6d\x6f\x24\x0a\x0e\x6d\x05\x22\x39\xd3\x8f\xf2"
+ "\xff\x18\x55\x7f\xd2\xed\xcd\xe4\xfc\x4f\x85\xf4\x54\x9f",
+ "\xab\x87\xed\xad\x74\x9a\x6c\x2c\xc7\x4a\x92\xb0\x83\x06"
+ "\x6b\x68\xd3\x5c\x2c\x91\x89\x9a\xff\xff\xc3\x22\xb9\x6f",
+ "\x35\x63\x39\x89\x49\xc4\x0a\xa4\x88\x7b\xda\xdb\xf8\x65"
+ "\x49\xbb\x58\xa1\x66\x16\x56\x60\x51\x07\xfb\xc7\x2a\x56" },
+
+ { "\x1f\x04\xc0\xe3\x51\x45\x7f\x27\x2f\xff\xdc\xff\x4f\x81"
+ "\xd7\x38\x56\x51\x6f\x31\x18\x8d\xbf\xec\xcc\xec\x83\x7e",
+ "\x8e\xc7\x5b\x09\xf0\x40\xa6\xb3\x24\x6e\x98\x57\x96\xfb"
+ "\x26\xbe\x66\x20\x08\x29\x1a\x00\xfe\x64\xe8\xff\xb8\xeb",
+ "\x7f\x1d\x7a\xeb\x23\xe8\x23\x01\xc0\x56\x18\x31\x91\x9a"
+ "\x1d\xb8\x69\x06\xb0\x7e\x42\xf9\xa3\x59\x17\x4b\x38\x5d",
+ "\x12\xdb\x42\x99\x03\x52\x81\x59\x17\xee\x7e\x0b\x23\xa7"
+ "\x7d\x5a\x04\xc7\x87\x62\x07\x0e\x6b\xdb\x11\x04\x75\x60",
+ "\xe0\x93\xfe\xde\xff\xff\xc3\xf1\xb9\x01\x9b\x0c\x03\x2f"
+ "\x64\x07\x25\xe6\x54\x4c\x5e\x6f\x1b\x39\x76\xaf\xe9\xfa" },
+
+ { "\x7e\x31\x5c\x03\xd3\xf3\x2d\x62\xa1\xa2\x53\xce\x37\x30"
+ "\x78\x8a\x94\x3d\xe0\x51\x03\xb0\xae\x2d\xf6\x06\x9c\x1e",
+ "\x9b\x3b\x5d\x53\x83\x17\xeb\x4e\x05\xfe\xb6\x40\xe1\xfc"
+ "\x72\x10\x81\xb5\x11\x79\xa5\xba\x46\x83\x94\x6c\x03\x36",
+ "\x88\x39\x5f\xd4\x54\x96\xb7\xb0\x0e\xa6\x18\xfd\xf9\x96"
+ "\x5f\xf9\x27\x28\x44\xf4\xac\xb6\xd4\x48\x3e\x8a\xe5\xa5",
+ "\xd8\xc0\xd0\xe8\x70\x7b\x13\x18\xdc\x24\xd7\xb4\x3d\x1c"
+ "\xce\x32\x9c\x13\xc5\xcc\x49\xca\x96\x16\xe1\x7b\x04\xbf",
+ "\x00\xff\x17\x5c\x7b\x27\x99\x56\xc5\x43\xe7\xfb\x0c\xfd"
+ "\x26\xf8\x8b\x98\xd6\x34\x50\x02\x4b\xbf\x9e\x65\x01\xf4" },
+
+ { "\x29\x1a\x48\x68\xef\x47\x24\x85\x51\x1c\xb3\x81\x86\x83"
+ "\x53\x98\x3e\xa2\xb6\xff\x52\xf4\x1f\x98\x47\xf1\x79\x2c",
+ "\xf3\x86\x89\xd0\xb9\xa3\xa0\x39\x57\x84\x62\xaf\x92\xf5"
+ "\xa9\x28\xea\x23\x4d\x93\xe3\xed\x4c\xb2\x41\x39\xd1\xd0",
+ "\xc1\x6a\xbc\x67\x50\x7f\x0a\xff\xd5\x56\x9d\x90\x12\x98"
+ "\x8d\x8a\xcd\x76\x2c\xa0\x04\x57\x90\xe9\xcb\xac\xf4\x50",
+ "\x7a\x9b\x85\x5b\xef\x01\x0e\xde\xf1\xb4\x85\x64\xb2\x0c"
+ "\xb2\xe4\x06\x68\xe0\xe5\xde\x16\xa2\x55\xf4\x14\x23\x5d",
+ "\xf5\x21\x7a\x73\x8a\xd9\x63\xcd\x0d\xed\xf4\xd6\x18\x5b"
+ "\x19\x0d\x77\x6e\xb8\x5a\x57\x88\xad\x7f\xba\x2e\x8a\x2c" },
+
+ { "\x11\x62\x98\x59\xee\x09\xef\xbe\x60\xdb\x65\x58\xb9\xbd"
+ "\x80\xcc\x9a\x30\x96\xc0\xbc\x9e\x69\x50\xfa\xd9\xa8\x2d",
+ "\x1a\x2f\x4b\x80\x6b\xa2\x34\xc0\x50\xa3\xf7\x50\x52\x99"
+ "\x5a\xb8\x63\x13\xc5\x11\xa8\x41\x2e\xa0\x5f\x32\x03\x8b",
+ "\x48\x72\x4a\x5b\x79\x22\xbd\x20\x4b\xe2\x95\x3d\x47\xa4"
+ "\x5a\xf5\xaa\x9b\x0a\x72\x04\x55\x1f\xe3\x7f\xcb\x91\xa7",
+ "\x8f\x18\x48\xfa\x23\x8e\xf8\x36\xe1\x45\xcd\x32\x72\xf2"
+ "\x51\x4e\x04\x56\xc0\x67\x5c\x43\xe5\x41\x2e\xa2\xaa\x8e",
+ "\x28\xa8\xc7\x03\x0d\x70\x88\x65\xf1\xd4\x6a\xb9\x67\xd0"
+ "\xf6\xdd\x45\x70\x06\x72\xb7\xbf\xaa\x64\xa9\x7a\x01\x23" },
+
+ { "\x17\x4c\x96\xb0\x2a\xba\x8c\xab\x99\xdd\x8c\xbc\xa8\x6b"
+ "\xfa\x8b\x0d\x3f\x4f\x4c\x9a\x8a\x1b\x75\x9d\x53\x6c\x18",
+ "\xf4\x83\xb9\x4b\x60\x26\xae\x11\xab\xed\x33\x90\x68\x16"
+ "\xfb\x63\x0c\x29\x7b\x79\x01\x82\x23\xb6\x3d\x06\xc0\x79",
+ "\x0f\x6e\x7b\x5b\x6c\xad\xe8\xfc\xd9\xb0\x93\x28\x73\xff"
+ "\xab\xdc\x69\x75\x24\x00\x1e\x03\x12\x46\xc9\xbf\x29\x79",
+ "\x98\x84\x39\xbb\xde\xee\x89\x45\x0c\xb2\x0a\x58\xa0\x96"
+ "\x0a\x74\x19\xb6\x17\xa8\xe2\x33\xef\xf5\x8b\x23\xf5\x85",
+ "\xfa\x28\xc6\x51\xeb\xbb\x03\xb3\xd1\xb5\xc7\x32\xbe\x7c"
+ "\xfd\x06\xec\xd6\x68\x5d\xae\x19\xc4\x45\x1e\x30\xd9\x69" },
+
+ { "\x47\xa0\xc4\xf2\x9f\x82\x31\x3f\x37\x6a\x3f\x45\x9a\x52"
+ "\xa8\x15\x9c\x19\x41\xb5\xdd\x51\xa5\xb2\x51\x80\xf4\xda",
+ "\x6d\xb1\x09\xdf\xb3\x13\xb7\x9b\x96\x4b\x03\xad\x15\x92"
+ "\x58\xfe\xdd\xa0\xe3\x2c\xb1\x8d\xef\x87\xa5\xe3\xdd\x6e",
+ "\x18\xc0\x86\x35\x8b\x6b\x26\xf0\xe7\xa8\x24\x23\xd0\xe2"
+ "\xf8\x65\x29\x01\xe4\xba\x16\xd8\x39\x92\x9b\x4a\x59\x77",
+ "\xf7\x00\x7e\xcd\x09\x3d\xe4\x8c\x79\xd6\x1e\x0e\x47\xc5"
+ "\x68\x31\xcf\xc0\x9d\x5a\x66\x7f\x9a\xd3\x95\xef\x4d\x1f",
+ "\xe8\xfa\xd8\xdd\xb1\xde\x6c\x24\x42\x96\x16\x05\xd1\xb7"
+ "\xf6\xe9\xc8\xc6\xa7\x29\x87\xfc\x93\xd7\xa2\xf4\xd9\xf9" },
+
+ { "\x7e\x96\x75\x75\x58\x4f\xb8\x8a\xcf\x3f\xe6\x92\x43\xbe"
+ "\x13\x21\xa3\xea\xa6\x8c\xe1\xe6\x8d\x72\x4c\x8e\x77\xe8",
+ "\xa6\x52\x08\xef\xdc\x22\x8e\x99\x5c\x96\x3e\xf3\x48\xd7"
+ "\x82\x8f\x1d\x6f\x53\x51\x1e\xd1\xe1\xdd\x7e\x99\xdd\xe1",
+ "\xb5\x00\xc1\xa6\x3d\x44\xa9\xec\x42\x81\xed\x2f\x68\x7e"
+ "\xdc\x47\x6e\x0d\x2d\xf3\xb3\x10\x57\x6a\xe8\xaf\x63\x67",
+ "\xfa\x27\x37\xe3\x19\x5d\xa2\x69\xfb\x48\xa3\x8a\x82\x0e"
+ "\x8c\xab\x93\xec\x9f\x90\xc5\x1a\xff\x55\x26\x6f\x4e\x85",
+ "\xc2\x8a\xc6\x40\x02\xa3\x07\xae\xf0\x4b\x85\x11\xbc\x82"
+ "\xc9\xdd\x34\x3a\x2f\x4f\x3f\xc6\xa5\x48\x6c\x6d\xaa\x68" },
+
+ { "\xf5\x69\x65\xa6\x9f\x1e\xac\x36\x55\x5d\x24\x2b\x85\xe7"
+ "\x5c\x1d\x17\xfe\x09\x2a\xb4\xee\xeb\xec\x98\xca\x43\x82",
+ "\xe0\x02\xd5\x9d\xa5\x39\xf1\xe9\x35\xc8\xf4\xfb\xfa\x2c"
+ "\x75\x37\x5d\xcb\xd4\xc9\xbf\xb1\xc4\x56\x5e\xc2\x10\x81",
+ "\x14\xe8\xf5\x8a\x0a\xc5\xf9\xce\xab\xde\xa2\xf1\xb7\x50"
+ "\xba\xf1\x2e\x45\xd5\x59\x65\x7e\xa1\xfa\x9c\xbb\x9f\xe2",
+ "\xbb\x25\xd7\x58\xfd\x4a\x48\xbc\x6c\xf8\xc0\xbc\x70\xd7"
+ "\x9d\x6a\xca\x1a\x6d\xd7\x12\xc3\x61\x56\x69\x27\x90\xe5",
+ "\x7a\x85\x53\x35\x47\x89\xbb\x75\xde\xb3\xed\x7f\x41\xa3"
+ "\x73\xa6\x40\x64\x77\x68\xe2\x4a\x38\x08\x1f\x5a\xea\x89" },
+
+ { "\x31\xf4\x63\x6e\x71\x16\x5a\x78\xc6\x92\x92\xdd\xb8\x58"
+ "\x19\x22\xd1\x5e\x0f\xd4\x2d\x5f\x1a\x24\xbd\x8e\x15\xcd",
+ "\xfa\x03\x95\x8e\x0d\x74\x22\x86\xff\xa6\x64\x01\x7c\x0a"
+ "\x0a\x87\xed\x61\x18\x92\xcb\xdd\xa2\xfd\x44\x48\x2b\x81",
+ "\xbe\xb0\x14\x2b\xbc\x7a\x5f\x91\xcf\x30\x45\xc0\x99\xaf"
+ "\xf8\x8f\x77\xb2\xa0\xc5\x3c\xcc\xe3\x8e\xa1\x88\x54\x01",
+ "\x9f\xe8\x75\xc3\xb1\x35\x33\x9a\xc3\x56\xa6\xbd\xac\xfe"
+ "\x53\x59\xb8\xa0\x92\xac\x5d\xd4\x1c\xe5\xaa\x05\x84\x07",
+ "\x43\x0b\xa3\x5c\x07\x62\xe9\xa0\xd3\xfd\x4b\x3a\x32\x2c"
+ "\x89\x32\x2e\x78\x33\x96\xa4\xee\xb6\x57\x03\xca\xc3\xda" },
+
+ { "\xab\x39\xec\xa9\x01\xf7\x3b\xce\xc0\xc9\x0d\x26\xa4\x36"
+ "\x58\x2d\xb8\x00\x88\x95\xdd\x95\x25\x00\x0c\xdf\x47\x7d",
+ "\x06\x3c\x88\x08\x34\x4b\xdb\xa2\x7f\xa7\xb8\xd1\xd9\x4a"
+ "\x43\xf6\x98\xe8\xb4\x7b\x19\x3d\x85\x60\x12\xa3\x96\xd4",
+ "\xf2\x1c\xb9\x06\xb4\xd7\xaa\xf2\x90\x8a\xa5\xe4\x34\xa6"
+ "\x26\xd5\x98\xf4\x4b\x5a\x5b\x8a\xf2\x90\xae\xef\x78\xe3",
+ "\x94\x0a\xfb\x7d\xba\x27\xcc\x67\x23\xc3\xdd\x08\xc3\x46"
+ "\xb0\xe2\x12\xef\x33\x40\x21\x0e\x0c\x4f\xf7\xc8\x74\x77",
+ "\x51\xc8\x06\x43\xdf\x8c\x8d\x61\x95\xbc\x08\x00\x95\xd9"
+ "\x9a\xb3\x87\xda\x50\x55\x83\xf0\x2f\x19\x2d\x62\x36\x65" },
+
+ { "\xd4\x69\x26\x18\x98\x17\x1d\x69\x5a\xfb\x6e\x04\xd4\xfd"
+ "\x46\xe0\x4b\xce\xfb\xd9\x39\x8a\x63\x34\x43\xd7\x8d\x48",
+ "\x05\xec\x47\xa2\xfd\xf0\x52\x81\xbc\x87\xd0\x85\xbd\xb5"
+ "\xdc\xc8\xa2\xe0\x64\x21\xbd\x69\x85\x5e\xe3\xc3\x05\x26",
+ "\x83\xe3\x71\x1c\xa0\x52\x4b\x51\x70\x2a\xea\x58\xd4\x81"
+ "\x73\x5e\xac\x71\x23\x46\x84\xb2\x5b\x76\x15\xf0\x2d\x3a",
+ "\x6a\x8c\xae\x26\x50\x88\xea\xa2\xba\x02\x32\x1f\x23\x9b"
+ "\xc6\x40\x3f\xc2\x51\xd6\xca\xbe\x84\x71\x58\xa8\xac\x94",
+ "\x1a\xb3\xff\xe4\xf1\xe6\x81\xe4\x69\x60\x30\x0d\x1e\x5b"
+ "\xd6\xde\xb6\x05\x98\x99\xc6\xa5\xee\x6d\xc5\xf4\x95\x75" },
+
+ { "\xc1\x93\x35\xc9\x1b\x13\x1e\xd5\x67\x1e\x26\x5b\x60\x0c"
+ "\x61\xb7\x7a\xde\xd2\x52\x5b\xb5\xa7\xb1\xb6\xeb\xf4\xca",
+ "\x8e\x46\x21\x7c\x96\xd8\xa6\xe1\x6e\x3a\x74\x43\x67\x15"
+ "\xb2\x77\xa7\x29\x5c\xcd\xea\xf2\xa3\x66\x08\x81\xdc\xeb",
+ "\xb1\xc7\x1a\x00\x38\x5d\x90\xbe\x93\x25\xc8\x9c\x0e\xa6"
+ "\xea\xb9\x6c\xdb\x71\x18\x61\x3f\xe8\x46\x0c\x2c\x8b\x2e",
+ "\x77\xa6\x39\xb9\x63\x30\x1c\xbf\x6a\xac\x08\xad\x03\x8b"
+ "\x2e\xbe\x8a\x32\x15\x4c\x8d\x6b\x2b\xe3\x5b\x2a\xfb\xa3",
+ "\xff\x0f\x01\x88\x07\x26\xa4\x5f\xa5\x56\xed\xd4\x8a\x2b"
+ "\x59\x0a\xc9\xa5\x01\x74\x16\x1d\x3e\x52\xab\x73\x7a\x16" },
+
+ { "\xa3\xc0\x62\xa4\xcb\x5e\x40\x7f\x7d\x99\xe8\xf9\xe3\x73"
+ "\x86\xb2\x76\x97\x05\x5d\x87\x39\x28\x25\xc6\xe1\x86\xbf",
+ "\x1f\x98\x95\x87\x82\x4c\xb6\x2c\x03\xa0\x18\xab\xd4\xd3"
+ "\x19\xdc\x2b\x08\x2e\xda\x66\x66\x2b\xfb\x7a\x65\x95\xfe",
+ "\x87\xb3\x39\xb3\xa4\x81\x5d\x51\x4a\xcf\xe8\x7b\xd6\x53"
+ "\xbe\xe1\xcc\xd3\x3a\x1d\xb4\x24\xc9\xea\x3f\x67\x53\xc8",
+ "\xca\xe1\x6b\xc9\x21\xa8\x51\x38\x15\x9d\x62\xd9\x20\xbb"
+ "\x73\x6b\xa4\x4c\x73\x71\x72\x5f\xa9\xc9\x59\xee\x1f\xcc",
+ "\x3a\xde\x1c\x85\x1d\x9a\x58\x39\xa9\xff\x5f\x12\x8b\x8d"
+ "\xa8\x05\x09\x5c\x76\xb7\x7b\x85\xa8\x1b\x68\x2e\x8f\xa7" },
+
+ { "\xcd\x16\xea\xa0\x2c\xed\xaf\x67\x4f\x35\x32\xf4\xe7\xca"
+ "\x73\xe4\x01\xf0\xc4\xf5\xa6\xed\xd9\xa6\xd7\x0e\xec\xf8",
+ "\x9c\xc1\x4d\x9d\x8b\x1b\x9e\xcf\xe2\x96\x08\x45\x0c\x90"
+ "\xbc\x8e\x51\xf3\x7d\x0b\x74\xf9\x99\x61\x7e\xc4\xb3\x74",
+ "\x2c\x97\x35\x91\x60\x17\xbc\xa8\x51\xdd\xb8\x2c\x30\x9a"
+ "\x52\x47\x3e\xd3\xfd\x88\x46\x1f\xed\x66\x81\x42\xb0\x84",
+ "\xe9\xff\x59\x72\xc0\x5e\x4e\x6d\x79\x24\x61\xce\x67\x1b"
+ "\x75\x0d\xf2\x04\xcb\xe0\xa2\x73\x1d\xcc\xd6\x06\x42\xfd",
+ "\xe6\x76\xda\xbe\x28\x25\x7e\x14\x1d\xe3\xff\x7b\xd8\x95"
+ "\xdb\x55\x43\x37\xcf\x56\x71\x48\xe7\x87\x80\x9e\xd0\x3a" },
+
+ { "\x23\x6d\x4c\x9b\x98\xcf\x11\xa3\x79\x61\x04\x5a\xbf\xe3"
+ "\x99\xe4\xa6\xab\xc8\xab\x2a\x7e\xbc\x80\xf8\xc8\x8e\x71",
+ "\x9c\xc7\x3c\x49\x82\x1c\x1c\x10\xb5\xf5\x79\x4f\xa5\xd3"
+ "\xde\x6f\x5e\xbc\x4e\x78\x0e\x47\x68\x92\xfb\xcd\x2f\x22",
+ "\xc0\xa9\xb0\x20\xe5\x79\x9e\x7f\xc6\xea\x7a\x44\x79\xb7"
+ "\x66\x13\x90\x16\x66\x74\x60\xf4\xbf\x01\xfc\x45\x21\xfc",
+ "\x39\x61\xe9\xee\x46\x75\x38\x4a\x76\xec\xf5\x29\x8b\xa0"
+ "\x43\x03\x5e\x27\x44\x38\x4c\xd0\xf9\x84\xc4\xf0\xb3\xe7",
+ "\x08\x6c\xd8\x6d\x1c\xd6\x9e\x86\x60\xb4\xf7\xae\x62\xec"
+ "\x2f\xca\xe4\xd6\x3b\xd6\x7d\x46\x78\x2e\xb2\xa4\xd8\x21" },
+
+ { "\x04\xcd\xb9\x7e\x47\x58\xc8\x32\x85\x33\x6a\xb6\xe5\x85"
+ "\xbc\x51\xd0\xa1\x78\x04\xbc\x02\x81\x90\x25\x83\x95\x8a",
+ "\x38\x75\xd5\xc9\x01\x40\x03\x71\x83\xb7\xa6\x59\xfb\xaf"
+ "\x79\xd0\x1c\x86\x27\xbe\xdb\xc1\x88\xb7\x01\xf5\xf7\xca",
+ "\xd3\xfc\x0f\xd8\x2c\x8a\xf1\x09\x82\x58\xde\x13\xb8\x54"
+ "\x39\xe3\x3c\xf5\xb3\xb7\xe3\x5f\x8a\xdb\xf7\x1f\x7a\x06",
+ "\xc9\xcb\xa6\xd3\x91\x4d\x59\x0b\x51\x0f\xe3\x22\x59\xf6"
+ "\xd1\xe2\x4d\xa1\xa9\x93\xe9\xae\x7c\xb3\x85\xad\x15\x4d",
+ "\x2f\x8e\x72\x0f\xa0\xd8\x0b\xb0\xa0\x67\x20\x23\x22\xa7"
+ "\x07\xe7\xa0\xe7\x2e\xae\xfb\xd0\xd8\x2f\xbb\x58\xb8\x83" },
+
+ { "\x94\x58\xed\x7f\xbf\x97\x86\xe8\xf1\xbc\x56\xea\xfd\x69"
+ "\xc9\xa8\x3b\x73\x07\x41\x98\x0f\xdd\xfc\x30\x76\xaa\xee",
+ "\x24\x66\x17\x73\x35\x0d\x72\x8e\xd2\x95\x48\x48\x2f\xf6"
+ "\x76\xe9\x77\xd6\xa0\x76\xcc\x59\xde\xb7\xe8\x2e\x00\xc0",
+ "\xfd\x5e\x7a\x2c\x5b\xb2\x2f\x43\x7d\x3b\xc6\xf0\xaf\xba"
+ "\xa5\x69\x58\xb6\x29\x5b\x03\x5c\x7e\xd8\x61\xbc\x85\xe3",
+ "\xdf\x81\x0c\xd0\xa3\xca\xf2\x5f\xac\x62\x73\x21\x0a\x18"
+ "\x09\xae\x1d\x69\xf3\xfe\xe0\x88\x7b\xc7\xe0\x2b\xc3\x94",
+ "\xfe\xb0\x44\x61\xae\x77\x2f\x66\x67\x27\x76\xdf\xd9\x11"
+ "\x0d\x11\x32\x31\x2f\x67\x4f\xff\xf3\x79\x93\x9b\xfe\xd4" },
+
+ { "\x29\x2e\xa4\x45\xba\xb6\xd4\xa1\x10\xe9\x39\x0e\x6d\x9e"
+ "\x0a\xcb\xd6\x0f\x19\x91\xa6\x42\xcc\x33\x9d\x0c\xc7\x66",
+ "\x7c\x99\x6a\xbe\xab\x4a\x1a\xbc\x16\x64\x03\xe1\xd5\xbd"
+ "\x77\x84\x75\x25\x6b\xa5\xe5\xce\x39\x36\xd3\x2f\x5f\x41",
+ "\x2c\x74\x9f\x27\x53\x0d\x05\x96\xe1\xf3\xb3\x7d\x1b\xf8"
+ "\xac\x30\x90\xcb\xe6\xcb\xc8\x7d\x6c\x3e\x69\x6f\xb1\xd8",
+ "\xba\x49\x93\x24\xda\x93\x4a\x0c\x1f\x56\xac\x2e\x08\x4c"
+ "\xf6\xca\xc6\xc1\x2b\x91\xe7\xf5\xea\x92\xb9\xcc\xac\xaf",
+ "\x2e\x90\x90\x2a\x26\xab\x5d\x13\xe7\x1b\x4b\x73\xaf\xf4"
+ "\xd0\x82\x32\xce\x06\x6b\x0e\x89\x90\xca\x79\x12\x8d\x80" },
+
+ { 0, 0, 0, 0, 0 }
+ };
+
+ ecdh_message *a, *b;
+ int i, rv;
+ uint8_t obuf[EC_P224_LEN];
+
+ for (i = 0; testvecs[i].dA; i++) {
+ a = ecdh_message::load_secret((const uint8_t *)testvecs[i].dA);
+ tt_int_op(a, !=, 0);
+
+ b = ecdh_message::load_secret((const uint8_t *)testvecs[i].dB);
+ tt_int_op(b, !=, 0);
+
+ a->encode(obuf);
+ tt_mem_op(obuf, ==, testvecs[i].xA, EC_P224_LEN);
+ b->encode(obuf);
+ tt_mem_op(obuf, ==, testvecs[i].xB, EC_P224_LEN);
+
+ rv = a->combine((const uint8_t *)testvecs[i].xB, obuf);
+ tt_int_op(rv, ==, 0);
+ tt_mem_op(obuf, ==, testvecs[i].z, EC_P224_LEN);
+
+ rv = b->combine((const uint8_t *)testvecs[i].xA, obuf);
+ tt_int_op(rv, ==, 0);
+ tt_mem_op(obuf, ==, testvecs[i].z, EC_P224_LEN);
+
+ delete a;
+ delete b;
+ }
+
+ end:;
+}
+
+static void
+test_crypt_ecdh_p224_bad(void *)
+{
+ enum { bad_x = 1, bad_z };
+ struct testvec
+ {
+ const char *dA;
+ const char *xA;
+ const char *dB;
+ const char *xB;
+ const char *z;
+ unsigned int what;
+ };
+ const struct testvec testvecs[] = {
+ { "\x8d\x17\x56\x30\xd4\xf8\x31\xc3\x3c\x47\xd3\x1c\xaf\xdb"
+ "\xd9\xf2\x6f\xd0\xc6\x0d\x82\x4c\x69\x6d\x0f\x50\x2a\xbe",
+ "\xd5\x50\x88\x33\x86\x53\xb4\xd3\x78\x88\xf9\x57\x83\xae"
+ "\x36\x70\xeb\x66\x31\xe9\x3c\x75\x91\xab\x4b\x33\x9b\x75",
+ "\xcd\xc7\x8f\x44\x4a\xf1\xa3\x29\x25\x97\x41\x73\xb4\x26"
+ "\x3d\xc7\x79\x1b\x54\x37\xf6\xd6\xf4\xc5\x4f\xd2\x4a\xb9",
+ "\x72\x8d\x13\x5f\xbe\xdf\x2f\xdd\x31\x16\x6f\xd5\x05\x5a"
+ "\x74\x6d\x2b\xf9\x0f\xde\xf2\xdd\xc1\x65\xea\x99\x9a\xc9",
+ "\xfd\x72\x21\x93\x90\x0d\x35\xf0\x79\x52\x8f\x11\x36\x1d"
+ "\xd2\xa8\x7a\x58\xbe\x6b\x34\xb9\xae\xa2\x18\x97\x5b\x4a",
+ bad_x },
+
+ { "\xf0\x13\x22\xb9\xcb\x1b\x17\xe5\xf5\xa6\x14\xe5\x18\x62"
+ "\xd6\x32\x6f\xe7\x64\x9e\xdd\xd8\xe7\x08\x65\xba\xba\xd0",
+ "\x8d\xf9\x90\x92\xb0\x22\x4b\x70\xc2\x26\x26\x27\x18\xce"
+ "\x9b\x4d\xa4\xfb\xbb\xc1\x7b\xb8\x5e\x21\x1f\xff\xe2\x33",
+ "\xb9\xda\x33\x22\x0c\xf1\x79\xc5\x01\x3e\xe5\x01\x69\x4a"
+ "\x70\xf0\xf2\x29\x4c\xa6\x39\x25\x21\x89\x8f\x7d\x0f\xb1",
+ "\x5f\xd7\xee\x0b\x48\x96\xbd\xc1\x72\x4c\xb5\x92\x3a\xe3"
+ "\xda\x8f\x75\xe8\xd5\x63\xa9\x51\xa7\x7e\xb5\xc4\x87\x5c",
+ "\x84\xc9\xfb\x7a\x82\x7a\x4e\xb7\x18\x00\x2a\x47\x0e\xdd"
+ "\x9e\xf0\xe8\xcd\x33\xf0\xc5\xe7\xe5\x1b\x80\xaa\x59\x4e",
+ bad_x },
+
+ { "\xc1\xf3\x83\x84\x0f\x6c\x39\x1b\xdb\x45\x70\x05\x5e\x54"
+ "\x7e\xc3\x84\x75\x8b\x25\x1c\x9c\x0e\x5e\x2e\x14\x53\x3d",
+ "\x5f\xae\xf4\x8b\xef\x7a\x4d\x4a\x8d\xb3\xd6\x4b\xea\xc1"
+ "\x72\x17\x99\xbb\xf0\x83\xd8\xa3\x70\x7e\x84\x71\xa1\xe2",
+ "\x55\x30\xfc\xf5\x2f\x1a\x02\x00\xd4\x6b\x66\x69\x8a\xa7"
+ "\xb4\x20\x1c\x8d\xee\x1c\x41\xff\x27\x1e\x8f\xac\xc7\x5c",
+ "\x3b\x57\xae\x47\x2d\xb8\x1a\xf0\x20\x0b\x8d\x53\xf9\x1d"
+ "\x5b\x5b\xe6\x13\xe7\xff\xc1\x33\x19\xe9\x14\x8b\xe9\x10",
+ "\xa6\xb3\x02\x59\xa8\x41\x77\x22\x68\xe2\xd4\xe3\x10\xb6"
+ "\x19\x05\xa7\x58\x36\xf9\xf9\x74\x73\x33\x1b\x9d\x62\xd9",
+ bad_z },
+
+ { "\x71\xa4\xc0\xbd\x85\xa9\xfb\x8e\x33\xc5\x4c\xdd\x73\x1f"
+ "\x98\x7c\xb8\xa2\x44\xc5\x2c\x27\x7d\x97\x67\x7e\x4b\x43",
+ "\x30\xd3\x18\xbe\x17\x7b\xa5\xb5\x13\x69\x87\x89\xc6\xfc"
+ "\x4e\x54\xd8\x92\x57\xd2\x62\xdf\x2f\x09\xab\x0d\x21\x16",
+ "\x4f\xf7\x7e\xb6\x4d\x97\xd7\x1c\x12\xb4\x52\x6e\xc6\xde"
+ "\x2e\x5f\x97\xbe\x5f\xcb\x5d\x16\x44\x74\x7a\x5a\x40\x03",
+ "\x32\x14\x21\x90\xe1\xda\xbb\x40\x73\x27\xc4\x4a\xb3\x18"
+ "\x82\x2a\x15\x62\x68\x38\x4c\x86\xc5\x5a\x33\xcc\x8d\x0a",
+ "\x86\x8d\x73\xd8\xca\xce\x1b\x87\xa5\xfe\x16\xcb\xf3\x49"
+ "\x9e\x4a\x69\x85\xef\x6c\xae\xe0\xf0\x92\x46\xb4\xb0\x22",
+ bad_z },
+
+ { 0, 0, 0, 0, 0, 0 }
+ };
+
+ ecdh_message *a, *b;
+ int i, rv;
+ uint8_t obuf[EC_P224_LEN];
+
+ for (i = 0; testvecs[i].dA; i++) {
+ a = ecdh_message::load_secret((const uint8_t *)testvecs[i].dA);
+ tt_int_op(a, !=, 0);
+
+ b = ecdh_message::load_secret((const uint8_t *)testvecs[i].dB);
+ tt_int_op(b, !=, 0);
+
+ a->encode(obuf);
+ if (testvecs[i].what == bad_x) {
+ tt_mem_op(obuf, !=, testvecs[i].xA, EC_P224_LEN);
+ } else {
+ tt_mem_op(obuf, ==, testvecs[i].xA, EC_P224_LEN);
+ }
+
+ b->encode(obuf);
+ tt_mem_op(obuf, ==, testvecs[i].xB, EC_P224_LEN);
+
+ memset(obuf, 0, EC_P224_LEN);
+ rv = a->combine((const uint8_t *)testvecs[i].xB, obuf);
+ tt_int_op(rv, ==, 0);
+ if (testvecs[i].what == bad_z) {
+ tt_mem_op(obuf, !=, testvecs[i].z, EC_P224_LEN);
+ } else {
+ tt_mem_op(obuf, ==, testvecs[i].z, EC_P224_LEN);
+ }
+
+ memset(obuf, 0, EC_P224_LEN);
+ rv = b->combine((const uint8_t *)testvecs[i].xA, obuf);
+ if (testvecs[i].what == bad_x) {
+ tt_int_op(rv, !=, 0);
+ tt_mem_op(obuf, !=, testvecs[i].z, EC_P224_LEN);
+ } else {
+ tt_int_op(rv, ==, 0);
+ if (testvecs[i].what == bad_z) {
+ tt_mem_op(obuf, !=, testvecs[i].z, EC_P224_LEN);
+ } else {
+ tt_mem_op(obuf, ==, testvecs[i].z, EC_P224_LEN);
+ }
+ }
+
+ delete a;
+ delete b;
+ }
+
+ end:;
+}
+
/* HKDF-SHA256 test vectors from http://tools.ietf.org/html/rfc5869 */
static void
test_crypt_hkdf(void *)
@@ -988,6 +1419,8 @@ struct testcase_t crypt_tests[] = {
T(aesgcm_enc),
T(aesgcm_good_dec),
T(aesgcm_bad_dec),
+ T(ecdh_p224_good),
+ T(ecdh_p224_bad),
T(hkdf),
T(rng),
END_OF_TESTCASES
1
0