This exercise is reserved for pair programming in the live lab sessions.
Please skip it when doing the exercises individually.
In this exercise we will implement the one-time pad. This is a type of encryption which is impossible to crack (if you don’t have the pad)!
To use this encryption method, we take a plaintext string, for example THISISMYSECRETCODE, and encrypt it using a key, for example, SUPERSECRETKEYKEEPMESAFE. For a one-time pad to work, we need the key to be longer than the plaintext.
Note
We will use the convention that key and plaintext should be uppercase, while ciphertexts should be lowercase for testing. The key will not contain spaces, but the plaintext and the ciphertext may.
The code is simple in concept. First, we consider mapping letters to numbers:
Letter | Number | Letter | Number |
---|---|---|---|
A | 0 | P | 15 |
B | 1 | Q | 16 |
C | 2 | R | 17 |
D | 3 | S | 18 |
E | 4 | T | 19 |
F | 5 | U | 20 |
G | 6 | V | 21 |
H | 7 | W | 22 |
I | 8 | X | 23 |
J | 9 | Y | 24 |
K | 10 | Z | 25 |
L | 11 | ||
M | 12 | ||
N | 13 | ||
O | 14 |
This allows us to convert both our key and plaintext into a list of numbers. For example:
\[ \begin{split}key = SUPERSECRETKEYKEEPMESAFE &= \mathtt{18\ 20\ 15\ 4\ 17 \ldots} \\ plaintext = THISISMYSECRETCODE &= \mathtt{19\ 7\ 8\ 18\ 8\ \ldots}\end{split} \]To encipher, using the one-time pad, we add up the numbers:
\[ \mathtt{37\ 27\ 23\ 22\ 25 \ldots } \]Take the modulo of each number around 26:
\[ \mathtt{11\ 1\ 23\ 22\ 25 \ldots } \]and then convert these numbers back to letters:
\[ ciphertext = \mathtt{ l b x w z \ldots} \]In this exercise, we will need to introduce another basic type, char. char represents a single letter, similar to Haskell.
To implement the ciphering and deciphering using the one-time pad, you will create a class OneTimePadEncipher. We have given the skeleton for this class below:
public class OneTimePadEncipher { public static int charToInt(char l) { // ADD CODE HERE // Should convert a character to an integer, for example 'a' -> 0, 'b' -> 1 } public static char intToChar(int i) { // ADD CODE HERE // Should convert an integer to a character, for example 0 -> 'a', b -> '1' // it should always return lower case chae } public static boolean isAlpha(char c) { // You do not need to implement this method, but you may find it useful. } public static String encipher(String original, String onetimepad) { // ADD CODE HERE } public static void main(String[] args) { String ciphertext = encipher("HELLO EVERYBODY", "MYSECRETKETMYSECRETKEY"); System.out.print(ciphertext); } }
Notes:
- You should be careful that your plaintext and your key are both in uppercase. You can use the String method toUpperCase() and toLowerCase() to convert a string to upper or lowercase. Note that this method returns a new string, so it must be assigned. E.g., mystring = mystring.toLowerCase;.
- To extract a char from a String at a certain index, you can use the String.charAt() method on the String object. For example, char c = "hello".charAt(2);, will set c=l .
- It is possible to convert a char into an int using casting. However, note that this will give the ascii value of the letter. For example (int) ('a') -> 97, (int) ('b') -> 98, (int) ('A') -> 65.
- Think about what to do in the case of spaces in the plaintext; they should be spaces in the output (This is not good for making the code secure, but makes human reading easier!). Unit tests will assume that you ignore the values in the one-time pad at the indices of the spaces.
If everything is successful, you should be able to encrypt the following:
Plaintext | Key | Ciphertext |
---|---|---|
HELLO | XMCKL | eqnvz |
SUPERSECRETMESSAGE | MYSUPERDUPERSECRETCKEY | eshygwvfltxdwwurkx |
IS THIS SECURE | KEEPMEVERYVERYSAFE | sw itmn jcxyic |
An automated test has been created for this exercise: OneTimePadEncipherTest.java.
Create a new class OneTimePadDecipher and implement a method to decrypt ciphertext given a key. To decrypt a code, you need to subtract the key from the ciphertext representation, instead of adding it.
As with Question 3, you can call methods already defined in OneTimePadEncipher by using the qualified name (for example OneTimePadEncipher.charToInt(o)).
Note
Be careful with the % operator on negative numbers. -4 % 26 is not 22 as you might expect. To be careful, you can add 26 to possibly negative numbers, before taking the modulo of them, which will ensure they are positive, but not change the result.
The signature of the new method is as follows:
public static String decipher(String encipheredText, String onetimepad)
If everything is sucessful, you should be able to decrypt the following:
Ciphertext | Key |
---|---|
uvufsghktdal | WHATSTHEPASSWORD |
wconlahzgzgleuai | YOULLNEVERREADMYONETIMEPAD |
An automated test has been created for this exercise: OneTimePadDecipherTest.java.