Test the Mosh crypto layer
This commit is contained in:
committed by
Keith Winstein
parent
d1c4b0a5d7
commit
c354a69ee6
+1
-1
@@ -107,7 +107,7 @@ AS_IF([test x"$with_skalibs" != xno],
|
|||||||
AC_SUBST([STDDJB_LDFLAGS], ["$SKALIBS_LDFLAGS -lstddjb"])])
|
AC_SUBST([STDDJB_LDFLAGS], ["$SKALIBS_LDFLAGS -lstddjb"])])
|
||||||
|
|
||||||
# Checks for header files.
|
# 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([pty.h util.h libutil.h])
|
||||||
AC_CHECK_HEADERS([endian.h sys/endian.h])
|
AC_CHECK_HEADERS([endian.h sys/endian.h])
|
||||||
|
|||||||
@@ -78,6 +78,12 @@ class PRNG {
|
|||||||
fill( &x, 4 );
|
fill( &x, 4 );
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t uint64() {
|
||||||
|
uint64_t x;
|
||||||
|
fill( &x, 8 );
|
||||||
|
return x;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
/ocb-aes
|
/ocb-aes
|
||||||
|
/encrypt-decrypt
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
AM_CXXFLAGS = $(WARNING_CXXFLAGS) $(PICKY_CXXFLAGS) -fno-default-inline -pipe
|
AM_CXXFLAGS = $(WARNING_CXXFLAGS) $(PICKY_CXXFLAGS) -fno-default-inline -pipe
|
||||||
|
|
||||||
if BUILD_TESTS
|
if BUILD_TESTS
|
||||||
noinst_PROGRAMS = ocb-aes
|
noinst_PROGRAMS = ocb-aes encrypt-decrypt
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ocb_aes_SOURCES = ocb-aes.cc test_utils.cc
|
ocb_aes_SOURCES = ocb-aes.cc test_utils.cc
|
||||||
ocb_aes_CPPFLAGS = -I$(srcdir)/../crypto -I$(srcdir)/../util
|
ocb_aes_CPPFLAGS = -I$(srcdir)/../crypto -I$(srcdir)/../util
|
||||||
ocb_aes_LDADD = ../crypto/libmoshcrypto.a ../util/libmoshutil.a
|
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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -32,3 +32,7 @@ void hexdump( const void *buf, size_t len, const char *name ) {
|
|||||||
void hexdump( const Crypto::AlignedBuffer &buf, const char *name ) {
|
void hexdump( const Crypto::AlignedBuffer &buf, const char *name ) {
|
||||||
hexdump( buf.data(), buf.len(), name );
|
hexdump( buf.data(), buf.len(), name );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hexdump( const std::string &buf, const char *name ) {
|
||||||
|
hexdump( buf.data(), buf.size(), name );
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,11 +19,14 @@
|
|||||||
#ifndef TEST_UTILS_HPP
|
#ifndef TEST_UTILS_HPP
|
||||||
#define TEST_UTILS_HPP
|
#define TEST_UTILS_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
|
|
||||||
#define DUMP_NAME_FMT "%-10s "
|
#define DUMP_NAME_FMT "%-10s "
|
||||||
|
|
||||||
void hexdump( const void *buf, size_t len, const char *name );
|
void hexdump( const void *buf, size_t len, const char *name );
|
||||||
void hexdump( const Crypto::AlignedBuffer &buf, const char *name );
|
void hexdump( const Crypto::AlignedBuffer &buf, const char *name );
|
||||||
|
void hexdump( const std::string &buf, const char *name );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user