Colorado State University Logo | CS 163/4: Java Programming (CS 1) Colorado State University Logo | CS 163/4: Java Programming (CS 1)
CS 163/4: Java Programming (CS 1)
Computer Science

Practical Two - Encrypted Message System 101

Introduction

Welcome to the Encrypted Message System 101, a program that is going to require you to write key components including basic ciphers to help encrypt the messages between clients. While this application is not ready for networking, it is very similar to a basic email application.

In addition to writing the code, you will be learning to use an Integrated Development Environment (IDE), and in particular for this class, you will be using IntelliJ. While you are technically free to use other IDEs, if you have issues with other environments, the TAs will not be able to support you.

What you will learn

  • String manipulation
    • charAt
    • substring
    • indexOf
  • Reviewing classes
    • getters / setters
    • Simple methods

Setting Up Your IDE - IntelliJ

Applying for a free version of IntelliJ Ultimate with JetBrains

Apply for a free version of IntelliJ Ultimate here. Fill out the application with your university email address. Be sure to check your email and accept the License Agreement. Then log in or create a Jet Brains account to link your free license.

Installing the JetBrains Toolbox App

The JetBrains Toolbox App is a hub for all JetBrains IDEs and will keep your IDE up to date. You can download it from here. Make sure to select the correct version for your operating system. Once the Toolbox is installed, open it and install IntelliJ IDEA Ultimate.

Creating your first Project in IntelliJ

  1. Open IntelliJ and select Do not import settings.

  1. Log in with your JetBrains account. At the top left select File > New > Project… or simply New Project from the start up menu.

  2. In the pop up under Project SDK: select Download JDK… (see picture bellow)

  3. Make sure to select version 15 and Oracle OpenJDK. Leave location as is and click Download. (see picture bellow)

  4. Select Next twice, then you will be asked to input a title for your Project. (see picture bellow)

  5. Select Finish. You may be asked if you want to open the new project in the current window or a new one. Select This Window. Congratulations! You now have your first Java Project. Click Project on the left hand side to expand your project directory.

Download JDK (3)
Select JDK Version (4)
Name your Project (5)

Downloading files from Zybooks

Navigate to Practical 2 through Canvas. To download the files for Practical 2 select the download button to the right of the files in Zybooks.

You will need to navigate to your Downloads folder, or wherever you downloaded the files to, and unzip the folder. Then you want to copy all Java Source Files you just downloaded into the src (source) file in your new project. You may need to select the arrow next to the name of your project in IntelliJ in order to see the src folder.

The easiest way to copy the files is to highlight all files and drag them to the src folder. Your project directory should look as follows.

Running Your Program

There are multiple ways of running a program in IntelliJ. First, select the Main file in your project directory. The symbol should have a tiny green arrow next to it. Then select the green arrow to the left of “public class Main”. Select Run Main.main() and your program should run.

Another way is by selecting the green arrow at the top right of the window.

A console window should pop up if you have run your code successfully. To stop the program simply select the red square in the top right or bottom left.

Files

One thing you will notice about this program is that there are a lot of files. However, this is because the contents of the files are relatively short. This application is also designed in the model-view-controller paradigm.

  • view classes (all view classes are readonly)
    • ContactsView.java
      A view that helps display a contact to the console.
    • English.java
      This is stores all the Strings that the views use to print to the console. This could be swapped with another language to provide localization options.
    • LoginView.java
      Displays the initial login sequence (login/password).
    • MainView.java
      The main menu of the application, asking to look up contact, login, exit, and read/compose messages.
    • MessageView.java
      Displays both the information to compose a message and to read a message.
  • controller classes (all controller classes are readonly)
    • ContactsController.java
      Controls program flow between the contacts model and the view.
    • LoginController.java
      Handles login including password authentication.
    • MainController.java
      Handles main menu actions, and passing information between different controllers.
    • MessageController.java
      Handles composing and displaying a message.
  • model classes
    • Address.java (readonly)
      Stores address information for the contact. Read only as an example for other model classes.
    • Contact.java
      Stores the combined contact information.
    • Email.java
      Stores email information about a contact, including splitting up the email lines based on component.
    • Message.java
      Stores a message in the system, including the encryption type.
    • PhoneNumber.java
      Stores a 10 digit phone number.
  • security classes
    • SecurityHash.java (readonly)
      It is common to hash passwords before storing them in a database (or should be common). This file help secure the client’s password by hashing it.
    • ShiftingCaesarCipher.java
      A modified version of the Caesar Cipher for “encrypting” messages
    • SubstitutionCipher.java
      A class that implements a Substitution Cipher for encrypting messages.
  • other classes
    • ContactFactory.java (readonly)
      Contains information for different contacts.
    • Main.java (readonly)
      Entry point for the program.
    • UnitTest.java
      Tests to help you build the application in steps.

After looking through the files, you should go to canvas and take the code tracing quiz for Practical 2.

Pro Tip
Most of these files would have been separated into packages based on the breakdown above. However, zybooks auto-grader doesn’t current support packages, which is why they are not in packages. To read more about java packages, this is a good resource.

Step 1 - Email: getter and setters

Now you have looked through the code, let’s start with working on the Email data class. We use the term dataclass, as email simply holds the email, and returns information about it. Good design of your data classes makes the rest of the application easier. Most data classes have a number of accessor and mutator (getter/setter) methods that match the private variables.

You should implement the following methods in Email.java

  • setEmail(String email)
  • getEmail()
  • setType(String type)
    You do not need to validate the type. Just set whatever String is in the parameter to this.type.
  • getType()

Testing Email: getters and setters

You should run your program with the debug command line argument now. You will notice both of those methods are tested in UnitTests.testEmail(). It, however, only tests one email address, so you may want to add a second set of tests here.

Step 2 - Email: getEName() and getDomain()

The getEName() and getDomain() methods are return substrings of the email. For a quick review of substring, go here and here.

For getEName(), you want to take the email substring from 0 until the indexOf the “@” sign. To review indexOf, go here.

For example, if I had a string, and I wanted to grab each side of a colon

1
2
String myString = "Star Trek:TNG"
String firstHalf = myString.substring(0, myString.indexOf(":"));

For getDomain(), you want the second half of the String after the “@” sign.

For example given the following email:

splashylemon@cs.colostate.edu

The return values would be

splashylemon  // getEName()
cs.colostate.edu  // getDomain()

Testing Email: getEName() and getDomain()

Once again run in debug mode, the above examples should show up. You will want to add additional emails. We are unconcerned about cases with more than one @ sign as that is invalid email/against email specification.

Step 3 - Email: render()

The render() methods in all the classes with them are about returning formatted Strings. The format for the email is as follows:

Home:   splashylemon@cs.colostate.edu
Office: splashylemon2@cs.colostate.edu

The type is formatted with 7 characters of padding (%7s), and the email is provided as is. You do not have to worry about types over 7 characters.

Hint: use String .format, getType() and getEmail().

Testing Email: render()

Once again, run the code with the debug argument to see the Unit Tests, and you should add your own. This is the last method to complete in Email, so you will really want to add additional emails.

Step 4 - PhoneNumber

You will want to go to PhoneNumber.java and implement the following methods

  • getType
  • setType(String)
    Once again no need to check type, any String is allowed.
  • getNumber()
    returns the raw number
  • setNumber(String number)
    sets the number (10 character string, digits only). You do not need to confirm the string format that is done in another class.
  • getAreaCode()
    Uses substring to get the first 3 digits of the number.
  • getPrefix()
    Gets the next three digits (so 4-6) as a string, uses substring
  • getLine()
    Gets the last four digits. Remember with substring, if you only put in one parameter, it gives you the remainder of the string from that point.

Additional Methods

getPrettyNumber()
Combines String.format with getAreaCode(), getPrefix() and getLine() to return a pretty formatted phone number.
The format would be as follows for 9708675309:

(970) 867-5309

render()
Uses getPrettyNumber() and getType() to build a formatted String. Like Email, the type should have 7 padding. For example:

Home:   (970) 111-5309
Office: (970) 111-1101

Testing PhoneNumber

You should test every method after writing every method (i.e. don’t wait until you write all methods). To run the tests, you will need to uncomment out the call to tests in UnitTest.java as follows:

1
2
3
4
5
6
7
8
9
 public static void runTests() {
   testEmail();
   testPhone();
   //testContact();
   //testCaesarCipher();
   //testSubstitutionCipher();
   //testMessage();
   //...
}

You will also notice, only one number is tested, so you will want to add in additional numbers in the tests.

Step 4 - Contact: cleanNumber(String number)

The goal of the cleanNumber method is to remove everything that isn’t a digit, and keep everything that is a digit. Given a String of any length, remove the characters that are not numbers (0-9) and return the String of numbers that are left.

Example: Given the input “12tes34ting”, the output should be “1234”.

For the cleanNumber method, you will make use of loops, String .charAt(int), StringBuilder and the Character class method isDigit.

The important part about StringBuilder is the append method, as you will be appending to a string as you iterate through each character. For example, if I wanted to remove all whitespace while building a new String, the code would be as follows:

1
2
3
4
5
6
7
8
9
10
11
public String example() {
  String line = "my line with spaces";
  StringBuilder lineNew = new StringBuilder();
  for(int i = 0; i < line.length; i++) {
     char tmp = line.charAt(i);
     if(!Character.isWhitespace(tmp)) {
        lineNew.append(tmp);
     }
  }
  return lineNew.toString();
}

Pro Tip
Why StringBuilder? If you recall, we mentioned Strings are immutable, which means they can’t be changed. Instead, every time you concatenate you create a copy of the String. StringBuilder allows for a mutable string, so you aren’t wasting memory copying the string over and over.

Testing Contact: cleanNumber(String)

You can uncomment the testContact(); in UnitTests, however, looking at that method, you will notice we did not explicitly test cleanNumber. You may want to write your own lines of test to truly test it to make sure it works.

Step 5 - ShiftingCaesarCipher

shift(char x, byte shift)

Now that you are warmed up, we are going to move to the encryption part of the program. The first part of writing a CaesarCipher is writing the shift method. The shift method in this case is a simple shift only (don’t worry about letters only, it can be unusual characters).

Remember divide-conquer-glue. This method is simple as you will use it in the next part. The only thing you have to do is take character x, add byte shift to it, cast it back to a character (char) and return the answer.

A shift in a Caesar Cipher is an amount that each character in a string is shifted by. An easy way to think about this is by assigning numbers to each characters (see ASCII table), and then using those numbers to add a shift value to each one. For example, the character ‘a’ has an ASCII value of 97. Since characters can be treated like integers, we can add to them. If the shift value was 1, 97 + 1 = 98, which is the ASCII value of ‘b’. Using casting, we can now convert the integer value back to a character. This method should only do the shift for a single character, as you will want to call this method in your simpleCeasarEncode method.

simpleCaesarEncode(String str, byte shift)

The purpose of this method is to take a String and return an ‘encoded’ string with every character shifted. You will make use of the shift method, and your experience with StringBuilder and looping through a string using .charAt. Here is a suggestion:

First practice looping through the String pulling the character using .charAt. Second, take that character and call the shift method Third, append the result from shift to the StringBuilder

If you try to do more than that, you are doing too much.

Testing ShiftingCaesarCipher

In the unit tests, uncomment the testCaesarCipher();. Make sure to run a lot while writing these methods.

Step 6 - SubstitutionCipher: encrypt(String str, String mapTo, String mapFrom)

You will want to work on the SubstitutionCipher next. While the code for this is not complex, it takes a moment to wrap your head around the problem. You should draw out what you want to do on paper first before coding. Namely, what is a substitution cipher? If you had two Strings of the same length, what do they share in common (they both have indices from 0..n). If you place the mapFrom on top of the mapTo on your page, and then write the indices between them - you see a pattern. Finding the index of a letter in mapFrom, gives you the character to replace it with in the mapTo.

For example, if your mapTo is di3kj and your mapFrom is abcde, and the word you want to encrypt is abba. I take a, find the index in abcde (0), and then use that index to find the charAt that index in the replacement String (d). we would then append the answer, so builder would eventually have diid. Please note, if the character is not in the mapFrom, that means you don’t do anything, and leave the character exactly without changes.

Useful methoods to complete ‘your quest’ are:

  • indexOf(String)
  • String.valueOf(char) // gives the String rep of a character
  • charAt(int)
  • contains(String) // returns true if parameter is in string

Testing encrypt(String str, String mapTo, String mapFrom)

In the unit tests, uncomment the testSubstitutionCipher();. It may help to work out the answers on a piece of paper, as an OB1 error will be very hard to track down.

Step 7 - Finishing up Message

Message.java has the following mutators and accessors that need to be implemented. The methods that handle the encryption are completed for you, but it still needs the direct getters and setters. All of the getters and setters below are direct without any extra checking or changes (e.g. for setMessage, just set the parameter to this.message).

  • getMessage()
  • setMessage(String message)
  • getEncryptionType()
  • setEncryptionType(String encryptionType)
  • getFrom()
  • setFrom(String from)
  • getTo()
  • setTo(String to)
  • getSubject()
  • setSubject(String subject)

You should read the provided code.

Testing Message

Uncomment testMessage(); in UnitTests.java runTests(). You should also add your own tests.

Step 8 - Run the program, and turn in.

You have now been working through the program, but wouldn’t it be more fun to run the actual program? Go into your Run Configurations and remove the debug String from the program arguments and run the program again. You will be presented with a login screen.

Welcome to Encrypted Message System 101
Please enter your e-name > awonder
Please enter your password > alice

Click down in the run area to enter the eName and password. As a review, you can find all the passwords for the system by looking at ContactFactory.

With that said, here are the pairings

ename password
awonder alice
madhatter hatter
offwiththeirheads red
vanishingcat cheshire
late rabbit
necro queen
hookahblue caterpillar

You can log in as different clients, and leave messages for them. Try leaving different types of messages, and then logging in as that client.

Step 9 - Submitting to Zybooks

By clicking through canvas, click the link to the zybooks lab again. The lab will ask you to submit files. Hint, you can highlight all files in the directory, and it will only take the files allowed for submission. If you have been debugging this entire time, you should have minimal things to fix, however, if you tried writing it all at once, this step becomes the hardest step.

Step 10 - Reflection

Please complete the reflection in canvas now. Something to consider in your reflection, this application is stateless. That means whenever the application closes all information is lost - including the messages. How would you keep state between times when the application runs? If you think about it, a word file is storing the ‘state’ of what you are typing. In practice, email works by storing files on the server for retrieval by the client!

Going Further
If you enjoyed this application, you really will want to look at the Networking and Cyber Security Concentration for computer science (netsec). You can also learn more about the field. Additionally, what happens if you scale the program up to 1,000,000 clients or more? Computing Systems is critical to understanding how we scale applications for large audiences, among other areas.

Computer Science Department

279 Computer Science Building
1100 Centre Avenue
Fort Collins, CO 80523
Phone: (970) 491-5792
Fax: (970) 491-2466

CS 163/4: Java Programming (CS 1)

Computer Programming in Java: Topics include variables, assignment, expressions, operators, booleans, conditionals, characters and strings, control loops, arrays, objects and classes, file input/output, interfaces, recursion, inheritance, and sorting.