diff --git a/configure.ac b/configure.ac index b05a707..a55803b 100644 --- a/configure.ac +++ b/configure.ac @@ -107,7 +107,7 @@ AS_IF([test x"$with_skalibs" != xno], AC_SUBST([STDDJB_LDFLAGS], ["$SKALIBS_LDFLAGS -lstddjb"])]) # Checks for header files. -AC_CHECK_HEADERS([arpa/inet.h curses.h fcntl.h langinfo.h limits.h locale.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/resource.h sys/socket.h sys/time.h term.h termios.h unistd.h wchar.h wctype.h], [], [AC_MSG_ERROR([Missing required header file.])]) +AC_CHECK_HEADERS([arpa/inet.h curses.h fcntl.h langinfo.h limits.h locale.h netinet/in.h stddef.h stdint.h inttypes.h stdlib.h string.h sys/ioctl.h sys/resource.h sys/socket.h sys/time.h term.h termios.h unistd.h wchar.h wctype.h], [], [AC_MSG_ERROR([Missing required header file.])]) AC_CHECK_HEADERS([pty.h util.h libutil.h]) AC_CHECK_HEADERS([endian.h sys/endian.h]) diff --git a/src/crypto/prng.h b/src/crypto/prng.h index ef435bd..2f0287c 100644 --- a/src/crypto/prng.h +++ b/src/crypto/prng.h @@ -78,6 +78,12 @@ class PRNG { fill( &x, 4 ); return x; } + + uint64_t uint64() { + uint64_t x; + fill( &x, 8 ); + return x; + } }; #endif diff --git a/src/tests/.gitignore b/src/tests/.gitignore index c24b293..0d56ed6 100644 --- a/src/tests/.gitignore +++ b/src/tests/.gitignore @@ -1 +1,2 @@ /ocb-aes +/encrypt-decrypt diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 8489aa6..6108f05 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -1,9 +1,13 @@ AM_CXXFLAGS = $(WARNING_CXXFLAGS) $(PICKY_CXXFLAGS) -fno-default-inline -pipe if BUILD_TESTS - noinst_PROGRAMS = ocb-aes + noinst_PROGRAMS = ocb-aes encrypt-decrypt endif ocb_aes_SOURCES = ocb-aes.cc test_utils.cc ocb_aes_CPPFLAGS = -I$(srcdir)/../crypto -I$(srcdir)/../util ocb_aes_LDADD = ../crypto/libmoshcrypto.a ../util/libmoshutil.a + +encrypt_decrypt_SOURCES = encrypt-decrypt.cc test_utils.cc +encrypt_decrypt_CPPFLAGS = -I$(srcdir)/../crypto -I$(srcdir)/../util +encrypt_decrypt_LDADD = ../crypto/libmoshcrypto.a ../util/libmoshutil.a diff --git a/src/tests/encrypt-decrypt.cc b/src/tests/encrypt-decrypt.cc new file mode 100644 index 0000000..196ad95 --- /dev/null +++ b/src/tests/encrypt-decrypt.cc @@ -0,0 +1,139 @@ +/* + Mosh: the mobile shell + Copyright 2012 Keith Winstein + + 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 3 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, see . +*/ + +/* Tests the Mosh crypto layer by encrypting and decrypting a bunch of random + messages, interspersed with some random bad ciphertexts which we need to + reject. */ + +#include + +#define __STDC_FORMAT_MACROS +#include + +#include "crypto.h" +#include "prng.h" +#include "fatal_assert.h" +#include "test_utils.h" + +using namespace Crypto; + +PRNG prng; + +const size_t MESSAGE_SIZE_MAX = 4096; +const size_t MESSAGES_PER_SESSION = 256; +const size_t NUM_SESSIONS = 64; + +bool verbose = true; + +#define NONCE_FMT "%016"PRIx64 + +std::string random_payload( void ) { + const size_t len = prng.uint32() % MESSAGE_SIZE_MAX; + char *buf = new char[len]; + prng.fill( buf, len ); + + std::string payload( buf, len ); + delete [] buf; + return payload; +} + +void test_bad_decrypt( Session &decryption_session ) { + std::string bad_ct = random_payload(); + + bool got_exn = false; + try { + decryption_session.decrypt( bad_ct ); + } catch ( CryptoException e ) { + got_exn = true; + + /* The "bad decrypt" exception needs to be non-fatal, otherwise we are + vulnerable to an easy DoS. */ + fatal_assert( ! e.fatal ); + } + + if ( verbose ) { + hexdump( bad_ct, "bad ct" ); + } + fatal_assert( got_exn ); +} + +/* Generate a single key and initial nonce, then perform some encryptions. */ +void test_one_session( void ) { + Base64Key key; + Session encryption_session( key ); + Session decryption_session( key ); + + uint64_t nonce_int = prng.uint64(); + + if ( verbose ) { + hexdump( key.data(), 16, "key" ); + } + + for ( size_t i=0; i= 2 ) && !strcmp( argv[ 1 ], "-q" ) ) { + verbose = false; + } + + for ( size_t i=0; i + #include "crypto.h" #define DUMP_NAME_FMT "%-10s " void hexdump( const void *buf, size_t len, const char *name ); void hexdump( const Crypto::AlignedBuffer &buf, const char *name ); +void hexdump( const std::string &buf, const char *name ); #endif