SE 2811, Lab 2: Strategy-based Encryption

This lab will give you experience using the Strategy Pattern. In this lab you will use the Strategy Pattern to build a portable device for carrying secure messages known as a CrypStick. When a message is entered into the CrypStick, it is encrypted before storing on the internal media. When a message is read from the internal media, it is decrypted. Thus (after the encryption method is cleared) anyone who steals the media must also break the encryption to reveal the message. This is an individual lab.

The primary class you will implement is CrypStick; it will contain Encrypter objects to handle encrypting and decrypting messages. The key elements are illustrated in the following class diagram:

You are being given a starting point for this lab, crypstick-start.zip. This code includes a preliminary implementation of the CrypStick and Media classes. It also includes a short program that uses these classes to encrypt and decrypt data. This program will serve as a test bed to help check that your implementation is correct. The provided CrypStick and Media classes are summarized in the following class diagram:

Note the provided Main.java interacts with the user through standard input and output (System.in, System.out). You are not to change the code to use a GUI or GUI operations like JOptionPane. On start up, the program prompts the user for whether to encrypt or decrypt the data and what encryption method to use. It then encrypts the data and displays the result.

For example, if you run your program from IntelliJ and direct it to encrypt tole using the key told, a sample run would be

E)ncrypt or D)ecrypt: e
Method (rev, shift, xor): xor
Key: told
Message: 
tole
^D
00 00 00 01 7e 

Some notes on the interaction:

The Media object simply stores the byte array given to it. When given a string, it treats the string as a series of space-separated bytes, each coded as two hexadecimal places. The toString() method returns a representation of the string using hexadecimal digits. We are using lower case letters (a-f) to represent the decimal values 10 through 15.

When encrypting information, the media's contents should be displayed in the Media object's String format, that is, in space-separated hexadecimal bytes.

When decrypting the message, the media's contents should be set with the space-separated hexadecimal bytes entered by the user before reading the message. A full application would not display this to the end user, but doing so in this lab allows us to confirm the media is properly encrypted.

Note that the encryption algorithms are fairly simple (that is, not secure). For example, the ShiftEncrypter encrypts text by simply substituting the another alphabetic character for each character encountered. The amount attribute (set by the ShiftEncrypter constructor) affects which character is substituted. For example, when amount is 1, ShiftEncrypter's encrypt() method would encrypt the 3-byte text Hal to Ibm, while the decrypt() method does the opposite. Similar to a Caesar cipher, if the numeric value of the character would fall outside of the ASCII range (0-255), the encrypter must "wrap around" to the other end. For example, if a code would have the numeric value of 256, it should wrap around to 0, and a numeric value of 260 should wrap around to 4.

ReverseEncrypter encrypts by reversing the characters in the string to be encrypted; thus Hello there Bob! becomes !boB ereht olleH. In hexadecimal, this is printed as 0a 21 62 6f 42 20 65 72 65 68 74 20 6f 6c 6c 65 48. This is a silly form of encryption, but it is a worthwhile encryption method to implement because it helps you debug your framework before attempting to introduce better encryption methods.

XOREncrypter is a little more complicated and so slightly harder to crack. For each byte in the array to be encrypted, this encrypter is to compute an exclusive-or (^ in Java) with each successive character in the specified key. For example, if the key is "abcd", then the encrypted array is

H^a   e^b   l^c   l^d   o^a   <sp>^b   t^c   h^d   e^a   r^b   e^c   <sp>^d   B^a   o^b   b^c   !^d

where H^a represents the character that results from applying the exclusive-or to H and a and <sp>^b represents computing the exclusive-or between b and a space character. Note how this also illustrates cycling through the bytes in the key arrway. For example, encrypting "Hello there Bob!" with "abcd" will give the hexadecimal output

29 07 0f 08 0e 42 17 0c 04 10 06 44 23 0d 01 45 6b

Decryption for XOR is the same process: reapply the exclusive-or operation (using the same key) to the encrypted array. Note α ^ β ^ β gives α; that is, computing an exclusive-or with the same string twice returns the original string.

The ShiftEncryter and XOREncrypter may produce non-printable characters. This is why all input and output of encrypted text uses hexadecimal.

Additional Constraints and Notes

Your submission will consist of the following:

See our Enterprise Architect Notes for how to reverse-engeineer a class model. The reverse-engineered model must include stereotypes (e.g. <<strategy interface>>, <<concrete strategy>>, etc.). Note the reverse-engineered diagram is to match your implementation; it may differ in details from the above diagram! For example, you may have different types of assocations. The EA Notes page also indicates how to generate a .PNG of your model; do not use screen capture to generate the .PNG because this results in a low-resolution image with important, missing details.

When you are finished, submit your assignment according to your instructor's specific directions. For example, you may need to convert your .PNG into a .PDF (probably using print-to-PDF on your computer).

Hints

Submission

Submission of the lab will be electronic. See Canvas for details.