Perihelion Science Fiction

Sam Bellotto Jr.
Editor

Eric M. Jones
Associate Editor


Fiction

Go for the Dome
by Sean Monaghan

Quantum Rose
by Jude-Marie Green

Autumn’s Net
by Matt Thompson

Crawley, I Tell You!
by Tim McDaniel

In the Cave of the Silver Pool
by Peter J Larrivee

How Uncle Larry Became a Shape-Shifting Blob
by Marc Rokoff

Urtication
by KJ Hannah Greenberg

Through a Poisoned Stream I Flow
by Brandon Ketchum

Shorter Stories

Robot Story
by Robin Wyatt Dunn

Compatibility
by Jeffrey Abrams

Dumb Luck
by Michael N. Farney

Articles

Xenophobia Destroys Science Fiction
by Carol Kean

Computed Cryptograms
by Sam Bellotto Jr.


Cover

Editorial

Comic Strips

Reviews

Feedback

Submissions

 

Computed Cryptograms

By Sam Bellotto Jr.

WHAT WITH SO MUCH ADO about nothing being made over government emails and insecure servers, I find myself asking “if said emails were so super Top Secret, why weren’t they encrypted?” Technologies exist today that can quickly code and decode text messages. Government servers are notoriously hackable; they are like Swiss cheese. You’d think a person would actually be commended for using another server. But I digress.

You see, I have a bit of experience with encryption schemes. In 2008, I co-authored a book with nationally-syndicated puzzle guru Terry Stickels entitled “Quotable Cryptograms.” It was published by Random House and you can still buy it on Amazon. As you may have guessed, the book included 500 fun cryptograms to crack. A variety of encrypting methods were used: from the simple letter-substitution variety (BE SURE TO DRINK YOUR OVALTINE), to the more advanced Rail Fence, Playfair, and Quagmire cryptograms.

But we didn’t encode all of the puzzles by hand; that would have taken ... well, we’d probably still be working on them! Rather, I wrote a variety of algorithms with which the computer would generate the finished puzzles. After the book was released, I took my code and developed a fun little Windows application called “Quiptics,” with which anybody can create their own cryptograms.

I’ve derived about as much income as I could hope for from both the book and the software. So at this time, I’d like to release some of this code to our readers of whom I am certain many have computers and are capable of writing applications. Whether or not you have any interest in doing this, I cannot say. But you might enjoy looking at some of the code. It is written in Delphi Pascal, a very popular language. Admittedly, the code isn’t commented as heavily as it should be, but it isn’t too difficult to figure out, if you have a solid knowledge of encryption and programming.

Common Cryptograms

The typical and most widely-known kind of cryptogram involves a random substitution of one letter in the plaintext alphabet with another letter of the ciphertext alphabet. No letter stands for itself. For example, all of the Bs may be replaced with Ms, and the Fs with Ys. This is done for every letter in the original text. Letters in kind are always replaced with the same letters in kind. In other words, the phrase “CRYPTOGRAMS ARE FUN PUZZLES TO SOLVE” after encryption becomes “MIZUGARIFXH FID CNQ UNSSBDH GA HABLD.”

The most basic and easiest of cryptograms use alphabet offset encryption. In these puzzles, the natural order of the alphabet is maintained—the positions are just shifted. For example, an alphabet offset cryptogram might have A encrypted to F, in which case B is G, C is H and so on. This cryptogram is known as a Caesar cipher. The method is named after Julius Caesar, who used it to communicate with his generals.

Here is the code for both random letter substitution and alphabet offset cryptogram generation:

procedure MakeRandomCipher(PT: String);
procedure MakeOffsetCipher(PT: String);
procedure Shuffle(Abcs:TStringList);

var
  alpha: TStringList;
  CT: String;
  FromManual: Boolean = False;

implementation

procedure Shuffle(Abcs:TStringList);
var
  randomIndex: integer;
  cnt: integer;
begin
  Randomize;
  for cnt:=0 to-1+Abcs.Count do
  begin
    randomIndex:=Random(-cnt+Abcs.Count);
    Abcs.Exchange(cnt,cnt+randomIndex);
  end;
end;

procedure MakeRandomCipher(PT: String);
var
  abc,xyz: String;
  tmp: Char;
  c,i,key,rg1: Integer;
begin
  rg1:=StrToInt(copy(CipherRads,1,1));
  if FromManual=False then
  begin
    alpha:=TStringList.Create;
    abc:='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    for c:=65 to 90 do alpha.Add(Chr(c));
    Shuffle(alpha);
    xyz:='';
    for i:=0 to 25 do xyz:=xyz+alpha[i];
    alpha.Free
  end else begin
(*Cipher key tool override*)
    xyz:=CipherKey;
    FromManual:=False
  end;
(*Unique cryptogram rules*)
  if rg1=1 then
  begin
    abc:='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    for key:=1 to Length(xyz)-1 do
    begin
      if xyz[key]=abc[key] then
      begin
        tmp:=xyz[key];
        xyz[key]:=xyz[key+1];
        xyz[key+1]:=tmp
      end;
      if xyz[26]='Z' then
      begin
        xyz[26]:=xyz[25];
        xyz[25]:='Z'
      end
    end
  end;
  CipherKey:=xyz;
  CT:=AnsiUpperCase(PT);
(*Encrypt text*)
  for i:=1 to length(CT) do
  begin
    if CT[i] in['A'..'Z'] then
    begin
      key:=Ord(CT[i])-64;
      CT[i]:=xyz[key]
    end
  end
end;

procedure MakeOffsetCipher(PT: String);
var
  abc,xyz: String;
  offset,key,i: Integer;
begin
  abc:='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  xyz:='';
  Randomize;
  offset:=Random(Length(abc))+1;
  xyz:=copy(abc,offset,26)+copy(abc,1,offset-1);
(*Cipher key tool override*)
  if FromManual=True then
  begin
    xyz:=CipherKey;
    FromManual:=False
  end;
  CipherKey:=xyz;
  CT:=AnsiUpperCase(PT);
(*Encrypt text*)
  for i:=1 to length(CT) do
  begin
    if CT[i] in['A'..'Z'] then
    begin
      key:=Ord(CT[i])-64;
      CT[i]:=xyz[key]
    end
  end
end;

Rail Fence Ciphers

The Rail Fence Cipher is a kind of transposition cipher. In other words, all of the letters in the plaintext appear in the encrypted text unchanged but scrambled. In a substitution cipher, like a cryptogram, the message is replaced by different letters in the alphabet. The key to the scrambling is why it is called a Rail Fence Cipher. In this cipher, the message is divided into columns of alternating rows, resembling a rail fence. The Rail Fence Cipher is a very old technique.

Here’s how to make a simple 2-rail cipher of the message QUIPTICS IS THE GREATEST. First count the number of letters in the plaintext. There are 21. For two rails, this must be divisible by 2, so add the needed letters at the end. These are called “nulls” and have little impact on understanding the decoded message. This message needs only one. QUIPTICS IS THE GREATESTX. Next divide the message into sections equalling the number of rails, eliminating spaces, alternating the letters according to the number of rails. Like this:

Q.I.T.C.I.T.E.R.A.E.T.
.U.P.I.S.S.H.G.E.T.S.X

See how it looks like a rail fence? This design is merely to make the process of encryption easier. The rows can be written directly above each other, if you prefer.

Finally combine all the individual groups into a single long string, first rail, second rail, and so on. The encoded message reads QITCITERAETUPISSHGETSX. There is no established format as to how the cipher is presented. In this article, we’ll break the message into chunks of letters equal to the number of rails, which becomes the “key,” as a default. QI TC IT ER AE TU PI SS HG ET SX indicates this is a two-rail cipher. QTIE TUIS BXIC TEVP SHSW indicates a four-rail cipher.

Now for the code:

procedure MakeRailfenceCipher(PT: String);

var
  rg3: Integer;
  CT: String;

implementation

procedure MakeRailfenceCipher(PT: String);
var
  i,n,r: Integer;
  qRail: array[1..4] of String;
begin
  for i:=1 to 4 do qRail[i]:='';
(*Number of rails*)
  r:=rg3+2;
  CT:=AnsiUpperCase(PT);
  for i:=1 to length(CT) do
    if (CT[i] in ['A'..'Z']) then qRail[1]:=qRail[1]+CT[i];
  CT:=qRail[1];
  Randomize;
  if length(CT) mod r<>0 then
  repeat CT:=CT+Chr(Random(25)+65) until length(CT) mod r=0;
(*Encipher*)
  qRail[1]:='';
  i:=0;
  n:=0;
  repeat
    repeat
      inc(n);
      if n<=length(CT) then
      begin
        inc(i);
        qRail[i]:=qRail[i]+CT[n]
      end
    until (i=r) or (n>length(CT));
    repeat
      inc(n);
      if n<=length(CT) then
      begin
        dec(i);
        qRail[i]:=qRail[i]+CT[n]
      end
    until (i=1) or (n>length(CT))
  until n>length(CT);
  CT:='';
  for i:=1 to r do CT:=CT+qRail[i];
  qRail[1]:='';
(*Format output*)
  for i:=1 to length(CT) do
  begin
    qRail[1]:=qRail[1]+CT[i];
    if i mod r=0 then qRail[1]:=qRail[1]+' '
  end;
  CT:=qRail[1]
end;

Playfair Ciphers

Playfair Ciphers are generated from an arbitrary 5×5 matrix using all the letters of the alphabet except the letter Q. This is the standard convention that we have adopted for this article. Any Qs that appear in the plaintext are automatically converted to K. Thus, the word EQUAL will be spelled EKUAL. The word QUALITY will be spelled KUALITY. This should not confuse anybody.

The Key Table is made by filling in the matrix cells, left to right, top to bottom, with all 25 letters of the alphabet (Q is not used). Start with the keyphrase, dropping any duplicate letters. Then add the unused letters of the alphabet, in order. This is the standard Playfair encoding scheme.

Here’s an example Key Table using CONUNDRUM as the keyphrase:

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

To encrypt a message, break the message into groups of 2 letters known as digraphs. If both letters are the same (or only one letter is left), add an “X” after the first letter. Encrypt the new pair and continue. (“CRYPTOGRAM” becomes “CR YP TO GR AM", however “BOTTLE” would be prepped as “BO TX TL EX.") Now encode using the key table and the following rules, in order, for each letter pair.

Basic encrypting is accomplished by replacing each digraph with the letters on the same row respectively but at the other pair of corners of the rectangle defined by the original pair. The order is important. The first encrypted letter of the pair is the one that lies on the same row as the first plaintext letter.

BO is encrypted as MU. RY as BV. AT as EP.

If the letters appear on the same ROW of the table, replace them with the letters to their immediate right, respectively (wrapping around to the left side of the row if a letter in the original pair was on the right side of the row).

CO is encrypted as ON. HI as IJ. BE is ER. ST is TK.

If the letters appear on the same column of the table, replace them with the letters immediately below, respectively (wrapping around to the top side of the column if a letter in the original pair was on the bottom side of the column).

CR is encrypted as RG. HP as PX. SY as YU. LW as WO.

Following these rules, here is how CRYPTOGRAM is encrypted.

CR YP TO GR AM
RG XS LD KG BA

The code is quite a bit more complex, as it involves first generating the key table and then encrypting the message. Here it is:

procedure MakePlayfairCipher(PT: String);
function SwapKeywordRoute(ks: String): String;

var
  CT,keystr: String;

implementation

procedure MakePlayfairCipher(PT: String);
var
  kt: array[1..5,1..5] of char;
  ss: String;
  i,x,y,nA,nB: Integer;
  twin: Boolean;

function TheKeyString(const ed: String): String;
var
  keyS,abc: String;
  n: Integer;
begin
(*Create key table*)
  abc:='ABCDEFGHIJKLMNOPRSTUVWXYZ';
  keyS:=ed+abc;
  Result:='';
(*Drop duplicates*)
  for n:=1 to length(keyS) do
  begin
    if pos(keyS[n],abc)<>0 then
    begin
      Result:=Result+keyS[n];
      Delete(abc,pos(keyS[n],abc),1)
    end
  end
end;

function ArrayX(c: Char): Integer;
var
  xx,yy: Integer;
begin
  Result:=1;
  for yy:=1 to 5 do
  for xx:=1 to 5 do
  if kt[xx,yy]=c then
  Result:=xx
end;

function ArrayY(c: Char): Integer;
var
  xx,yy: Integer;
begin
  Result:=1;
  for yy:=1 to 5 do
  for xx:=1 to 5 do
  if kt[xx,yy]=c then
  Result:=yy
end;

begin
  keystr:=PlayKey;
  ss:=TheKeyString(keystr);
(*Adjust to offset*)
  ss:=AnsiRightStr(ss,StrToInt(PlayOff))
      +AnsiLeftStr(ss,length(ss)-StrToInt(PlayOff));
  if PKvert then ss:=SwapKeywordRoute(ss);
  i:=0;
  for y:=1 to 5 do
    for x:=1 to 5 do
    begin
      inc(i);
      kt[x,y]:=ss[i]
    end;
    CT:='';
    ss:='';
    CT:=AnsiUpperCase(PT);
(*Remove extraneous characters*)
    for i:=1 to length(CT) do
      if (CT[i] in ['A'..'P','R'..'Z']) then ss:=ss+CT[i]
        else if CT[i]='Q' then ss:=ss+'K';
    CT:=ss;
    ss:='';
(*Prep plaintext*)
    repeat
      twin:=false;
      for i:=1 to length(CT)-1 do
        if (Odd(i) and (CT[i]=CT[i+1])) then
        begin
          insert('X',CT,i+1);
          twin:=true;
          Break
        end
      until twin=false;
    ss:=CT;
    if Odd(length(ss)) then
      if ss[length(ss)]='X' then ss:=ss+'J' else ss:=ss+'X';
(*Encode*)
    nA:=1;
    nB:=2;
    CT:='';
    repeat
    if ArrayY(ss[nA])=ArrayY(ss[nB]) then
    begin
      y:=ArrayY(ss[nA]);
      if ArrayX(ss[nA])=5 then CT:=CT+kt[1,y]
        else CT:=CT+kt[ArrayX(ss[nA])+1,y];
      if ArrayX(ss[nB])=5 then CT:=CT+kt[1,y]
        else CT:=CT+kt[ArrayX(ss[nB])+1,y]
    end else begin
      if ArrayX(ss[nA])=ArrayX(ss[nB]) then
      begin
        x:=ArrayX(ss[nA]);
        if ArrayY(ss[nA])=5 then CT:=CT+kt[x,1]
          else CT:=CT+kt[x,ArrayY(ss[nA])+1];
        if ArrayY(ss[nB])=5 then CT:=CT+kt[x,1]
          else CT:=CT+kt[x,ArrayY(ss[nB])+1]
      end else begin
        CT:=CT+kt[ArrayX(ss[nB]),ArrayY(ss[nA])];
        CT:=CT+kt[ArrayX(ss[nA]),ArrayY(ss[nB])];
      end
    end;
    inc(nA,2);
    inc(nB,2)
  until nB=length(ss)+2
end;

function SwapKeywordRoute(ks: String): String;
var
  y,x: Integer;
  k: String;
begin
  k:='';
  for y:=1 to 5 do
  for x:=0 to 4 do
  k:=k+ks[y+x*5];
  Result:=k
end;

Quagmire Ciphers

The Quagmire cipher is devilishly complex, based upon a number of cryptographic elements. It is a type of Vigenère cipher. Basically, a Quagmire cipher is made from a ciphertext table that consists of stacked alphabet rows below a key row:

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

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
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
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
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
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
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

The top row is the plaintext alphabet. Beneath is the ciphertext table. Shown above before applying keywords. Quagmires can have up to three different keywords.

The top plaintext row is formed using a keyword much the same way the Playfair matrix is formed. Begin with the keyphrase, dropping any duplicate letters. Then the unused letters of the alphabet, in order. Using TERRY STICKELS as the keyphrase, the key row comes out:

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

The rows in the ciphertext table are then formed using the same keyphrase as the key row, or another keyphrase altogether.

Let’s use CRYPTOGRAM as the ciphertext table keyphrase. The ciphertext table would look thus:

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

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

However, Quagmires all use an indicator key. The indicator key establishes the “period”—the number of rows in the table—and the letter with which each alphabet row begins. If the indicator key is SAMUEL, it would direct six rows thus:

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

S T U V W X Y Z A B C D E F G H I J K L M N O P Q R
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
M N O P Q R S T U V W X Y Z A B C D E F G H I J K L
U V W X Y Z A B C D E F G H I J K L M N O P Q R S T
E F G H I J K L M N O P Q R S T U V W X Y Z A B C D
L M N O P Q R S T U V W X Y Z A B C D E F G H I J K

Combining the indicator key with the ciphertext table key and we get the actual table to use for encoding the plaintext:

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

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

The indicator key does not always have to appear down the first column. It can be any of the 26 columns, adjusting the alphabet rows accordingly. The same ciphertext table with the indicator key in column 10:

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

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

Encoding is relatively simple. Locate each plaintext letter on the keyed plaintext row (top) and replace it with the corresponding letter of an ciphertext table row, depending upon period order. The first letter of the plaintext is replaced by a letter from the first ciphertext table row, the second letter from the second row, the third letter from the third row, and so on. If the period consists of six rows, after the sixth letter, cycle back to the first row.

So the phrase CRYPTOGRAMS ARE FUN PUZZLES TO SOLVE after encryption becomes LCYOY CXCMY GLHZE AQRGW XSPFE KPTDT F. Quagmires are conventionally broken up into five-character units.

A Quagmire I cipher uses a keyed plaintext row run against a straight cipher table.

A Quagmire II cipher uses an unkeyed plaintext row alphabet run against a keyed cipher table.

A Quagmire III cipher uses both a keyed plaintext row and a keyed cipher table sharing the same keyword.

A Quagmire IV cipher uses a uniquely different key for the plaintext row, the cipher table and the period key.

Following is the code for all types of Quagmire cryptograms:

procedure CreateTheArray;
procedure MakeQuagmireCipher(PT: String);

var
  CT,key,ckey,pkey: String;
  c: Integer;
  QuagArray: Array[0..7] of String;

implementation

function TheKeyString(const ed: String): String;
var
  keyS,abc: String;
  i: Integer;
begin
(*Create keyed alphabet*)
  abc:='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  keyS:=ed+abc;
  Result:='';
(*Drop duplicates*)
  for i:=1 to length(keyS) do
  begin
    if pos(keyS[i],abc)<>0 then
    begin
      Result:=Result+keyS[i];
      Delete(abc,pos(keyS[i],abc),1)
    end
  end
end;

procedure CreateTheArray;
var
  pp: String;
  i,k: Integer;
begin
(*Period key is required*)
  if pkey='' then
    if (ckey<>'') then pkey:=StringOfChar(ckey[1],7) else       pkey:='AAAAAAA';
  for i:=0 to 7 do QuagArray[0]:='';
  if key<>'' then QuagArray[0]:=TheKeyString(key)
    else QuagArray[0]:='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  if (QuagCKey=QuagKey) then pp:=QuagArray[0] else
    if ckey<>'' then pp:=TheKeyString(ckey) else
      pp:='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  k:=0;
  i:=0;
  while i<length(pkey) do
  begin
    inc(k);
    inc(i);
    pp:=copy(pp,pos(pkey[i],pp),80)+copy(pp,1,pos(pkey[i],pp)-1);
(*Indicator key*)
    pp:=RightBStr(pp,c-1)+LeftBStr(pp,26-c+1);
    QuagArray[k]:=pp
  end
end;

procedure MakeQuagmireCipher(PT: String);
var
  i,p,y,x: Integer;
  ss: String;
begin
  key:=QuagKey;
  ckey:=QuagCKey;
  pkey:=copy(QuagIndi,1,pos('@',QuagIndi)-1);
  c:=StrToInt(copy(QuagIndi,pos('@',QuagIndi)+1,3));
  CT:='';
  ss:='';
(*Remove extraneous characters*)
  for i:=1 to length(PT) do
    if (PT[i] in ['A'..'Z','a'..'z']) then ss:=ss+PT[i];
(*Clean plaintext*)
  PT:=UpperCase(ss);
  CreateTheArray;
(*Period*)
  p:=length(pkey);
  y:=p;
(*Make ciphertext*)
  for i:=1 to length(PT) do
  begin
    if y=p then y:=1 else inc(y);
    x:=pos(PT[i],QuagArray[0]);
    CT:=CT+QuagArray[y][x]
  end;
(*Format output*)
  ss:='';
  for i:=1 to length (CT) do
  begin
    ss:=ss+CT[i];
    if i mod 5=0 then ss:=ss+' '
  end;
  CT:=ss
end;

In conclusion, let me add that the primary purpose of this article is to present tested and true code blocks for generating a variety of popular cryptograms. If you are interested in a deeper understanding of the ciphers themselves, the Internet is chock full of information on the subject. the end

Sam Bellotto Jr. is the Editor of “Perihelion Science Fiction.” He also writes stories, having been published in “Bewildering Stories,” “Twisted Tails” anthologies, “Third Flatiron” anthologies, and elsewhere. And he has published lots of puzzles.

 

ad blocker

 

bendayMake a donation to “Perihelion” and get a
FREE copy of “Quiptics”
—the fun Windows software that generates five different kinds of cryptograms!
benday

 

And buy these books by
John McCormick