diff options
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/crypto/prng.h | 6 | ||||
-rw-r--r-- | src/tests/.gitignore | 1 | ||||
-rw-r--r-- | src/tests/Makefile.am | 6 | ||||
-rw-r--r-- | src/tests/encrypt-decrypt.cc | 139 | ||||
-rw-r--r-- | src/tests/test_utils.cc | 4 | ||||
-rw-r--r-- | src/tests/test_utils.h | 3 |
7 files changed, 159 insertions, 2 deletions
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 <http://www.gnu.org/licenses/>. +*/ + +/* 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 <stdio.h> + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#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<MESSAGES_PER_SESSION; i++ ) { + Nonce nonce( nonce_int ); + fatal_assert( nonce.val() == nonce_int ); + + std::string plaintext = random_payload(); + if ( verbose ) { + printf( DUMP_NAME_FMT NONCE_FMT "\n", "nonce", nonce_int ); + hexdump( plaintext, "pt" ); + } + + std::string ciphertext = encryption_session.encrypt( Message( nonce, plaintext ) ); + if ( verbose ) { + hexdump( ciphertext, "ct" ); + } + + Message decrypted = decryption_session.decrypt( ciphertext ); + if ( verbose ) { + printf( DUMP_NAME_FMT NONCE_FMT "\n", "dec nonce", decrypted.nonce.val() ); + hexdump( decrypted.text, "dec pt" ); + } + + fatal_assert( decrypted.nonce.val() == nonce_int ); + fatal_assert( decrypted.text == plaintext ); + + nonce_int++; + + if ( ! ( prng.uint8() % 16 ) ) { + test_bad_decrypt( decryption_session ); + } + + if ( verbose ) { + printf( "\n" ); + } + } +} + +int main( int argc, char *argv[] ) { + if ( ( argc >= 2 ) && !strcmp( argv[ 1 ], "-q" ) ) { + verbose = false; + } + + for ( size_t i=0; i<NUM_SESSIONS; i++ ) { + try { + test_one_session(); + } catch ( CryptoException e ) { + fprintf( stderr, "Crypto exception: %s\r\n", + e.text.c_str() ); + fatal_assert( false ); + } + } + + return 0; +} diff --git a/src/tests/test_utils.cc b/src/tests/test_utils.cc index 8656532..3d16e71 100644 --- a/src/tests/test_utils.cc +++ b/src/tests/test_utils.cc @@ -32,3 +32,7 @@ void hexdump( const void *buf, size_t len, const char *name ) { void hexdump( const Crypto::AlignedBuffer &buf, const char *name ) { hexdump( buf.data(), buf.len(), name ); } + +void hexdump( const std::string &buf, const char *name ) { + hexdump( buf.data(), buf.size(), name ); +} diff --git a/src/tests/test_utils.h b/src/tests/test_utils.h index b32fcd5..9711d4a 100644 --- a/src/tests/test_utils.h +++ b/src/tests/test_utils.h @@ -19,11 +19,14 @@ #ifndef TEST_UTILS_HPP #define TEST_UTILS_HPP +#include <string> + #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 |