When teaching the various modes of encryption: electronic code book (ECB), cipher block chaining (CBC) and the rest, it’s nice to have a simple cipher for the students to play with. DES is too complicated and fiddly, and Schaefer’s simplified DES, although a great deal easier, is still too fiddly for encryption of multiple blocks, at least by hand.
Probably the simplest “hand” block cipher is the Hill, or matrix cipher, but even that can be time-consuming to compute. Also, its linearity means that many of the standard modes are trivial, and don’t add any further security.
What would be ideal is a simple hand cipher, which uses characters instead of bits – for easier analysis of patterns or lack of them – and is non-linear. Playfair to the rescue! In fact, what I have in mind is a cousin of the Playfair cipher and Delastalle’s trifid cipher.
Here’s how it works. The alphabet consists of 27 characters: all upper case letters and a space (or a full stop if you like); the key is any permutation of these characters. The permutation is then put into a 3x3x3 array, so that each character corresponds to three indices giving its position in the array. This is an example of a fractionating cipher, where each plaintext letter is “subdivided” into several different cipher symbols. Alternatively, and equivalently, the indices could be replaced by the base 3 digits of the character’s position in the permutation.
For example, suppose the permutation was
This could be made into a 3x3x3 array:
and the indices easily read off as row, column, layer (each indexed 0,1 2), so that T for example corresponds to (1,2,1).
Suppose a block consists of three characters, whose indices in the array are
Then encryption simply consists of re-ordering the indices:
For example, suppose the block is the trigram . The indices can be read from the arrays above:
and so the new characters are
producing as the ciphertext block.
This is trivial to implement in Sage:
def pf3(block,key): d0 = ZZ(key.index(block)).digits(3,padto=3) d1 = ZZ(key.index(block)).digits(3,padto=3) d2 = ZZ(key.index(block)).digits(3,padto=3) f0 = [d1,d2,d0] f1 = [d1,d2,d0] f2 = [d1,d2,d0] return key[ZZ(f0,3)]+key[ZZ(f1,3)]+key[ZZ(f2,3)]
Here’s a simple example of ECB mode of a plaintext:
sage: alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ' sage: k = "XJEIOLUBGCDWZA YTFPSKMNQRHV" sage: p = "WITHDRAWONEHUNDREDDOLLARS" sage: p += (3-len(p)%3)*' ' sage: pl = [p[3*i:3*i+3] for i in range(len(p)/3)] sage: ct = [pf3(b,k) for b in pll]; ct ['BZM', 'RHD', 'ZAF', 'DET', 'FWS', 'YHD', 'IOH', 'OCT', 'TBS', 'ONF'] sage: join(ct,'') BZMRHDZAFDETFWSYHDIOHOCTTBSONF
To implement CBC, we need some alternative to exclusive-or. This can be implemented with addition, modulo 27, of characters in our alphabet:
def alph_add(x,y): return alph[(alph.index(x)+alph.index(y))%27]
And now addition of an entire block is very easy:
def block_add(x,y): return join([alph_add(i,j) for i,j in zip(x,y)],'')
And now for CBC, with the equation
where , are plaintext and ciphertext blocks, is encryption, and the addition as defined above.
sage: C=["XXX"] sage: P = [p[3*i:3*i+3] for i in range(len(p)/3)] sage: for i in range(len(p)//3): ....: C += [pf3(block_add(P[i],C[i-1]),k)] ....: sage: C ['XXX', 'XRW', 'OT ', 'BGU', 'KO ', 'AFA', 'LGU', 'OIR', 'WXY', 'TYI', 'CSW']
It is now fun to change one character in the plaintext:
sage: p1 = "WITHDREW ONE HUNDRED DOLLARS"
and see how the different ECB and CBC ciphertexts are affected.
All other modes of encryption can be quickly implemented – by hand if need be.