/* xorfile.c John Simpson 2007-08-19 uses a file (presumably full of random bytes) as a pad to xor-encode stdin to stdout ********************************************************************* Copyright (C) 2007 John Simpson. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 3, as published by the Free Software Foundation. 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 . */ #include #include #include #include #include #include #define WORK_BUF_LEN 65536 /* how many bytes we want to chew on at once not too big, allocated from stack space */ #define PAD_BUF_LEN 1048576 /* size of memory buffer for pad data. max size depends on OS */ #define PAD_MIN_LEN 16 /* if you want to reject key files which are too small to be secure. must be larger than BUFSKIP */ #define stringify(s) #s /****************************************************************************** * error handlers */ void die ( const char *msg ) { fputs ( msg , stderr ) ; exit ( 1 ) ; } void pdie ( const char *msg ) { perror ( msg ) ; exit ( 1 ) ; } /****************************************************************************** * compensate for cases where read() and write() may not be able to handle * all of the desired data at once */ ssize_t bigread ( int fd , void *buf , size_t count ) { int rv ; int tcount ; tcount = 0 ; while ( tcount < count ) { rv = read ( fd , buf+tcount , count-tcount ) ; if ( -1 == rv ) pdie ( "read()" ) ; if ( 0 == rv ) break ; tcount += rv ; } return tcount ; } ssize_t bigwrite ( int fd , void *buf , size_t count ) { int rv ; int tcount ; tcount = 0 ; while ( tcount < count ) { rv = write ( fd , buf+tcount , count-tcount ) ; if ( -1 == rv ) pdie ( "write()" ) ; if ( 0 == rv ) break ; tcount += rv ; } return tcount ; } /****************************************************************************** * pad buffer and buffer extraction function * loops back to beginning if it reaches the end of the buffer */ int padfh = -1 ; unsigned char padbuf[PAD_BUF_LEN] ; unsigned char *padp = NULL ; unsigned char *pad_end = NULL ; ssize_t pad_short = 0 ; unsigned char get_pad_byte ( void ) { ssize_t rv ; /*************************************** * first read ever * if bigread() < PAD_BUF_LEN, we know that we have the entire * pad in memory and won't need to re-read it if we have to loop * back to the beginning */ if ( ! padp ) /* first read ever */ { rv = bigread ( padfh , padbuf , PAD_BUF_LEN ) ; if ( rv == 0 ) die ( "pad file is empty!\n" ) ; #ifdef PAD_MIN_LEN if ( rv < PAD_MIN_LEN ) die ( "pad file too short, need at least " stringify(PAD_MIN_LEN) "bytes\n" ) ; #endif if ( rv < PAD_BUF_LEN ) /* does it all fit in memory? */ pad_short = 1 ; padp = padbuf ; pad_end = padbuf + rv ; } /*************************************** * reached end of buffer * if the pad is all in memory, go back to the beginning * otherwise read the next chunk of pad data from the disk */ if ( padp >= pad_end ) { padp = padbuf ; if ( ! pad_short ) { rv = bigread ( padfh , padbuf , PAD_BUF_LEN ) ; if ( rv == 0 ) { rv = lseek ( padfh , 0 , SEEK_SET ) ; if ( rv == -1 ) pdie ( "lseek()" ) ; rv = bigread ( padfh , padbuf , PAD_BUF_LEN ) ; } pad_end = padbuf + rv ; } } /*************************************** * return the next available byte of pad data */ return *padp++ ; } /****************************************************************************** ******************************************************************************* ******************************************************************************/ int main ( int argc , char *argv[] ) { unsigned char workbuf[WORK_BUF_LEN] ; ssize_t c , n ; /*************************************** * open the pad file */ if ( argc < 2 ) die ( "No key file specified.\n" ) ; padfh = open ( argv[1] , O_RDONLY ) ; if ( padfh == -1 ) pdie ( "open()" ) ; /*************************************** * do the deed */ c = bigread ( 0 , workbuf , WORK_BUF_LEN ) ; while ( c ) { for ( n=0 ; n