#define _POSIX_C_SOURCE 200809L /* V této úloze si naprogramujeme jednoduchou techniku * z kryptografie známou jako „one-time pad.“ * * Podprogramu ‹otp› jsou předány dva vstupní a jeden výstupní * popisovač souborů. Jeho úkolem je na výstupní popisovač zapsat: * * obsah prvního souboru ‹bitwise xor› obsah druhého souboru * * «Druhý» soubor zde považujeme za klíč a pro bezpečnost této * kryptografické techniky je nezbytné, aby jeho délka byla * «alespoň» taková jako je délka prvního. * * V případě, že tento požadavek není splněn, funkce nechť vrátí -1. * Jestliže nastane systémová chyba (např. problém ve čtení * některého souboru), vraťte -2. Pokud je vše úspěšné, vraťte 0. * * Doporučení: při testování se může hodit příkaz ‹od -t x1› na * prohlížení zapsaných bajtů do souboru (případně ‹od -t x1 -t c›, * pokud zároveň chceme zobrazit ASCII znaky). */ int otp( int fd_file, int fd_key, int out ); /* ┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄┄┄┄ následují testy ┄┄┄┄┄┄┄┄┄┄ %< ┄┄┄┄┄┄┄ */ #include /* assert */ #include /* err, warn */ #include /* errno, EBADF, ENOENT */ #include /* open */ #include /* open */ #include /* unlink */ #include /* memcmp */ #include /* close, read, unlink, write */ static void unlink_if_exists( const char *name ) { if ( unlink( name ) == -1 && errno != ENOENT ) err( 2, "unlinking %s", name ); } static void close_or_warn( int fd, const char *name ) { if ( close( fd ) == -1 ) warn( "closing %s", name ); } static int open_or_die( const char *name ) { int fd = open( name, O_RDONLY ); if ( fd == -1 ) err( 2, "opening %s", name ); return fd; } static int create_file( const char *name ) { int fd = open( name, O_CREAT | O_TRUNC | O_WRONLY, 0666 ); if ( fd == -1 ) err( 2, "creating %s", name ); return fd; } static int check_otp( const char *file, const char *key ) { const char *out_name = "zt.r4_test_out"; int out_fd = create_file( out_name ); int file_fd = open_or_die( file ); int key_fd = open_or_die( key ); int result = otp( file_fd, key_fd, out_fd ); close_or_warn( out_fd, out_name ); close_or_warn( file_fd, out_name ); close_or_warn( key_fd, out_name ); return result; } static int check_output( const char* expected, int size ) { const char *name = "zt.r4_test_out"; char buffer[ 4096 + 1 ] = { 0 }; int read_fd = open_or_die( name ); if ( read( read_fd, buffer, 4096 ) == -1 ) err( 2, "reading %s", name ); close_or_warn( read_fd, name ); return memcmp( expected, buffer, size ); } static void write_file( const char *name, const char *str, int size ) { int fd = create_file( name ); ssize_t written = write( fd, str, size ); if ( written == -1 ) err( 2, "writing file %s", name ); if ( written < size ) errx( 2, "write couldn't write all data to %s", name ); close_or_warn( fd, name ); } int main( void ) { char long_data[] = "abcdefghijklmnop"; char long_key[] = { 0x03, 0xbf, 0xfb, 0xb0, 0xb9, 0x54, 0x7b, 0xd7, 0x3e, 0x49, 0x43, 0x2a, 0xf0, 0x01, 0x1c, 0x82 }; char long_cipher[] = { 0x62, 0xdd, 0x98, 0xd4, 0xdc, 0x32, 0x1c, 0xbf, 0x57, 0x23, 0x28, 0x46, 0x9d, 0x6f, 0x73, 0xf2 }; char zeroes[ sizeof( long_key ) ] = { 0 }; char short_data[] = { 0xa5, 0x31, 0xfe }; char short_key[] = { 0x8d, 0xbc, 0x7f }; char short_cipher[] = { 0x28, 0x8d, 0x81 }; char alt_cipher[] = { 0xa6, 0x8e, 0x05 }; const int size = sizeof( long_key ); const int short_size = sizeof( short_key ); write_file( "zt.r4_key_long", long_key, size ); write_file( "zt.r4_key_short", short_key, size ); write_file( "zt.r4_file_long", long_data, size ); write_file( "zt.r4_file_short", short_data, short_size ); /* Dostatečná délka klíče: */ assert( check_otp( "zt.r4_key_long", "zt.r4_key_long" ) == 0 ); assert( check_output( zeroes, size ) == 0 ); assert( check_otp( "zt.r4_key_short", "zt.r4_key_short" ) == 0 ); assert( check_output( zeroes, short_size ) == 0 ); assert( check_otp( "zt.r4_file_long", "zt.r4_key_long" ) == 0 ); assert( check_output( long_cipher, size ) == 0 ); assert( check_otp( "zt.r4_file_short", "zt.r4_key_short" ) == 0 ); assert( check_output( short_cipher, short_size ) == 0 ); assert( check_otp( "zt.r4_file_short", "zt.r4_key_long" ) == 0 ); assert( check_output( alt_cipher, short_size ) == 0 ); /* Nedostatečná délka klíče: */ assert( check_otp( "zt.r4_file_long", "zt.r4_key_short" ) == 0 ); /* Chyba: */ assert( otp( -1, -1, -1 ) == -2 ); assert( errno == EBADF ); unlink_if_exists( "zt.r4_test_out" ); unlink_if_exists( "zt.r4_file_long" ); unlink_if_exists( "zt.r4_file_short" ); unlink_if_exists( "zt.r4_key_long" ); unlink_if_exists( "zt.r4_key_short" ); return 0; }