Implementing the Chaocipher in C#


Introduction

Whilst doing some research on cryptography, I came across the Chaocipher.

This cipher was invented by the late John F. Byrne in 1918 and defied all attempts to break it until details of the algorithm used were disclosed by his family in 2010.

A paper entitled Chaocipher Revealed : The Algorithm was published by Moshe Rubin in July 2010 and forms the basis of this article.

How does the cipher work?

For full details of how the cipher is applied, you should consult Mr Rubin's paper which, by cryptographic standards, is very easy to read and understand.

Briefly, the idea is that you start with two alphabets: a 'left' alphabet (for ciphertext) and a 'right' alphabet (for plaintext).

You then convert each letter in the plaintext to ciphertext by looking up the index of the former in the right alphabet and then using that index of read off the corresponding ciphertext letter from the left alphabet.

However, unlike a normal substitution cipher, you then make some permutations to both the left and right alphabets before encrypting the next letter. Similar operations are carried out after encrypting each letter until the plaintext is exhausted.

Decryption follows a similar pattern except that the permutations used are slightly different from those used in encryption.

This is a clever idea which is known as an 'autokey' cipher in cryptography because the next key is generated from the previous one. Clearly, the permutations used need to be such that they can be easily reversed by the decryption process.

C# Implementation

Although a C# implementation is said to exist, I could not find it on the internet and so have written my own.

The following console application is based on the algorithm described in Mr Rubin's paper and uses the example which he gives so we can check that it is working correctly. The resulting ciphertext is then decrypted back to the plaintext.

No attempt has been made to optimize the code though, for a large piece of plaintext, performance could almost certainly be improved by using unsafe code and pointers to manipulate the character arrays.

The code is also available in the accompanying download:

using System;

static class Chao
{
    private static string lAlphabet = "HXUCZVAMDSLKPEFJRIGTWOBNYQ";
    private static string rAlphabet = "PTLNBQDEOYSFAVZKGJRIHWXUMC";

    public static string Encrypt(string plainText)
    {
       char[] left = lAlphabet.ToCharArray();
       char[] right = rAlphabet.ToCharArray();
       char[] pText = plainText.ToCharArray();
       char[] cText = new char[pText.Length];
       char[] temp = new char[26];
       int index;
       char store;

       for(int i = 0; i < pText.Length; i++)
       {
          Console.WriteLine("{0}  {1}", new string(left), new string(right));

          index = Array.IndexOf(right, pText[i]);
          cText[i] =left[index];
          if (i == pText.Length - 1) break;

          // permute left

          for(int j = index; j < 26; j++) temp[j - index] = left[j];
          for(int j = 0; j < index; j++) temp[26 - index + j] = left[j];
          store = temp[1];             
          for(int j = 2; j < 14; j++) temp[j - 1] = temp[j];
          temp[13] = store;
          temp.CopyTo(left, 0);

          // permute right
 
          for(int j = index; j < 26; j++) temp[j - index] = right[j];
          for(int j = 0; j < index; j++) temp[26 - index + j] = right[j];
          store = temp[0];
          for(int j = 1; j < 26; j++) temp[j - 1] = temp[j];
          temp[25] = store;
          store = temp[2];
          for(int j = 3; j < 14; j++) temp[j - 1] = temp[j];
          temp[13] = store;
          temp.CopyTo(right, 0);         
       }

       return new string(cText);
    }

    public static string Decrypt(string cipherText)
    {
       char[] left = lAlphabet.ToCharArray();
       char[] right = rAlphabet.ToCharArray();
       char[] cText = cipherText.ToCharArray();
       char[] pText = new char[cText.Length];
       char[] temp = new char[26];
       int index;
       char store;

       for(int i = 0; i < cText.Length; i++)
       {
          // Console.WriteLine("{0}  {1}", new string(left), new string(right));

          index = Array.IndexOf(left, cText[i]);
          pText[i] = right[index];
          if (i == cText.Length - 1) break;

          // permute left

          for(int j = index; j < 26; j++) temp[j - index] = left[j];
          for(int j = 0; j < index; j++) temp[26 - index + j] = left[j];
          store = temp[1];             
          for(int j = 2; j < 14; j++) temp[j - 1] = temp[j];
          temp[13] = store;
          temp.CopyTo(left, 0);

          // permute right

          for(int j = index; j < 26; j++) temp[j - index] = right[j];
          for(int j = 0; j < index; j++) temp[26 - index + j] = right[j];
          store = temp[0];
          for(int j = 1; j < 26; j++) temp[j - 1] = temp[j];
          temp[25] = store;
          store = temp[2];
          for(int j = 3; j < 14; j++) temp[j - 1] = temp[j];
          temp[13] = store;
          temp.CopyTo(right, 0);        
       }

       return new string(pText);
   }
}

class Program

    static void Main()
    {      
       string plainText = "WELLDONEISBETTERTHANWELLSAID";
       Console.WriteLine("The original plainText is : {0}", plainText);
       Console.WriteLine("\nThe left and right alphabets after each permutation during encryption are\n"); 
       string cipherText = Chao.Encrypt(plainText);     
       Console.WriteLine("\nThe ciphertext is {0}", cipherText);
       string plainText2 = Chao.Decrypt(cipherText);
       Console.WriteLine("\nThe recovered plaintext is {0}", plainText2);
       Console.ReadKey();
    }   
}


Output

A screen-shot of the output is shown below.

Chaocipher.gif

The print out of the left and right alphabets after each permutation during the decryption process has been suppressed as the output would otherwise have exceeded the length of a maximized console window on my machine:

Conclusion

I am not sure how strong this cipher is by modern cryptographic standards but clearly, relative to the effort needed to implement it, it is very strong indeed!

Although the present implementation only covers upper-case letters, it would be easy to adapt it to deal with larger character sets and, for those interested in developing their own ciphers, it should make an excellent starting point.