// // ********************************************************************** // * Code Challenge * // ********************************************************************** // // Challenge: // // Write an exclusive-OR encryption program. // The program should take as input a filename that // is then encrypted by the program. The program // should ask the user to input an encryption key, // which should be used to encrypt the file. // The output of the program should go into a file // with the same filename but a .ENC extension // (for simplicity sake). // All programs should run under DOS. // // Comments and voluntary changes: // // Added a second argument for output filename, // as you cannot encrypt/decrypt a file that already // is encrypted and has the .enc extension following // the given guidelines. This change to the specifications // is optional, so it works as per the specifications as // well. // The program encrypts the file, not the filename like // stated above, I think it's obvious that this passage // should not be taken by the word. // This application uses ANSI commands and standard headers, // it should be able to run as a .c file as well. However, // I was too lazy to test it on anything but VC as a windows // console application. // My other programs would probably be commented differently, // but as all of us are working at the same problem, much of // it will be quite clear from own experience. // Edit: Tested ok as pure C. // // Time: // // I received the mail Tuesday, 08.01.2002 15:27. // Started coding at roughly 18:00 // Finished coding at about 18:45, starting to write comment. // Sent the reply mail: 19:30 // // Facts: // // Author: Niels Voigt // EMail: nvoigt@saz.net // Username: nvoigt from cprogramming // Compiler: VC 6 SP 5 // Project: Console Application, should be 100% DOS compatible // Libraries: ANSI C // // Testing: // // Encrypting a file twice and checking with the FC utility // gives a 100% match. So if there are still mistakes, at // least they are consistent ;-) // // standard includes for io and strings #include #include // constants #define MAX_PATH 1000 #define MAX_ENCRYPT_KEY 100 #define XOR_FILE_EXT ".enc" #define ERROR_NOERROR 0 #define ERROR_READERROR 1 #define ERROR_WRITEERROR 2 // prototypes, description see below int CreateFileName( const char* szOldFile, char* szNewFile ); int RemoveUnwantedCharacters( char* szBuffer ); // // main // // the encryption program itself // int main( int argc, char* argv[] ) { // variable declaration FILE* fpInput; FILE* fpOutput; char szFileName[MAX_PATH+1]; char szEncryptionKey[MAX_ENCRYPT_KEY+1]; int nEncryptKeyLength; int nByte; int nCount; int nError; // check for arguments if( argc == 2 ) { // create filename if only source was given CreateFileName( argv[1], szFileName ); } else if( argc == 3 ) { // copy given destination strcpy( szFileName, argv[2] ); } else { // print help if number of arguments are illegal printf( "\nWrong number of arguments\n" ); printf( "USAGE: %s Source [Destination]\n\n", argv[0] ); return 1; } // ask for encryption key do { printf( "Please enter encryption key ( 1 - %d characters ):",MAX_ENCRYPT_KEY ); memset( szEncryptionKey, MAX_ENCRYPT_KEY+1, 0 ); fgets( szEncryptionKey, MAX_ENCRYPT_KEY, stdin ); RemoveUnwantedCharacters( szEncryptionKey ); nEncryptKeyLength = strlen( szEncryptionKey ); } while( nEncryptKeyLength == 0 ); // print status and data printf( "\n" ); printf( "Encrypting [%s]\n",argv[1] ); printf( " to [%s]\n",szFileName ); printf( " using [%s]\n",szEncryptionKey ); printf( "\n" ); // open input file fpInput = fopen( argv[1], "rb" ); if( fpInput == NULL ) { printf( "Error: Unable to open %s for reading.\n\n", argv[1] ); return 2; } // open output fpOutput = fopen( szFileName, "wb" ); if( fpOutput == NULL ) { printf( "Error: Unable to open %s for writing.\n\n", szFileName ); return 3; } nCount = 0; nError = ERROR_NOERROR; // encryption loop: // read a byte, encrypt, write, next until no more bytes // each byte is encrypted with one letter from the key, // when the end of the key is reached, the next byte is // encrypted with the first one again. while( ( nByte = fgetc( fpInput ) ) != EOF ) { if( fputc( nByte ^ szEncryptionKey[nCount], fpOutput ) == EOF ) { nError = ERROR_WRITEERROR; break; } nCount++; if( nCount >= nEncryptKeyLength ) nCount = 0; } // check if the loop terminated with an end-of-file. // after all, somebody may have pulled the // plug or the network cable, which will also result // in an EOF condition for fgetc. if( ! feof( fpInput ) ) nError = ERROR_READERROR; // print end message switch( nError ) { case ERROR_NOERROR: printf( "Encryption complete.\n\n" ); break; case ERROR_READERROR: printf( "Error: unable to perform READ operation on file [%s]\n\n", argv[1] ); break; case ERROR_WRITEERROR: printf( "Error: unable to perform WRITE operation on file [%s]\n\n", szFileName ); break; default: printf( "Error: Unknown Error, please contact your support.\n\n" ); break; } // close files fclose( fpInput ); fclose( fpOutput ); // done ;-) return 0; } // // CreateFileName // // creates the destination filename from the source // by replacing the file extension or adding it if // no other extension is found. // int CreateFileName( const char* szOldFile, char* szNewFile ) { char* szReplace; strcpy( szNewFile, szOldFile ); szReplace = szNewFile + strlen( szNewFile ); while( szReplace > szNewFile && *szReplace != '\\' && *szReplace != '/' ) { if( *szReplace == '.' ) { strcpy( szReplace, XOR_FILE_EXT ); return 0; } szReplace--; } strcat( szNewFile, XOR_FILE_EXT ); return 1; } // // RemoveUnwantedCharacters // // removes the 0D characters that are left in the buffer // when reading... I wish there was ONE out-of-the-box // simple-to-use input function. // int RemoveUnwantedCharacters( char* szBuffer ) { while( *szBuffer != 0 ) { if( *szBuffer == 0x0a || *szBuffer == 0x0d ) *szBuffer = 0; szBuffer++; } return 0; } // // END OF FILE //