I am a hobby programmer with a background in biology and have developed an encryption program based on DNA. I tried to make it hard to crack, but it's essentially a substitution cipher and uses the default Java random number generator so my guess it could be cracked relatively easily. But how do I find out how good my encryption is? Can I post an encrypted message here and see if someone can crack it?
Again, I am not a professional cryptographer or programmer, I'm a grad student who does too much outside the lab like attempting to write encryption programs, so if there is already a question about this, I wouldn't know because I don't understand any of the terms I'm seeing in the similar questions.
Here is my code:
import java.util.Random;
import java.util.ArrayList;
import java.util.HashMap;
public class GenenCrypt {
private Random ranGen;
private Random coinFlip;
private String[] bases;
private ArrayList<String> originalCodonList;
private ArrayList<String> shuffledCodonList;
private String[] charList;
private HashMap<String,String[]> codonTable;
private HashMap<String, String> decryptTable;
private String key;
public GenenCrypt(String key){
// define the initial, unshuffled codon list of 4 base codons
originalCodonList = new ArrayList<String>();
bases = new String[]{"A", "T", "G", "C"};
for(int i = 0; i < 4; i++){
for(int j = 0; j < 4; j++){
for(int k = 0; k < 4; k++){
for(int l = 0; l < 4; l++){
originalCodonList.add("" + bases[i] + bases[j] + bases[k] + bases[l]);
}
}
}
}
// make a random number generator with a seed based on the key
this.key = key;
ranGen = new java.util.Random(makeKey(key));
coinFlip = new java.util.Random(makeKey(key));
// use the random number generator and the originalCodonList to make a shuffled list
shuffledCodonList = new ArrayList<String>();
while(originalCodonList.size() > 0){
int index = ranGen.nextInt(originalCodonList.size());
shuffledCodonList.add(originalCodonList.get(index));
originalCodonList.remove(index);
}
// define the characters that can be encoded, 64 in total
// 26 capital letters
// 10 digits
// space, newline, and tab
// the symbols . , ? " ! @ # $ % ^ & * ( ) - + = / _ \ : ; < >
charList = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", " ", "\t", "\n", ".", ",", "?", "\"", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "+", "=", "/", "_", "\\", ":", ";", "<", ">", "|"};
// define the codon table to encode text
codonTable = new HashMap<String, String[]>();
for(int i = 0; i < charList.length; i++){
String[] tempArray = new String[]{shuffledCodonList.get(4 * i), shuffledCodonList.get(4 * i + 1), shuffledCodonList.get(4 * i + 2), shuffledCodonList.get(4 * i + 3)};
//System.out.println(i);
codonTable.put(charList[i], tempArray);
}
// define the decryption table
decryptTable = new HashMap<String, String>();
for(int i = 0; i < codonTable.size(); i++){
String s = charList[i];
String[] sa = codonTable.get(s);
decryptTable.put(sa[0], s);
decryptTable.put(sa[1], s);
decryptTable.put(sa[2], s);
decryptTable.put(sa[3], s);
}
}
public void printShuffledList(){
for(int i = 0; i < shuffledCodonList.size(); i++){
System.out.println(shuffledCodonList.get(i));
}
}
public void printOriginalList(){
for(int i = 0; i < originalCodonList.size(); i++){
System.out.println(originalCodonList.get(i));
}
}
public void printCodonTable(){
// print the codon table
for(int i = 0; i < codonTable.size(); i++){
String s = charList[i];
String[] sa = codonTable.get(s);
if(s == "\t"){
System.out.println(i + "\t" + "\\t" + "\t" + sa[0] +", "+ sa[1] +", "+ sa[2] +", "+ sa[3]);
} else if(s == "\n"){
System.out.println(i + "\t" + "\\n" + "\t" + sa[0] +", "+ sa[1] +", "+ sa[2] +", "+ sa[3]);
} else if(s == " "){
System.out.println(i + "\t" + "\" \"" + "\t" + sa[0] +", "+ sa[1] +", "+ sa[2] +", "+ sa[3]);
} else{
System.out.println(i + "\t" + s + "\t" + sa[0] +", "+ sa[1] +", "+ sa[2] +", "+ sa[3]);
}
}
}
public String encrypt(String input){
String output = "";
for(int i = 0; i < input.length(); i++){
// insert junk bases
int offset = ((int)key.charAt(i % key.length()))%100;
String junk = "";
for(int j = 0; j < offset; j++){
junk += bases[ranGen.nextInt(4)];
}
output += junk;
int comp = coinFlip.nextInt(2);
int choose = ranGen.nextInt(4);
String s = ("" + input.charAt(i)).toUpperCase();
if(codonTable.containsKey(s)){
String[] sa = codonTable.get(s);
if(comp == 0){
output += sa[choose];
}else{
output += complement(sa[choose]);
}
}
}
// add some junk bases to the end of the cipher text
int offset = ((int)key.charAt(input.length() % key.length()))%100;
// add bases to make the total length a mutliple of 4
offset += (output.length() + offset) % 4;
String junk = "";
for(int j = 0; j < offset; j++){
junk += bases[ranGen.nextInt(4)];
}
output += junk;
// reset the random number generators
ranGen.setSeed(makeKey(key));
coinFlip.setSeed(makeKey(key));
return output;
}
public String decrypt(String in){
String input = "" + in;
String output = "";
int keyCount = 0;
int junk = ((int)key.charAt(keyCount % key.length()))%100;
while(input.length() > junk + 4 ){
// cuts out the junk bases
input = input.substring(junk);
// get the codon, decrypt the codon, remove it from the input string
String codon = input.substring(0, 4);
int comp = coinFlip.nextInt(2);
if(comp == 1){
codon = complement(codon);
}
output += decryptTable.get(codon);
input = input.substring(4);
// increment the key counter and update junk
keyCount++;
junk = ((int)key.charAt(keyCount % key.length()))%100;
}
//reset the random number generators
ranGen.setSeed(makeKey(key));
coinFlip.setSeed(makeKey(key));
return output;
}
private String complement(String in){
String out = "";
for(int i = 0; i < in.length(); i++){
switch(in.charAt(i)){
case 'A': out+= 'T';
break;
case 'T': out+= 'A';
break;
case 'G': out+= 'C';
break;
case 'C': out+= 'G';
break;
default: out+= in.charAt(i);
break;
}
}
return out;
}
private long makeKey(String k){
long longKey = 0;
for(int i = 0; i < key.length(); i++){
longKey += (int)key.charAt(i);
}
return longKey;
}
public static void main(String[] args){
String plaintext = "This is the plaintext";
String key = "this is the key";
GenenCrypt gc1 = new GenenCrypt(key);
System.out.println("Encrypting the line \"" + plaintext + "\"");
System.out.println();
String encrypted = gc1.encrypt(plaintext);
System.out.println(encrypted);
System.out.println();
System.out.println("Decrypting the ciphertext");
System.out.println(gc1.decrypt(encrypted));
}
}
The comments probably aren't good enough to understand what I'm doing. First, you should know a little how DNA works. There are 4 bases, A, G, C, and T. DNA codes for proteins, which are made from 20 amino acids. Since $4^1$ = 4, and $4^2$ = 16, we need $4^3$, for 64 possible combinations of 3 bases. This 3 base unit is called a codon. Since 64 is larger than 20, most amino acids are coded for by more than 1 codon, and 3 codons are stop codons, simply marking where the protein ends.
But 20 symbols isn't enough to encrypt a message, I figured 64 symbols would be ok, that gives me all the letters (uppercase only), all the numbers, and most of the punctuation. I also wanted each symbol to be represented by more than 1 codon, so instead of a 3 base codon, I used a 4 base codon, which gives 256 possible combinations. So I assigned each symbol 4 random 4 base codons.
Another concept from DNA is reading frame. A DNA double strand has 6 possible ways to translate protein, 3 forward and 3 reverse, depending on whether you start on the first, second, or third base on either end. To mess up the reading frames in my encrypted messages, I insert a random amount of random bases in between each codon. Also, each codon has a 50% chance to be reversed to it's complement, so A becomes T, G becomes C, and so on.
This means that in order to succesfully decrypt a message, you need to find all 4 codons for each symbol, and sort out the junk, and determine which codons have been reversed. To further complicate things, you could encrypt the ciphertext with a ceasar cipher or other simple encryption to make it look like you have more than 4 characters and disguise the DNA. Or you could go with a hide in plain sight approach and post the message on any number of publicly available DNA databases.