33.

Learn Encryption Techniques with BASIC and C++
(Publisher: Wordware Publishing, Inc.)
Author(s): Gil Held
ISBN: 1556225989
Publication Date: 10/01/98

Previous Table of Contents Next


The CIPHER5.BAS Program

Listing 3.3 illustrates the statements contained in the main portion of CIPHER5.BAS as well as the subroutine INITIALIZE, which required a slight modification from its prior form. You should note that lines terminating with five asterisks (*) as a comment indicate lines that were added to the main program to facilitate an explanation of its operation. Those lines can be removed if you do not wish to burden a user who has no desire to understand the enciphering process with this extraneous information.

Listing 3.3 The main portion of the program CIPHER5.BAS and the modified subroutine INITIALIZE.

 REM PROGRAM CIPHER5.BAS DIM PLAINTEXT$(26), CIPHERTEXT$(26), KEY$(26) CLS GOSUB INITIALIZE    PRINT "CIPHER5.BAS PROGRAM enciphers text based upon the use of                a keyword or keyword"    PRINT "phrase and an alphabetic shift key using a monoalphabetic                substitution process."    PRINT    INPUT "Enter keyword or keyword phrase in UPPERCASE: ", TEXT$    PRINT "Plaintext based alphabet is : ";    '*****    FOR I = 0 TO 25: PRINT PLAINTEXT$(I);: NEXT I  '*****    GOSUB KEYWORD             'form keyword-based mixed alphabet    PRINT "Keyword-based alphabet is     : "; X$  '***** 1  INPUT "Enter UPPERCASE Alphabetic Shift Key: ", K$    FOR I = 0 TO 25    IF K$ = PLAINTEXT$(I) GOTO 2    NEXT I    PRINT "You must enter a letter from A to Z"    GOTO 1 2  REM Position I represents shift key letter GOSUB FORMCIPHER       'create cipher alphabet    PRINT "Shifted keyword mixed alphabet is  : ";   '*****    FOR I = 0 TO 25: PRINT CIPHERTEXT$(I);: NEXT I: PRINT    '***** GOSUB INITIALIZE       'reinitialize plaintext array GOSUB MSGFILE          'assign I/O files, place message on a file GOSUB CONVERTSTORE     'convert and store ciphertext on a file GOSUB PRTOUT           'print results STOP INITIALIZE:      RESTORE      REM Initialize plaintext values      FOR I = 0 TO 25      READ PLAINTEXT$(I)      NEXT I      DATA "A","B","C","D","E","F","G","H","I","J","K","L","M","N"      DATA "O","P","Q","R","S","T","U","V","W","X","Y","Z"  RETURN 

As indicated in Listing 3.3, first initialize the string array PLAINTEXT$ and then display information about the program. After the keyword or keyword phrase is entered and assigned to the string variable TEXT$, the plaintext alphabet is displayed. Next, the subroutine KEYWORD is invoked to form a keyword-based mixed alphabet. That subroutine is the same as the subroutine previously developed in the program WORD.BAS.

After the subroutine KEYWORD is invoked, the keyword-based alphabet is displayed via the use of another optional statement. The user is then prompted to enter an alphabetic shift character, and the subroutine FORMCIPHER is invoked to create a cipher alphabet. That alphabet is displayed through the use of a pair of optional statements.

Because the subroutine FORMCIPHER creates the cipher alphabet by shifting the previously created keyword-based mixed alphabet, you must restore the plaintext alphabet to its original sequence to correctly convert plaintext characters to their equivalent ciphertext characters. This is accomplished by again invoking the subroutine INITIALIZE. However, because that subroutine previously read the normal letter sequence into the array PLAINTEXT, you must place a RESTORE statement at the beginning of the subroutine. Otherwise, you would receive an “out-of-data” error message.

The Encipherment Process

Figure 3.2 illustrates the execution of CIPHER5.BAS to encipher a short but important message. To understand the encipherment process, examine the composition of the different alphabets displayed by the program.


Figure 3.2   A sample execution of CIPHER5.BAS

The plaintext based alphabet is simply the character sequence A through Z. After a keyword or keyword phrase is entered, the plaintext sequence is modified based upon the keyword or keyword phrase. For example, entering the keyword MICROSOFTWINDOWS results in the keyword-based alphabet MICROSFTWNDABEGHJKLPQUVXYZ because all duplicate characters in the keyword or keyword phrase are eliminated prior to the addition of the characters in the plaintext alphabet that are not in the modified keyword or keyword phrase. The entry of an alphabetic shift key causes the cycling of the keyword-based alphabet so that all characters to and including the alphabetic shift key character are rotated. Thus, the shifted keyword mixed alphabet becomes EGHJKLPQUVXYZMICROSFTWNDAB.

The encipherment process requires each character in the message to be located in the array PLAINTEXT$, which contains the normal alphabetic sequence. When a match is found, the ciphertext character located in the same position in the shifted keyword mixed alphabet in the CIPHERTEXT$ array is extracted and substituted for the plaintext character. Note the positional relationship of characters between the plaintext based alphabet and the shifted keyword mixed alphabet in Figure 3.2. The first character in the message is B, located in the second position in the plaintext alphabet. The second character in the shifted keyword mixed alphabet is G. Hence, B was replaced by G. The second letter in the message is I, located in the ninth position in the plaintext alphabet. In the ninth position in the shifted keyword mixed alphabet, extract a U. Similarly, D is replaced by the character J and the first word in the plaintext message, BID, is enciphered as GUJ.

The CIPHER5.CPP Program

The C++ version of the previously described CIPHER5.BAS program is appropriately named CIPHER5.CPP and is contained on the CD-ROM under the C directory. The executable version of this C++ program follows our naming convention and is named CIPHER5.EXE. To distinguish the BASIC executable version of CIPHER5 from the C++ version of that program, it is important to remember that those versions are located in the BASIC and C directories on the CD-ROM.

Listing 3.4 lists the contents of the program CIPHER5.CPP. As you examine the program listing you will note that the C++ software author, Jonathan Held, replaced the #define statements with the use of integer constants to demonstrate another method you can use to create constants for a C++ program. Similar to other C++ program listings, the listing of CIPHER5.CPP includes a detailed description via embedded comments that indicates how the program operates. The only function that is completely new in Listing 3.4 is the welcome function whose statements are listed at the end of the program. Although the other functions in CIPHER5.CPP were developed for previously covered C++ programs, the entire program is given in Listing 3.4 to provide you with the manner by which functions interact with one another as well as to provide an example of the use of integer constants instead of magic numbers.

Listing 3.4 The CIPHER5.CPP program listing.

 /* cipher5.cpp C++ Code written by Jonathan Held, February 28, 1998, using Microsoft Visual C++, version 5.0.  Please read file for detailed description of how the program works. */ //standard include files #include <iostream.h>      //standard i/o operations #include <string.h>        //used to find the length of a string #include <ctype.h>         //for character handling #include <fstream.h>       //file stream processing #include <stdlib.h>        //standard library functions #include <string.h>        //string handling functions //Constants - we don't want to use any magic numbers! //Notice how now we aren't using #defines as we did before - //Just another way to create constants for our program. const int TWO=2, THREE = 3, FOUR = 4, FIVE = 5, TWENTYFIVE = 25,       TWENTYSIX = 26, TWENTYSEVEN = 27, SIXTYFIVE = 65,       NINETY = 90, NINETYTWO = 92, SIZE = 256, BIGSIZE = 1000; //function prototypes - see function headers for more information void welcome(void);              //only function that is                                  //new to this file void getFileNames(char* &, char* &);   //all other functions have int getInputType(void);                //been used in previous programs //keyword or keyword phrase functions: void getKeyword(char * &); bool checkInput(char * &); void createAlphabet(char *, char []); bool getMessage(char*, char*, char [], const char[], const char[]); //monoalphabetic substitution functions: void getShiftKey(char &); void shiftKeyword(char [], char); //shiftKeyword modified for this                                   //program - see function for details //other functions: char* formCipheredMessage(const char[], const char [], char []); void printResults(const char[], const char[], const char[], const char [],                     const int); void printCipherToFile(ofstream, char[]); void formatData(char []); void groupBUFFER(ofstream, int); bool encryptText(char *, char *, const char [], const char[], char []); void display(char *); char BUFFER[BIGSIZE] = {'\0'}; //------------------------------------------------ //Function: main() //Parameters: None //Return Type: int - 0 execution is normal, 1 abnormal termination //Purpose: Runs the main part of the program. //------------------------------------------------ int main(){   //initialize plaintext   char plaintext[TWENTYSEVEN] = {'A','B','C','D','E','F','G','H','I',                       'J','K','L','M','N','O','P','Q','R',                       'S','T','U', 'V','W','X','Y','Z', '\0'};   //other variables we will use   char ciphertext[TWENTYSEVEN]= {'\0'};   char message_to_cipher[SIZE], key;   char *infile, *outfile, *keyword;   int input_type;   bool success = false;   welcome();   getKeyword(keyword);   createAlphabet(keyword, ciphertext);   cout << "\nPlaintext-based alphabet is: " << plaintext << endl      << "Keyword-based alphabet is:   " << ciphertext << endl << endl;   getShiftKey(key);   shiftKeyword(ciphertext, key);   cout << "Shifted keyword mixed alphabet is: " << endl << ciphertext                   << endl << endl;   getFileNames(infile, outfile);   input_type = getInputType();   //check for manual entry of data   if (!(input_type)){      success = getMessage(infile, outfile, message_to_cipher, plaintext,                   ciphertext);   }   //user wants to encipher a file   else {     success = encryptText(infile, outfile, plaintext, ciphertext,                   message_to_cipher);   }   //display the output file only if we were successful   if (success){      cout << "Press return to display resulting enciphered message."                    << endl;      //get the newlines off the current input stream      cin.get();      cin.get();      display(outfile);   }   else {     cerr << "Error executing program!" << endl;   }   //delete all dynamically allocated memory   delete [] keyword;   delete [] infile;   delete [] outfile;   return (static_cast<int>(!(success))); }//end main() //------------------------------------------------ //Function: checkInput() //Parameters: input - the keyword the user entered //Return Type: bool - true if the input string contains an error, //        false otherwise //Purpose: Checks the user's keyword for invalid characters. //------------------------------------------------ bool checkInput(char * &input) {   bool error = false;   int count = strlen(input);   for (int ix=0; ix<count; ix++){     int char_value = static_cast<int>(*(input+ix));     //determine if the user did not enter an uppercase character     if ((char_value < SIXTYFIVE) || (char_value > NINETY)){        error = true;        cerr << "You entered an invalid keyword!" << endl << endl;        break;      }   }   return error; }//end checkInput() //------------------------------------------------- //Function: createAlphabet() //Parameters: input - the keyword the user entered //      cipher - the keyword alphabet that will be constructed //Return Type: None //Purpose: Creates the keyword alphabet. //------------------------------------------------- void createAlphabet(char *input, char cipher[]) {   bool used[TWENTYSIX];   int index = 0,       count = strlen(input);   //no characters are initially used   for (int ix=0; ix<TWENTYSIX; ix++){     used[ix] = false;   }   //keep track of each character used, start forming the keyword   //alphabet   for (int jx=0; jx<count; jx++){     //get each character of the input string (integer value)     int char_value = static_cast<int>(*(input+jx));     if (used[char_value-SIXTYFIVE]){        //do nothing - the character was already used     }     else {       //mark as used and add to the keyword alphabet       used[char_value-SIXTYFIVE] = true;       *(cipher+index++) = static_cast<char>(char_value);     }   }   //go through the list of characters used - those which weren't   //used should be added to the keyword alphabet   for (int kx=0; kx<TWENTYSIX; kx++){     if (!(used[kx])){        *(cipher+index++) = static_cast<char>(SIXTYFIVE+kx);     }   }   return; }//end createAlphabet() //------------------------------------------------ //Function: display() //Parameters: name - the name of the file the user wants displayed //Return Type: None //Purpose: Echos the resulting output file to the screen. //------------------------------------------------ void display(char *name) {   ifstream infile(name, ios::in);   char input[SIZE];   if (!(infile)){      cerr << "Unable to open input file for display." << endl;   }   else {     while (infile.getline(input, SIZE, '\n')){      cout << input << endl;     }   }   return; }//end display() //------------------------------------------------ //Function: encryptText() //Parameters: inp_file - the name of the input plaintext file //     outp_file - the name of the output ciphertext file //     PTEXT[] - the plaintext alphabet //     CTEXT[] - the ciphertext alphabet //     encoded_msg[] - the message to be encoded //Return Type: bool, indicating success of operation //Purpose: Used to encrypt file input.  Takes each line of the input //file, encrypts it, and saves the result to the specified output //file. //------------------------------------------------ bool encryptText(char * inp_file, char * outp_file, const char PTEXT[],           const char CTEXT[], char encoded_msg[]) {   bool success = false;   char ip[SIZE];   //declare file stream objects   ifstream input(inp_file, ios::in);   ofstream output(outp_file, ios::app);   if ((!input) || (!output)){     //do nothing - I/O error; user will be notified upon     //procedure's return to main()   }   else {     success = true;     //print plaintext and ciphertext alphabets to the     //output file     output << "PLAINTEXT:  " << PTEXT << endl;     output << "CIPHERTEXT: " << CTEXT << endl << endl;     while (input.getline(ip, BIGSIZE, '\n')){      //check to see if the user wants the line to appear in plain text      if (ip[0] == '/'){         if (strlen(BUFFER)>0){         //empty whatever is in the buffer         groupBUFFER(output, strlen(BUFFER));         //adjust the buffer         strcpy(BUFFER, (BUFFER+strlen(BUFFER)));         //output plaintext       }       output << ip << endl;       }       else {         //encipher the line         char *msg = formCipheredMessage(CTEXT, ip, encoded_msg);         //print the cipher in groups of five to the ouput file         printCipherToFile(output, msg);       }     }     //empty the rest of the buffer     groupBUFFER(output, strlen(BUFFER));     //notify user where plaintext and ciphertext files are     cout << "Plaintext file is: " << inp_file << endl;     cout << "Encrypted file is: " << outp_file << endl << endl;   }   //don't forget to close the files   input.close();   output.close();   //return success of the operation   return success; }//end encryptText() //------------------------------------------------ //Function: formatData() //Parameters: data - the array we want to format //Return Type: None //Purpose: Get rid of all spaces in the array. //------------------------------------------------ void formatData(char data[]){   for (int mx=0, nx=0; (*(data+nx) != '\0'); nx++){     if (*(data+nx) == ' '){        //do nothing - skip over the space in the data     }     else {       *(data+mx++) = *(data+nx);     }   }   //don't forget to add the null terminator   *(data+mx) = '\0';   return; }//end formatData() //------------------------------------------------ //Function: formCipheredMessage() //Parameters:  CTEXT - the cipher alphabet we will use for substitution //       MESSAGETOCIPHER - the user's message //       enc_message - the enciphered message to be determined //Return Type: char* - a pointer to the encoded information. //Purpose: Encipher the user's message. //------------------------------------------------ char* formCipheredMessage(const char CTEXT[], const char MESSAGETOCIPHER[],                char enc_message[]){   int length = strlen(MESSAGETOCIPHER)+1;   int encode_value;   for (int ix=0; ix<length; ix++){     //test to see if we have an alphabetic character; if not,     //simply copy it to our encrypted message - this preserves     //characters such as ', ! etc...     if (!isalpha(static_cast<int>(MESSAGETOCIPHER[ix]))){       enc_message[ix] = MESSAGETOCIPHER[ix];     }     else {        //valid character - the easy way to calculate the ciphered        //character is based on the plain text's ascii character value;        //since it has to be a capital letter, it must be in the range        //from 65 to 90, with A represented by 65, Z by 90.  By simply        //subtracting 65 from the encode_value (the integer representation        //of the plaintext character), we now know what cipher character            //to use.        encode_value = toupper(static_cast<int>(MESSAGETOCIPHER[ix]));        enc_message[ix] = CTEXT[encode_value-SIXTYFIVE];      }   }   //return a reference to the encoded message   return enc_message; }//end formCipheredMessage() //------------------------------------------------ //Function: getFileNames() //Parameters: infile_name - the input file //       outfile_name - the output file we will write the //       enciphered text to //Return Type: None //Purpose: Get file information from the user. //------------------------------------------------ void getFileNames(char * &infile_name, char * &outfile_name) {   char data[SIZE];   cout << "Enter filename to store/retrieve plaintext message: ";   cin >> data;   infile_name = new char[strlen(data) + 1];   strcpy(infile_name, data);   cout << "Enter filename to store enciphered message: ";   cin >> data;   outfile_name = new char[strlen(data) + 1];   strcpy(outfile_name, data);   cout << endl;   return; }//end getFileNames() //------------------------------------------------ //Function: getInputType() //Parameters: None //Return Type: int - 0 indicates keyboard input, 1 indicates file //       input //Purpose: Determines if the user will be manually entering text to //be enciphered or if the user wants a file to be enciphered. //------------------------------------------------ int getInputType(void) {   char type;   bool error = false;   int value;   do {     //prompt user for input from file or keyboard     cout << "Is file input from keyboard (K, k) or file (F, f): ";     cin >> type;     //make type an uppercase letter     type = static_cast<char>(toupper(static_cast<int>(type)));     //check for an invalid character     if((type != 'K') && (type != 'F')){       cerr << "You have entered an invalid character!" << endl << endl;       error = true;     }     else {       if (type == 'K')          value = 0;       //value of 0 represents keyboard input          else value = 1;    //value of 1 represents file input       error = false;     }   } while (error);   cout << endl;   return value; }//end getInputType() //------------------------------------------------ //Function: getKeyword() //Parameters: text - the keyword that the user enters //Return Type: None //Purpose: Prompts the user for a keyword and continues until //a valid keyword has been entered. //------------------------------------------------ void getKeyword(char * &text) {   bool error = false;   do {     char buffer[SIZE];     cout << "Enter keyword or keyword phrase in UPPERCASE" << endl       << "do not use spaces or non-alphabetic characters): ";     cin.getline(buffer, SIZE, '\n');     text = new char[strlen(buffer) + 1];     strcpy(text, buffer);     error = checkInput(text);   } while (error);   return; }//end getKeyword() //------------------------------------------------ //Function: getMessage() //Parameters:  input - the name of the input plaintext file //       output the name of the output ciphertext file //       msg_to_cipher - the message to be encoded //       PTEXT[] - the plaintext alphabet //       CTEXT[] - the ciphertext alphabet //Return Type: bool, indicating success of operation //Purpose: Allow the user to manually input text from the keyboard. //Save the text in plaintext to the input file; encrypt the text //and save it to the specified output file for later retrieval. //------------------------------------------------ bool getMessage(char* input, char* output, char msg_to_cipher[],                   const char PTEXT[], const char CTEXT[]){   bool go_on = true, success = false;   ofstream textFile(input, ios::app);   ofstream cipherFile(output, ios::app);   if((!textFile) || (!cipherFile)){     //do nothing - error will be noted to user later   }   else {     success = true;     textFile << "PLAINTEXT:  " << PTEXT << endl;     textFile << "CIPHERTEXT: " << CTEXT << endl << endl;     //get the newline character off of the input stream     cin.get();     cout << "Enter the message in UPPERCASE or lowercase characters. "                   << endl          << "Non-alphabetic characters may be entered but are ignored."                   << endl          << "Use a / at the beginning of each line that should remain"                   << endl          << "in plaintext and a \\ on a separate line to indicate the"                   << endl          << "end of an enciphered message." << endl << endl;     while (go_on) {      //get the entire line, up to 256 characters      cin.getline(msg_to_cipher, SIZE, '\n');        //case user doesn't want the text to be encrypted      if(msg_to_cipher[0] == '/'){        if(strlen(BUFFER)>0){          //empty whatever is in the buffer          groupBUFFER(cipherFile, strlen(BUFFER));          //adjust the buffer          strcpy(BUFFER, (BUFFER+strlen(BUFFER)));        }        //output plaintext        textFile << msg_to_cipher << endl;        cipherFile << msg_to_cipher << endl;     }      //case user is done entering text      else if (static_cast<int>(msg_to_cipher[0]) == NINETYTWO){        go_on = false;     }      //encrypt the text      else {        textFile << msg_to_cipher << endl;        char enciphered_msg[BIGSIZE];        formCipheredMessage(CTEXT,msg_to_cipher,enciphered_msg);        printCipherToFile(cipherFile,enciphered_msg);     }     }   //empty the rest of the buffer   groupBUFFER(cipherFile, strlen(BUFFER));   }   //close the files   textFile.close();   cipherFile.close();   //notify user where plaintext and ciphertext files are   cout << "\nPlaintext file is: " << input << endl;   cout << "Encrypted file is: " << output << endl << endl;   return success; }//end getMessage() //------------------------------------------------ //Function: getShiftKey() //Parameters:  key_desired - uppercase key entered by the user //Return Type: None //Purpose: Get the key the user enters; error checking performed //until user enters a valid value. //------------------------------------------------ void getShiftKey(char &key_desired){   bool error = true;   do {     //prompt user to enter an uppercase shift key     cout << "Enter UPPERCASE Alphabetic Shift Key (CTRL-C to quit): ";     cin >> key_desired;     int key_value = static_cast<int>(key_desired);     //do some error checking     if((key_value < SIXTYFIVE) || (key_value > NINETY)){       cerr << "\nYou must enter a letter from A to Z!" << endl << endl;     }     else {       error = false;     }   } while (error);   cout << endl;   return; }//end getShiftKey() //------------------------------------------------ //Function: groupBUFFER() //Parameters: out - the output stream we are writing to //      num - the number of characters we want to output //Return Type: None //Purpose: Output the buffer in groups of five characters at a //time. //------------------------------------------------ void groupBUFFER(ofstream out, int num) {   for (int kx=0;kx<num;kx++){     if((kx!=0) && (kx%TWENTYFIVE==0)){       out << endl;     }     if((kx!=0) && (kx%FIVE == 0) && (kx%TWENTYFIVE!=0)){       out << " " << *(BUFFER+kx);     }     else {     out << *(BUFFER+kx);     }   }   out << endl;   return; }//end groupBUFFER() //--------------------------------------------- //Function: printCipherToFile() //Parameters: op - the output file we are writing to //      msg - the cipher text we are displaying //Return Type: None //Purpose: Group the cipher in 5-block characters in the //specified output file. //--------------------------------------------- void printCipherToFile(ofstream op, char msg[]){   formatData(msg);   //check to see if there are more than 25 characters   //in the buffer; if so, print out as many groups of   //25 as possible   if(strlen(BUFFER) >= TWENTYFIVE){     int numchars = (strlen(BUFFER)/TWENTYFIVE)*TWENTYFIVE;     //print the contents of the buffer to the output stream     groupBUFFER(op, numchars);     //shift whatever is left in the buffer     strcpy(BUFFER, (BUFFER+numchars));     //append data to the buffer     strcat(BUFFER, msg);   }   //if buffer contents are less than 25, simply append the new   //data to the buffer   else if ((strlen(BUFFER) >= 0) && (strlen(BUFFER) < TWENTYFIVE)){     strcat(BUFFER, msg);   }   return; }//end printCipherToFile() //------------------------------------------------ //Function: shiftKeyword() //Parameters: ctext - the cipher alphabet we are going to shift //      user_key - the key the user entered //Return Type: None //Purpose: Shift the keyword or keyword phrase we will use later to //encode the user's message. //------------------------------------------------ void shiftKeyword(char ctext[], const char USER_KEY){   int location;   char temp[TWENTYSIX] = {'\0'};   //find the location of the key in the plaintext   for (int ix=0; ix<TWENTYSIX; ix++){     if(USER_KEY == ctext[ix]){       location = ix;       break;      }   }   if(location == TWENTYFIVE){      //do nothing   }   else {     //put into temp all the characters up to and including the shift key     //location now indicated how many characters, so we must increment by     //one since the array uses a zero-based index     strncpy(temp, ctext, location+1);     //shift all remaining characters in the ciphertext     strcpy(ctext, (ctext+location+1));     //concatenate temp back to ctext     strcat(ctext, temp);   }   return; }//end shiftKeyword(); //------------------------------------------------ //Function: welcome() //Parameters: None //Return Type: None //Purpose: Prints the program's greeting message. //------------------------------------------------ void welcome(void) {   cout << "CIPHER5.EXE PROGRAM enciphers text based upon the use of a"                  << endl        << "keyword or keyword phrase and an alphabetic shift key using a"                  << endl        << "monoalphabetic substitution process." << endl << endl;   return; }//end welcome() //end file cipher5.cpp 


Previous Table of Contents Next


Learn Encryption Techniques with Basic and C++
Learn Encryption Techniques with BASIC and C++
ISBN: 1556225989
EAN: 2147483647
Year: 2005
Pages: 92
Authors: Gil Held

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net