Implemented a command line utility to encrypt and decrypt strings and files with two schemes in September 2017 at Stony Brook University.

Author

All works were solely done by Wonyong Jeong except the base code that is designed under the course CSE320: System Fundamentals II led by Professor Jeniffer Wong-Ma and Professor Eugene Stark.

NOTE: If you are a student in such a class, you should not copy (or copy then modify) this code without permission.

Description

The goal of this project is to implement a command line utility to encrypt and decrypt strings and files with two schemes; The first encryption scheme is a Polybius cipher and the second is a Fractionated Morse cipher.

Usage

usage: ./wyjeong-cipher -h [any other number or type of arguments]
usage: ./wyjeong-cipher [-h] -p|-f -e|-d [-k KEY] [-r ROWS] [-c COLUMNS]
    -h       Display this help menu.
    -p       Polybius Cipher
                 -e (Positional) - Encrypt using the Polybius cipher
                 -d (Positional) - Decrypt using the Polybius cipher
                 -k (Optional) - KEY is the key to be used in the cipher.
                                 It must have no repeated characters and each character in the key must be in `polybius_alphabet` in `const.c`.
                 -r (Optional) - ROWS is the number of rows for the Polybius cipher table.
                                 Must be between 9 and 15, inclusive. Defaults to 10.
                 -c (Optional) - COLUMNS is the number of columns for the Polybius cipher table.
                                 Must be between 9 and 15, inclusive. Defaults to 10.

    -f       Fractionated Morse Cipher
                 -e (Positional) - Encrypt using the Fractionated Morse cipher
                 -d (Positional) - Decrypt using the Fractionated Morse cipher
                 -k (Optional) - KEY is the key to be used in the cipher.
                                 It must have no repeated characters and each character in the key must be in `fm_alphabet` in `const.c`.

Polybius Cipher

Encryption and decryption using a Polybius cipher use an alphabet (i.e. list of characters) to construct a table, polybius_alphabet which has ASCII characters 0x21-0x7e (33-126).

The dimensions of the table are decided by command line arguments -r and -c. If either flag is not given, the corresponding variable defaults to 10. For this cipher to work correctly, the row and column labels need to be single characters, so I used hex digits (0-9 and A-F).

After validargs, it is guaranteed that (rows * cols) >= length of polybius_alphabet. My program fills in the table in row major order (i.e. elements in rows are stored next to each other in memory) with polybius_alphabet and fills the remaining space (if any) with null characters (\0`).

For example, let’s assume the user runs bin/wyjeong-cipher -p -e -r 11 -c 9. The resulting table of 11 rows and 9 columns looks like this:

  0 1 2 3 4 5 6 7 8
0 ! " # $ % & ' ( )
1 * + , - . / 0 1 2
2 3 4 5 6 7 8 9 : ;
3 < = > ? @ A B C D
4 E F G H I J K L M
5 N O P Q R S T U V
6 W X Y Z [ \ ] ^ _
7 \` a b c d e f g h
8 i j k l m n o p q
9 r s t u v w x y z
A { | } ~ \0 \0 \0 \0 \0

In this table, ‘!’ is at index (0, 0) and ‘~’ is at index (A, 3). The last five spaces are null characters (indices (A, 4) - (A,8)).

To encrypt a message, my program takes each character from stdin and write its two- character position in the table to stdout and continues until your program reads EOF (control-d in a UNIX system).

input: CSE320{}

// 'C' is at (3, 7)
// 'S' is at (5, 5)
// 'E' is at (4, 0)
// '3' is at (2, 0)
// '2' is at (1, 8)
// '0' is at (1, 6)
// '{' is at (A, 0)
// '}' is at (A, 2)

output: 375540201816A0A2

This encryption scheme can be improved by adding a key. The key consists of a subset of the characters in the alphabet and cannot have repeated characters. The characters in the key are placed first in the table and the remaining alphabet characters are placed after. For example, if the user runs bin/wyjeong-cipher -p -e -k cse320 to specify a key of cse320 and a table of 10 rows and 10 columns:

  0 1 2 3 4 5 6 7 8 9
0 c s e 3 2 0 ! " # $
1 % & ' ( ) * + , - .
2 / 1 4 5 6 7 8 9 : ;
3 < = > ? @ A B C D E
4 F G H I J K L M N O
5 P Q R S T U V W X Y
6 Z [ \ ] ^ _ \` a b d
7 f g h i j k l m n o
8 p q r t u v w x y z
9 { | } ~ \0 \0 \0 \0 \0 \0
input: CSE320{}
output: 3753390304059092

The characters in cse320 are first and all other characters are after. Using a key doesn’t change the number of characters in the table (only changes the ordering of the alphabet) but it makes the cipher more secure.

input: CSE     320 {}
output: 375339     030405 9092

1. Sample Encryption Execution

NOTE: In the following examples, the program encrypts one line at a time and stops encrypting after it reads ^d (control-d) from stdin. Entering ^d into a terminal in a UNIX system signals an EOF (end of file) to the program.

EOF is not actually a character in a file (i.e. it does not have a mapping in the ASCII table). It is a macro that signals that no more input can be read from a file or stream.

$ bin/wyjeong-cipher -p -e -r 11 -c 9 -k cse320
CSE320 IS MY FAVORITE CLASS!!
415843030405 4758 5265 4438625457476043 41513858580606
#NOT@ALL
0853546037385151
C IS AWESOME!!!
41 4758 38634358545243060606
$ echo $?
0

$? is an environment variable in bash which holds the return code of the previous program run.

$ bin/wyjeong-cipher -p -e -r 15 -c 7
CsE320 Is My FaVoRiTe ClAsS
46B551242321 55B5 62C4 529174B170A27295 46A544B571
$ echo $?
0
$

For decryption, my program reconstructs the same table used for encryption (i.e. the same number of rows and columns and the same key must be used). Then, the first two characters correspond to a row/column pair, which can be used to find the plaintext character in the table. For example:

command: `bin/wyjeong-cipher -p -d -k cse320`
encrypted string: "375339     030405 9092"

// (3, 7) is 'C'
// (5, 3) is 'S'
// ...
// (9, 2) is '}'

plaintext: "CSE     320 {}"

Like encryption, the decryption process preserves whitespace.

2. Sample Decryption Execution

$ bin/wyjeong-cipher -p -d
348236181715 4082 4488 3764537849725168 3475328250
CsE320 Is My FaVoRiTe ClAsS
$ echo $?
0
$

Fractionated Morse Cipher

Morse Code is a standardized method of transmitting text information. The text is translated into various sequences of “dots” . and “dashes” -. Fractionated Morse Cipher takes this translated text and ciphers it using a key back into text that can only be decoded using that same key.

In the ciphering of the intermediate Morse translation, my program will cipher groups of three characters until there are no more groups of three characters left. This means that any leftover characters will be truncated off the end and not ciphered.

For example, I LOVE CS with a detailed explanation of each step will be explained using the key HELP. My prgram first translates the text to Morse Code. **I am using the translation table as defined in the const.c **

I LOVE CS will be translated to ..xx.-..x---x...-x.xx-.-.x...xx

I is mapped to the Morse Code ..(dot dot). My program then puts the word divider xx to indicate that this is the end of the word. Next the program translates LOVE as .-..x---x...-x.xx. As you can see, L translates to .-.. and O translates to ---. In between these characters, we have the letter divider, which is a single x. This routine is done for the rest of the text. To end the entire sequence, we have a terminating word divider.

Next the program will determine the full key using the input value HELP. When we expand the key, it will become: HELPABCDFGIJKMNOQRSTUVWXYZ. This is because the full key is filled out with the rest of the letters of the alphabet that were unused.

Using the key, we will cipher the Morse Code. To do this, we must first associate the letters of the key with the Fractionated Table values. This is done in the following fashion:

H E L P A B C D F G I J K M N O Q R S T U V W X Y Z
. . . . . . . . . - - - - - - - - - x x x x x x x x
. . . - - - x x x . . . - - - x x x . . . - - - x x
. - x . - x . - x . - x . - x . - x . - x . - x . -

The table shows each possible Morse Code triple cipher. ... is ciphered to H, ..- is ciphered to E, ..x is ciphered to L, and so on.

Note that there is no xxx on the table!

We will split the Morse Code into triples, and then cipher the triples:

As a visual aid, the character | will be used to separate the triples in this example.

..x | x.- | ..x| --- | x.. | .-x | .xx | -.- | .xx

will be ciphered to:

L | T | L | M | S | B | F | I | F

or just

LTLMSBFICL

To decrypt our message, my program does the same steps in reverse. First my program must decipher the encrypted message back into Morse Code. For this to properly be done, it must decipher using the same key so that our table is the same as when it encrypted the message. As a reminder, the table will be listed again:

H E L P A B C D F G I J K M N O Q R S T U V W X Y Z
. . . . . . . . . - - - - - - - - - x x x x x x x x
. . . - - - x x x . . . - - - x x x . . . - - - x x
. - x . - x . - x . - x . - x . - x . - x . - x . -

Using the key we will build the original Morse Code translated message from the ciphered text, which is ..xx.-..x---x...-x.xx-.-.x...xx

Next it must translate the Morse Code back into plain text. This step requires translating all of the dot-and-dash combinations to their plain text equivalents, and translating word dividers accordingly.

.. will be translated to I. Since it is followed by a word divider, it will be adding a space after I to get I . Next, it translates .-.. to L. Since it is simply followed by a letter divider we will ignore it and translate the next --- to O. This routine is done for the rest of the phrase, and we are left with our original phrase I LOVE CS.

1. Sample Encryption Execution:

1) Basic Encryption

$ bin/wyjeong-cipher -f -e [-k KEY_STRING]

OR Input File:

$ cat rsrc/message.txt
DEFEND THE EAST
$
$ cat rsrc/message.txt | bin/wyjeong-cipher -f -e -k ROUNDTABLE
ESOAVVLJRSSTRX
$

2) Encryption with Multiple Lines

Input File:

$ cat rsrc/message2.txt
I LOVE C!
I LOVE CSE 320!
$
$ cat rsrc/message2.txt | bin/wyjeong-cipher -f -e -k FIXMYPROG
XQXENPGBOMH
XQXENPGFHIHEHBY
$

3) Encryption with Multiple Spaces between Words

Input File:

$ cat rsrc/message3.txt
I    LOVE     C   !
$
$ cat rsrc/message3.txt | bin/wyjeong-cipher -f -e -k FROPY
OSOJQADGDGY
$

4) Encryption with character with no Morse Translation

Input File:

$ cat rsrc/message4.txt
2^64 IS A LARGE NUMBER
$
$ cat rsrc/message4.txt | bin/wyjeong-cipher -f -e -k DONTWERK
$ echo $?
1
$

2. Sample Decyption Execution:

1) Basic Decryption

$ bin/wyjeong-cipher -f -d [-k KEY_STRING]

OR Input File:

$ cat rsrc/encoded_message.txt
ESOAVVLJRSSTRX
$
$ cat rsrc/encoded_message.txt | bin/wyjeong-cipher -f -d -k ROUNDTABLE
DEFEND THE EAST
$

2) Decryption with Multiple Lines

Input File:

$ cat rsrc/encoded_message2.txt
XQXENPGBOMH
XQXENPGFHIHEHBY
$ cat rsrc/message2.txt | bin/wyjeong-cipher -f -d -k FIXMYPROG
I LOVE C!
I LOVE CSE 320!

3. Sample Execution using shell redirection

$ echo "HELLO, WORLD!" | bin/wyjeong-cipher -f -e -k DEKU | bin/wyjeong-cipher -f -d -k DEKU
HELLO, WORLD!
$ echo -e "HELLO\n\nMULTI\nLINE!" | bin/wyjeong-cipher -f -e -k ALMIGHT | bin/wyjeong-cipher -f -d -k ALMIGHT
HELLO

MULTI
LINE!
$
$ cat rsrc/message5.txt
TPDNOYQFKBJFNNCIYVFEU
$ bin/wyjeong-cipher -f -e -k URAVITY < rsrc/message5.txt | bin/wyjeong-cipher -f -d -k URAVITY
REDIRECTION IS FUN!

Source Code

Source code will be public on my github accout soon.