## An Implementation of Byrnes’ Chaocipher

July 5, 2010 | Cryptography | By: Mark VandeWettering

Okay, insomnia got me, so I went ahead and implemented it in Python. It appears to work reasonably well, at least it successfully deciphers their test message. You can specify the key by specifying the -c and -p options, which are the settings for the cipher and plain wheels. You should pass a permutation of the uppercase letters as arguments to those if you want to use other than the default key, which matches Rubin’s example.

```#!/usr/bin/env python
#
#       _                      _       _
#   ___| |__   __ _  ___   ___(_)_ __ | |__   ___ _ __
#  / __| '_ \ / _` |/ _ \ / __| | '_ \| '_ \ / _ \ '__|
# | (__| | | | (_| | (_) | (__| | |_) | | | |  __/ |
#  \___|_| |_|\__,_|\___/ \___|_| .__/|_| |_|\___|_|
#                               |_|
# An implementation of John Byrnes' Chaocipher as described in papers
# by Moshe Rubin.
#
# Written by Mark VandeWettering <mvandewettering@gmail.com>
# No rights are reserved.  No warranties are implied.
#

import sys
import random
import string
import optparse

p = optparse.OptionParser()
default="PTLNBQDEOYSFAVZKGJRIHWXUMC",
help="plaintext wheel setting")
default="HXUCZVAMDSLKPEFJRIGTWOBNYQ",
help="cipher wheel setting")

opts, args = p.parse_args()

# initialize the code machine...

cnt = 0

def output(c):
global cnt
sys.stdout.write(c)
cnt = cnt + 1
if cnt % 50 == 0:
sys.stdout.write('\n')
cnt = 0
elif cnt % 5 == 0:
sys.stdout.write(' ')

class Machine:
def __init__(self, cw, pw):
self.cw = cw 		# cipher wheel
self.pw = pw 		# plaintext wheel
pass
def twizzle(self, idx):
self.cw = self.cw[idx:] + self.cw[0:idx]
self.cw = list(self.cw[0]) + \
self.cw[2:14] + \
list(self.cw[1]) + \
self.cw[14:]
# and the plaintext wheel
self.pw = self.pw[idx:] + self.pw[0:idx]
self.pw = self.pw[1:] + list(self.pw[0])
self.pw = self.pw[0:2] + \
self.pw[3:14] + \
list(self.pw[2]) + \
self.pw[14:]
def encrypt(self, d):
# find where it is in the plain text wheel...
idx = self.pw.index(d)
r = self.cw[idx]
self.twizzle(idx)
return r
def decrypt(self, d):
idx = self.cw.index(d)
r = self.pw[idx]
self.twizzle(idx)
return r

random.seed(0)
machine = Machine(list(opts.cw), list(opts.pw))

for arg in args:
try:
except IOError, msg:
print >> sys.stderr, "%s: %s" % (arg, msg)
print >> sys.stderr, "continuing..."
data = data.upper()
# filter out all the non alpha characters...
data = filter(lambda x : x in string.uppercase, data)
if opts.decrypt:
for d in data:
output(machine.decrypt(d))
else:
for d in data:
output(machine.encrypt(d))
print
```

Addendum: Here is some cipher text that you can decode with the above program (or your own implementation):

```TLMAG OONSK JBJYB QVGDQ CDUNW NMZPL OYCWP CWKWQ RBOYA DSLQB
KYCDG XJOLO NKTTL RUZZJ QGJBQ NRQHQ RREUI YIDHZ OMVWZ MVYUF
QOGSN NUVYT JGQPS QTBRW FHLTC LVVBP MYYQV
```

Comment from Dave
Time 7/10/2010 at 6:34 am

Hi Mark,

Your cipher text decoded fine with a version I wrote in Scheme as a learning exercise.

Regards

Comment from Mark VandeWettering
Time 7/10/2010 at 8:47 am

Thanks for the confirmation Dave. Glad to see other people are playing with this too. I’m making headway on recovering the exhibit one text, and have some ideas regarding a ciphertext only attack.