[ fromfile: encryption-exercise.xml id: encryption-exercise ]
In Example 5.16 we declared but did not implement three operators for the Point3 class. Add implementations for these three operators and add tests to the client code.
In this exercise, we will reuse the random() function from the <cstdlib> (Appendix B).
random() generates a pseudo-random integer in the range from 0 to RAND_MAX (commonly set to 2147483647).
Write a function
int myRand(int min, int max);
that returns a pseudo-random int in the range from min to max - 1.
Write the function
QVector<int> randomPerm(int n, unsigned key);
that uses the myRand() function (seeded with key) to produce a permutation of the numbers 0, ... n.
Encryption and privacy are becoming increasingly important. One way to think of encryption is that we start with a string of text that we pass to one or more transforming functions. The result of these transformations is a string of encrypted text that we can then transmit more safely. The recipient of the encrpted string then applies the inverses of the transforming functions to the string of encrypted text (i.e., decrypts it) and obtains a copy of the original string. The sender of the encrypted string must share some information with the recipient that permits the string to be decrypted (i.e., a key). In the following exercises we explore a few simple designs for the transforming functions.
Write the function
QString shift(const QString& text, unsigned key) ;
shift() uses the parameter key to set the random function's seed by calling srandom(). For each character ch in the given string, text, produce a shifted character by adding the next pseudo-random int to the code for ch. The shifted character is then put in the corresponding place in the new string. When all the characters of text have been processed, shift() returns the new string.
When you add a random int to the code for a character you must do the addition “mod n” where n is the number of characters in the underlying character set that is being used. For this exercise, you can assume that you are working with the ASCII character set which has 128 characters.
The next function to write is:
QString unshift(const QString& cryptext, unsigned key);
This function reverses the process described in the previous exercise.
Write code to test the two functions described above.
Another approach to encryption (which can be combined with the approach described above) is to permute the characters of the given string. Write the function
QString permute(const QString& text, unsigned key);
that uses the randomPerm() function to generate a permutation of the characters of the original string, text.
Write the function
QString unpermute(const QString& scrtext, unsigned key);
that reverses the action of the permute() function described above.
Write code to test the two functions described above.
Write code to test shift() and permute() being applied to the same string, followed by unpermute() and unshift().
Implement a Crypto class that encapsulates the functions from the preceding exercises. You can use the following UML diagram to get you started.

m_OpSequence is a QString consisting of the characters 'p' and 's' that represent permute() and shift(). The encrypt() function applies those functions to the given string in the order that they appear in the m_OpSequence string.
Example 5.21 contains some code to test your class.
Example 5.21. src/functions/cryptoclass/crypto-client.cpp
#include "crypto.h" #include <QTextStream> #include <argumentlist.h> #include <qstd.h> using namespace qstd; void usage(const QString& appname) { cout << " Usage:\n" << appname << " actionSwitch " << " -k keyValue " << " -s string\n" << "where\nactionswitch is either -e (encrypt) or -d (decrypt)\n" << "(default is encrypt)." << "keyvalue is the encryption key if you don't use default key.\n" << "string is the string to be encrypted or decrypted.\n" << "Converted string is sent to stdout." << endl; } int main(int argc, char** argv) { QString str1 ("asdfghjkl;QWERTYUIOP{}}|123456&*()_+zxcvnm,,, ./?"), str2; cout << "Original string: " << str1 << endl; QString seqstr("pspsp"); ushort key(12579); Crypto crypt(key, seqstr); str2 = crypt.encrypt(str1); cout << "Encrypted string: " << str2 << endl; cout << "Recovered string: " << crypt.decrypt(str2) << endl; /* ArgumentList al(argc, argv); QString appname(al.takeFirst()); QString str1(al.getSwitchArg("-s")); if(str1 == QString()) { usage(appname); exit(1); } bool decrypt(al.getSwitch("-d")); QString keystr(al.getSwitchArg("-k")); unsigned key(214365); // default if(keystr != QString()) key = keystr.toUInt(); QString seqstr("pspsp"); Crypto crypt(key, seqstr); if(decrypt) cout << crypt.decrypt(str1); else cout << crypt.encrypt(str1); */ }
Now that you have developed a Crypto class for encrypting and decrypting strings, let's use that class for managing the passwords for users of some system.

In addition to the Crypto member, the UserManager class also needs members to hold, for each user, the userid and encrypted password. [20]
All of the member functions are “silent” (i.e., no interaction with the user). User interactions take place only in the client code.
The constructor instantiates the Crypto member.
Each of the three bool functions returns true if the operation is successful.
loadList() and saveList() both access a file named pwfile. They each return the number of users.
Write the class definition for UserManager.
Write implementations for all of the methods listed in the UML diagram for the UserManager.
Write client code to thoroughly test UserManager.
| Generated: $Date: 2009-09-08 12:15:32 -0400 (Tue, 08 Sep 2009) $ | © 2009 Alan Ezust and Paul Ezust. |