Test the Mosh crypto layer
This commit is contained in:
committed by
Keith Winstein
parent
d1c4b0a5d7
commit
c354a69ee6
@@ -1 +1,2 @@
|
||||
/ocb-aes
|
||||
/encrypt-decrypt
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ) {
|
||||
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
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user