CS 4363, Project 1:
Your Own Encryption/Decryption Scheme
Due, 28 February 2003
Project Description:
This project asks you to work on a simple symmetric (conventional)
cryptosystem. I am giving you a skeleton Java program below that
implements the Caesar cipher on each byte, using a rotation from 0 to 255.
- This is to be worked on by teams: from 1 to 3 of you can get
together as a team and work on the project. Later it is permissible
to alter a team (though I'd rather not see this).
- You are to produce a cipher that uses the same short secret key
for encryption and decryption. It would be fairly easy to modify the code
below so that it implements the Beale cipher, but you are not supposed to do
that.
- The idea is to try to implement something that might not be easy to
break. For the strongest possible system, you could
assume that opponents do not know your secret key, but
- have access to your actual Java code, so that they know
exactly what your algorithms are and how they work, and
- have access to a "black" encryption/decryption box (without access
to the secret key), so that they can carry out a known plaintext
attack, that is, can choose arbitrary plaintexts and get the
corresponding ciphertexts.
- The code below is strictly to get students started who might otherwise
not know where to start. You may also code in C++, using a different
skeleton. You are also encouraged to write your own Java skeleton,
perhaps entirely different from the one below. In particular you do
not have to get file names as command line parameters, but you could
even have the file names hard-wired into your code.
- Specifically, the minimum you should do is to modify the
methods encode and decode of the class
Code so that they will reverse one another, and
so they will make a cryptosystem harder to break than the Caesar cipher
(hopefully much harder to break).
- You need to finish this up, so just try some stuff out and get it
in. This is more like a warm-up exercise.
A few hints:
You are welcome to ignore these hints if you want.
- Remember that a system can't possibly be strong unless there
are at least 264 or more keys.
You can use anything you like for the key, but it must not be
arbitrarily long (as it is with the Beale cipher). However,
making the key long is something you can also leave as a feature
you might have included if you had had more time.
- One standard trick is to mess around with the key, and
exclusive-or the result with a plaintext block. Then to reverse
this, mess around with the key the same way and exclusive-or again.
- Block ciphers often use combinations of three basic elements,
repeated in rounds (to decrypt, the rounds are carried
out in the opposite order):
- The trick above: xor with something to encrypt and xor with
the same thing during decryption.
- Using a permutation of elements of the plaintext or
of the key. Here the word permutation means a rearrangement
of elements of the plaintext or of the key. Of course one uses
the reverse of the rearrangement to decrypt.
- Using a substitution of new items for elements of the
plaintext or key. Here something completely different is
inserted in place of each element. This operation also needs
to be reversed for decryption.
- See an appendix at the end of my book for material about
bit operation in Java. In particular, the result b1^b2
(both bytes) in Java is an int with the proper
bits in the 8 least significant bits. You then need to cast to
a byte (using (byte) to get a byte value for
assignment or other uses.
- If your block size in only 8 (as in this case), this is
also a weakness (why?). How might you attack any block cipher
with block size of 8? Obviously you could increase the block size,
but what else might you do to eliminate this weakness?
- You could increase the block size using the skeleton below
by just handling more than one byte at a time, say 4, 8, or 16
bytes at a time. In this case you will want to pad the file
at the end so that its length is a multiple of the block size.
What To Hand In:
The items below must appear in what you hand in, numbered
the same way and not hand-written, except for the annotations
on listings. You should strive for short bulleted items, rather
than long boring paragraphs.
- The names of the team members.
- An overview of the particular encryption scheme used, along
with other distinctive features of your system.
- Overview documentation about your program.
- A clear statement about which parts of the program turned
in are working and which parts are not working.
- A clear statement about any source code you are using that
you did not write yourselves, and any outside help or outside
sources you might have used. (These are permissible, as long
as credit is given.)
- A discussion of additional features you might have inserted
into your program if you had had more time.
- Source listings.
- A listing showing a run, with annotations describing
how the given run shows that your program is working, or the
extent to which it is working.
Java Code for
a Skeleton System:
The first class below (Crypto) just accesses command
line arguments (which say whether to encrypt or decrypt, give the
key, give the name of the input file, and give the name of the output
file), reads the key, opens the files, and creates an instance of
the other class that does the work, and invokes a method in that
class (transform).
// Crypto: simple encode and decode of a file, byte-at-a-time
import java.io.*;
public class Crypto {
static InputStream in; // input file args[2]
static OutputStream out; // output file args[3]
public static void openFiles(String infile, String outfile) {
try {
in = new FileInputStream(infile);
out = new FileOutputStream(outfile);
} catch (IOException e) {
System.err.println("Error opening files");
System.exit(-1);
}
}
public static void main(String[] args) {
boolean encode = true; // encode or decode
int key = 0;
String usage =
"Usage: java Crypto (-encode | -decode) key infile outfile";
if (args.length != 4) {
System.err.println(usage);
System.exit(-1);
}
try {
key = Integer.parseInt(args[1]);
} catch (NumberFormatException e) {
System.err.println("Error converting key \"" +
args[1] + "\" to int");
System.exit(-1);
}
if (args[0].equals("-encode")) encode = true;
else if (args[0].equals("-decode")) encode = false;
else {
System.err.println(usage);
System.exit(-1);
}
openFiles(args[2], args[3]);
Code code = new Code(encode, key, in, out);
code.transform();
}
}
The second class below (Code) actually reads and
writes the files, byte-at-a-time. Between reading and writing
a byte, it either encodes or decodes the byte, depending on the
value of a boolean switch encode. As mentioned
before, your main work (in a simple version of the assignment)
could be to find more complicated functions to use for the methods
encodeByte and decodeByte
(but they must be inverses of one another).
// Code: encode or decode a file
import java.io.*;
public class Code {
int key; // input key
InputStream in; // input file
OutputStream out; // output file
boolean encode = false; // encode or decode
// code: constructor, pass parameters
public Code(boolean mode, int keyP,
InputStream inP, OutputStream outP) {
encode = mode;
key = keyP;
in = inP;
out = outP;
}
// transform: read bytes, encode or decode each byte, write
public void transform() {
try {
int inB; // input byte
int outB; // output byte
// read input file, byte-at-a-time
while ((inB = in.read()) != -1) { // till end-of-file
// make a simple change
if (encode) outB = encodeByte(key, inB);
else outB = decodeByte(key, inB);
writeByte(outB);
} // end of while
} catch (IOException e) {
System.err.println("Error reading input file");
System.exit(-1);
} // end try
}
// encodeByte: encode a byte
private int encodeByte(int key, int inB) {
return (inB + key)%256; // encode
}
// decodeByte: decode a byte
private int decodeByte(int key, int inB) {
return (inB - key)%256; // decode
}
// writeByte: then write byte
private void writeByte(int outB) {
try {
out.write(outB);
} catch (IOException e) {
System.err.print("Error writing file");
System.exit(-1);
}
}
}
Here are the results of a simple run on a Unix box, using the JDK
directly. User input is in boldface. Notice that after
encoding and decoding, the original file is recovered.
% cat mess.text
Now is the time for all good men to come to the aid of their party
% java Crypto -encode 13 mess.text cipher2.text
% java Crypto -decode 13 cipher2.text mess2.text
% vi cipher2.text
[|\x84-v\x80-\x81ur-\x81vzr-s|^?-nyy-t||q-zr{-\x81|-p|zr-\x81|-\x81ur-nvq-|s-\x8
1urv^?-}n^?\x81\x86^W
% cat mess2.text
Now is the time for all good men to come to the aid of their party
Revision date: 2003-02-11.
(Please use ISO
8601, the International Standard.)